Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 20 additions & 6 deletions src/main/java/dev/isxander/controlify/Controlify.java
Original file line number Diff line number Diff line change
Expand Up @@ -335,12 +335,18 @@ public void discoverControllers() {
CUtil.LOGGER.log("No controllers found.");
}

// if no controller is currently selected, pick the first one
// if no controller is currently selected, try to restore preference or pick the first one
if (this.getCurrentController().isEmpty()) {
Optional<ControllerEntity> firstController = controllerManager.getConnectedControllers()
.stream()
.findAny();
this.setCurrentController(firstController.orElse(null), false);
String preferredUid = config().getSettings().globalSettings().preferredControllerUid;
Optional<ControllerEntity> preferred = Optional.empty();
if (!config().getSettings().globalSettings().autoSwitchControllers && !preferredUid.isEmpty()) {
preferred = controllerManager.getConnectedControllers().stream()
.filter(c -> c.uid().equals(preferredUid))
.findFirst();
}
this.setCurrentController(preferred.orElseGet(() ->
controllerManager.getConnectedControllers().stream().findAny().orElse(null)
), false);
}

config().saveIfDirty();
Expand Down Expand Up @@ -398,6 +404,13 @@ private void onControllerAdded(ControllerEntity controller, boolean hotplugged)
config().saveIfDirty();
}

if (hotplugged && !config().getSettings().globalSettings().autoSwitchControllers) {
String preferredUid = config().getSettings().globalSettings().preferredControllerUid;
if (controller.uid().equals(preferredUid)) {
this.setCurrentController(controller, true);
}
}

setupWizards.add(wizard);
}

