From 0f0f1070a060f21be48e2b18033b6c02b13b290a Mon Sep 17 00:00:00 2001 From: Elyas Date: Mon, 6 Jul 2026 00:35:49 +0300 Subject: [PATCH] specify what controller u wanna use, instead of all --- .../SDLControllerManager.java | 33 +++++++++ .../controlify/hid/ControllerSpecify.java | 73 +++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 src/main/java/dev/isxander/controlify/hid/ControllerSpecify.java diff --git a/src/main/java/dev/isxander/controlify/controllermanager/SDLControllerManager.java b/src/main/java/dev/isxander/controlify/controllermanager/SDLControllerManager.java index 2ea2cd310..bd4f49db8 100644 --- a/src/main/java/dev/isxander/controlify/controllermanager/SDLControllerManager.java +++ b/src/main/java/dev/isxander/controlify/controllermanager/SDLControllerManager.java @@ -18,6 +18,7 @@ import dev.isxander.controlify.driver.steamdeck.SteamDeckDriver; import dev.isxander.controlify.driver.steamdeck.SteamDeckUtil; import dev.isxander.controlify.hid.ControllerHIDService; +import dev.isxander.controlify.hid.ControllerSpecify; import dev.isxander.controlify.hid.HIDDevice; import dev.isxander.controlify.hid.HIDID; import dev.isxander.controlify.utils.CUtil; @@ -78,6 +79,11 @@ public void tick(boolean outOfFocus) { SDL_JoystickID jid = event.jdevice.which; logger.validateIsTrue(jid != null, "event.jdevice.which was null during SDL_EVENT_JOYSTICK_ADDED event"); + if (!isAssignedToThisInstance(jid)) { + logger.debugLog("Ignoring hotplugged joystick {} - not assigned to this instance", jid.intValue()); + break; + } + logger.debugLog("SDL event: Joystick added: {}", jid.intValue()); UniqueControllerID ucid = new SDLUniqueControllerID(jid); @@ -111,12 +117,39 @@ public void tick(boolean outOfFocus) { super.tick(outOfFocus); } + private boolean isAssignedToThisInstance(SDL_JoystickID jid) { + ControllerSpecify cfg = ControllerSpecify.get(); + if (!cfg.isFilteringEnabled()) return true; + + SDL_Joystick tempHandle = SDL_OpenJoystick(jid); + if (tempHandle == null) { + logger.warn("Could not open joystick {} to check serial: {}", jid.intValue(), SDL_GetError()); + return false; + } + + try { + String serial = SDL_GetJoystickSerial(tempHandle); + if (serial == null) { + logger.warn("Joystick {} reported no serial number - cannot filter by MAC for this device", jid.intValue()); + return false; + } + return ControllerSpecify.normalizeMac(serial).equals(ControllerSpecify.normalizeMac(cfg.getAssignedControllerMac())); + } finally { + SDL_CloseJoystick(tempHandle); + } + } + @Override public void discoverControllers() { logger.debugLog("Discovering controllers..."); SDL_JoystickID[] joysticks = SDL_GetJoysticks(); for (SDL_JoystickID jid : joysticks) { + if (!isAssignedToThisInstance(jid)) { + logger.debugLog("Skipping joystick {} - not assigned to this instance", jid.intValue()); + continue; + } + Optional controllerOpt = tryCreate( new SDLUniqueControllerID(jid), fetchTypeFromSDL(jid) diff --git a/src/main/java/dev/isxander/controlify/hid/ControllerSpecify.java b/src/main/java/dev/isxander/controlify/hid/ControllerSpecify.java new file mode 100644 index 000000000..e789cf090 --- /dev/null +++ b/src/main/java/dev/isxander/controlify/hid/ControllerSpecify.java @@ -0,0 +1,73 @@ +package dev.isxander.controlify.hid; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import dev.isxander.controlify.platform.main.PlatformMainUtil; +import dev.isxander.controlify.utils.CUtil; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Locale; + +public class ControllerSpecify { + private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); + private static final Path CONFIG_PATH = PlatformMainUtil.getConfigDir().resolve("controlify-controllerspecify.json"); + + private static ControllerSpecify instance; + + private String assignedControllerMac = ""; + + public static ControllerSpecify get() { + if (instance == null) { + instance = load(); + } + return instance; + } + + private static ControllerSpecify load() { + if (Files.exists(CONFIG_PATH)) { + try { + String json = Files.readString(CONFIG_PATH); + ControllerSpecify loaded = GSON.fromJson(json, ControllerSpecify.class); + if (loaded != null) { + CUtil.LOGGER.log("Loaded ControllerSpecify config: assignedControllerMac='{}'", loaded.assignedControllerMac); + return loaded; + } + } catch (IOException e) { + CUtil.LOGGER.error("Failed to read controlify-controllerspecify.json, using default", e); + } + } + + ControllerSpecify fresh = new ControllerSpecify(); + fresh.save(); + CUtil.LOGGER.log("Created default controlify-controllerspecify.json at {} - set assignedControllerMac to restrict this instance to one controller", CONFIG_PATH); + return fresh; + } + + public void save() { + try { + Files.writeString(CONFIG_PATH, GSON.toJson(this)); + } catch (IOException e) { + CUtil.LOGGER.error("Failed to write controlify-controllerspecify.json", e); + } + } + + public boolean isFilteringEnabled() { + return assignedControllerMac != null && !assignedControllerMac.isBlank(); + } + + public String getAssignedControllerMac() { + return assignedControllerMac; + } + + public void setAssignedControllerMac(String mac) { + this.assignedControllerMac = mac; + save(); + } + + public static String normalizeMac(String mac) { + if (mac == null) return ""; + return mac.replace(":", "").replace("-", "").trim().toLowerCase(Locale.ROOT); + } +}