Expand Down Expand Up @@ -546,7 +559,8 @@ private void tickInactiveController(ControllerEntity controller) {
boolean thisControllerGivingInput = state.isGivingInput();
boolean activeControllerGivingInput = getCurrentController().map(c -> c.input().orElseThrow().stateNow().isGivingInput()).orElse(false);

if (thisControllerGivingInput && !activeControllerGivingInput) {
if (config().getSettings().globalSettings().autoSwitchControllers
&& thisControllerGivingInput && !activeControllerGivingInput) {
this.setCurrentController(controller, true);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ public record GlobalConfig(
boolean alwaysAllowKeyboardMovement,
List<String> keyboardMovementWhitelist,
List<String> seenServers,
boolean showSplitscreenAd
boolean showSplitscreenAd,
boolean autoSwitchControllers,
String preferredControllerUid
) {
public static final Codec<GlobalConfig> CODEC = RecordCodecBuilder.create(instance -> instance.group(
Codec.list(Codec.STRING).fieldOf("virtual_mouse_screens").forGetter(GlobalConfig::virtualMouseScreens),
Expand All @@ -34,6 +36,8 @@ public record GlobalConfig(
Codec.BOOL.fieldOf("keyboard_movement").forGetter(GlobalConfig::alwaysAllowKeyboardMovement),
Codec.list(Codec.STRING).fieldOf("keyboard_movement_whitelist").forGetter(GlobalConfig::keyboardMovementWhitelist),
Codec.list(Codec.STRING).fieldOf("seen_servers").forGetter(GlobalConfig::seenServers),
Codec.BOOL.fieldOf("show_splitscreen_ad").forGetter(GlobalConfig::showSplitscreenAd)
Codec.BOOL.fieldOf("show_splitscreen_ad").forGetter(GlobalConfig::showSplitscreenAd),
Codec.BOOL.fieldOf("auto_switch_controllers").forGetter(GlobalConfig::autoSwitchControllers),
Codec.STRING.fieldOf("preferred_controller_uid").forGetter(GlobalConfig::preferredControllerUid)
).apply(instance, GlobalConfig::new));
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@

import com.mojang.datafixers.DataFixer;
import com.mojang.datafixers.DataFixerBuilder;
import dev.isxander.controlify.config.dto.dfu.fixes.AddAutoSwitchControllersFix;
import dev.isxander.controlify.config.dto.dfu.fixes.TheHolyMigrationFix;
import dev.isxander.controlify.config.settings.GlobalSettings;
import dev.isxander.controlify.config.settings.profile.ProfileSettings;
import dev.isxander.controlify.utils.CUtil;

public final class ControlifyDataFixer {
public static final int CURRENT_VERSION = 1;
public static final int CURRENT_VERSION = 2;

private static final DataFixer FIXER = createFixer();

Expand All @@ -28,6 +29,9 @@ private static DataFixer createFixer() {
ProfileSettings.createDefault(CUtil.rl("generic"))
));

var v2 = builder.addSchema(2, ControlifySchemas.SchemaV2::new);
builder.addFixer(new AddAutoSwitchControllersFix(v2));

return builder.build().fixer();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,10 @@ public SchemaV1(int versionKey, Schema parent) {
super(versionKey, parent);
}
}

public static class SchemaV2 extends ControlifySchema {
public SchemaV2(int versionKey, Schema parent) {
super(versionKey, parent);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package dev.isxander.controlify.config.dto.dfu.fixes;

import com.mojang.datafixers.DSL;
import com.mojang.datafixers.DataFix;
import com.mojang.datafixers.TypeRewriteRule;
import com.mojang.datafixers.schemas.Schema;
import com.mojang.serialization.Dynamic;
import dev.isxander.controlify.config.dto.dfu.ControlifyTypeReferences;

public final class AddAutoSwitchControllersFix extends DataFix {
public AddAutoSwitchControllersFix(Schema outputSchema) {
super(outputSchema, false);
}

@Override
protected TypeRewriteRule makeRule() {
var type = getInputSchema().getType(ControlifyTypeReferences.USER_STATE);

return fixTypeEverywhereTyped(
"Controlify: add auto_switch_controllers and preferred_controller_uid defaults",
type,
typed -> typed.update(
DSL.remainderFinder(),
this::rewrite
)
);
}

private <T> Dynamic<T> rewrite(Dynamic<T> root) {
Dynamic<T> global = root.get("global").orElseEmptyMap();

if (global.get("auto_switch_controllers").result().isEmpty()) {
global = global.set("auto_switch_controllers", root.createBoolean(true));
}
if (global.get("preferred_controller_uid").result().isEmpty()) {
global = global.set("preferred_controller_uid", root.createString(""));
}
Comment on lines +32 to +37
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Single source of truth.

Allow this fix to take the GlobalSettings in its constructor, and refer to the defaults that way, rather than providing them again here.


return root.set("global", global);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ public class GlobalSettings {
public List<String> keyboardMovementWhitelist;
public final Set<String> seenServers;
public boolean showSplitscreenAd;
public boolean autoSwitchControllers;
public String preferredControllerUid;

private static final GlobalSettings DEFAULT = new GlobalSettings();

Expand All @@ -48,6 +50,8 @@ private GlobalSettings() {
this.keyboardMovementWhitelist = new ArrayList<>();
this.seenServers = new HashSet<>();
this.showSplitscreenAd = true;
this.autoSwitchControllers = true;
this.preferredControllerUid = "";
}

public GlobalSettings(
Expand All @@ -63,7 +67,9 @@ public GlobalSettings(
boolean alwaysKeyboardMovement,
List<String> keyboardMovementWhitelist,
Set<String> seenServers,
boolean showSplitscreenAd
boolean showSplitscreenAd,
boolean autoSwitchControllers,
String preferredControllerUid
) {
this.virtualMouseScreens = new HashSet<>(virtualMouseScreens);
this.mixedInput = mixedInput;
Expand All @@ -78,6 +84,8 @@ public GlobalSettings(
this.keyboardMovementWhitelist = new ArrayList<>(keyboardMovementWhitelist);
this.seenServers = new HashSet<>(seenServers);
this.showSplitscreenAd = showSplitscreenAd;
this.autoSwitchControllers = autoSwitchControllers;
this.preferredControllerUid = preferredControllerUid;
}

public boolean shouldUseKeyboardMovement() {
Expand Down Expand Up @@ -114,7 +122,9 @@ public static GlobalSettings fromDTO(GlobalConfig dto) {
dto.alwaysAllowKeyboardMovement(),
List.copyOf(dto.keyboardMovementWhitelist()),
Set.copyOf(dto.seenServers()),
dto.showSplitscreenAd()
dto.showSplitscreenAd(),
dto.autoSwitchControllers(),
dto.preferredControllerUid()
);
}

Expand All @@ -135,7 +145,9 @@ public GlobalConfig toDTO() {
alwaysKeyboardMovement,
List.copyOf(keyboardMovementWhitelist),
List.copyOf(seenServers),
showSplitscreenAd
showSplitscreenAd,
autoSwitchControllers,
preferredControllerUid
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,23 @@
import net.minecraft.network.chat.Component;
import net.minecraft.resources.Identifier;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

public class GlobalSettingsScreenFactory {
public static Screen createGlobalSettingsScreen(Screen parent) {
var globalSettings = Controlify.instance().config().getSettings().globalSettings();
AtomicReference<ListOption<String>> whitelist = new AtomicReference<>();
AtomicReference<Option<String>> controllerSelector = new AtomicReference<>();

List<String> controllerUids = new ArrayList<>();
controllerUids.add("");
Controlify.instance().getControllerManager().ifPresent(cm -> {
for (ControllerEntity c : cm.getConnectedControllers()) {
controllerUids.add(c.uid());
}
});

boolean is12106OrLater = /*? if >=1.21.6 {*/ true /*?} else {*/ /*false *//*?}*/;;

Expand Down Expand Up @@ -153,6 +164,57 @@ public static Screen createGlobalSettingsScreen(Screen parent) {
.binding(GlobalSettings.defaults().mixedInput, () -> globalSettings.mixedInput, v -> globalSettings.mixedInput = v)
.controller(TickBoxControllerBuilder::create)
.build())
.option(Option.<Boolean>createBuilder()
.name(Component.translatable("controlify.gui.auto_switch_controllers"))
.description(OptionDescription.createBuilder()
.text(Component.translatable("controlify.gui.auto_switch_controllers.tooltip"))
.build())
.binding(GlobalSettings.defaults().autoSwitchControllers, () -> globalSettings.autoSwitchControllers, v -> globalSettings.autoSwitchControllers = v)
.controller(TickBoxControllerBuilder::create)
.addListener((opt, event) -> {
var selector = controllerSelector.get();
if (selector != null) selector.setAvailable(!opt.pendingValue());
})
.build())
.option(Util.make(() -> {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.option has a supplier overload. no need for Util.make here

var opt = Option.<String>createBuilder()
.name(Component.translatable("controlify.gui.current_controller"))
.description(OptionDescription.createBuilder()
.text(Component.translatable("controlify.gui.current_controller.tooltip"))
.build())
.binding(
"",
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a comment or two for future reference explaining what an empty string represents'd be good

() -> Controlify.instance().getCurrentController().map(ControllerEntity::uid).orElse(""),
uid -> {
if (uid.isEmpty()) {
Controlify.instance().setCurrentController(null, true);
} else {
Controlify.instance().getControllerManager().ifPresent(cm ->
cm.getConnectedControllers().stream()
.filter(c -> c.uid().equals(uid))
.findFirst()
.ifPresent(c -> Controlify.instance().setCurrentController(c, true)));
}
globalSettings.preferredControllerUid = uid;
}
)
.controller(o -> CyclingListControllerBuilder.create(o)
.values(controllerUids)
.formatValue(uid -> {
if (uid.isEmpty()) return Component.translatable("controlify.gui.carousel.entry.keyboard_mouse");
return Controlify.instance().getControllerManager()
.map(cm -> cm.getConnectedControllers().stream()
.filter(c -> c.uid().equals(uid))
.findFirst()
.map(c -> (Component) Component.literal(c.name()))
.orElse(Component.literal(uid)))
.orElse(Component.literal(uid));
}))
.available(!globalSettings.autoSwitchControllers)
.build();
controllerSelector.set(opt);
return opt;
}))
.optionIf(SteamDeckUtil.IS_STEAM_DECK, Option.<Boolean>createBuilder()
.name(Component.translatable("controlify.gui.use_enhanced_steam_deck_driver"))
.description(OptionDescription.createBuilder()
Expand Down
4 changes: 4 additions & 0 deletions src/main/resources/assets/controlify/lang/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@
"controlify.gui.open_issue_tracker": "Open Issue Tracker",
"controlify.gui.use_enhanced_steam_deck_driver": "Use Enhanced Steam Deck Driver",
"controlify.gui.use_enhanced_steam_deck_driver.tooltip": "If enabled, Controlify will use an enhanced driver for the Steam Deck to improve compatibility and performance. This is experimental and may have bugs. This driver requires Decky Loader to be installed on your Deck.",
"controlify.gui.auto_switch_controllers": "Auto-Switch Controllers",
"controlify.gui.auto_switch_controllers.tooltip": "Automatically switches the active controller when input is detected from a different controller. Disable this if you are running multiple game instances with different controllers.",
"controlify.gui.current_controller": "Current Controller",
"controlify.gui.current_controller.tooltip": "Select which controller to use. This option is only available when auto-switching is disabled.",
"controlify.gui.copy_debug_dump": "Copy Debug Dump To Clipboard",
"controlify.gui.copy_debug_dump.tooltip": "Copies a Controlify debug dump to your clipboard. You may be asked to use this if you are seeking support.",

Expand Down