fix: let a connected controller keep the first player slot (#1304)

This commit is contained in:
kingokksa authored and GitHub committed 2026-10-22 09:37:01 -04:00
1 parent 4361182b0e
commit eb0eecda7a
2 files changed
+26 -9

No files matched your search

@@ -117,6 +117,16 @@ public final class PadBridge {
if (changed && !on) resetBuiltin();
}
private static volatile int firstSlot;
public static void setFirstSlot(int slot) {
firstSlot = slot;
}
private int firstPlayerSlot() {
return firstSlot;
}
private void resetBuiltin() {
routedTouch.clear();
systemGuidePressed = false;
@@ -252,7 +262,9 @@ public final class PadBridge {
public synchronized void syncConnectedControllers() {
for (int deviceId : InputDevice.getDeviceIds()) {
InputDevice device = InputDevice.getDevice(deviceId);
if (isFromController(device) && !excluded.test(deviceId)) publish(slotFor(device));
if (!isFromController(device) || excluded.test(deviceId)) continue;
int slot = slotFor(device);
if (slot >= 0) publish(slot);
}
}
@@ -272,6 +284,7 @@ public final class PadBridge {
public synchronized boolean onKeyEvent(KeyEvent event) {
if (!isControllerKeyEvent(event) || excluded.test(event.getDeviceId())) return false;
int slot = slotFor(event.getDevice());
if (slot < 0) return false;
int side = JoyCon.side(event.getDevice());
if (side >= 0 && partners[slot] != NO_CONTROLLER && JoyCon.isRail(side, event.getScanCode())) return true;
PadState pad = stateFor(slot);
@@ -320,6 +333,7 @@ public final class PadBridge {
if (!isControllerMotionEvent(event) || excluded.test(event.getDeviceId())) return false;
if (event.getAction() != MotionEvent.ACTION_MOVE) return false;
int slot = slotFor(event.getDevice());
if (slot < 0) return false;
PadState pad = stateFor(slot);
noteDevice(event.getDevice(), slot);
statAxes++;
@@ -534,25 +548,25 @@ public final class PadBridge {
if (owners[slot] != NO_CONTROLLER && InputDevice.getDevice(owners[slot]) == null) leave(slot, owners[slot]);
}
int side = JoyCon.side(device);
for (int slot = 0; side >= 0 && slot < SLOTS; slot++) {
for (int slot = firstPlayerSlot(); side >= 0 && slot < SLOTS; slot++) {
if (owners[slot] == NO_CONTROLLER || partners[slot] != NO_CONTROLLER) continue;
InputDevice owner = InputDevice.getDevice(owners[slot]);
if (JoyCon.side(owner) != 1 - side) continue;
partners[slot] = id;
slotJoyCons.set(slot * 2 + side, id);
slotJoyCons.set(slot * 2 + 1 - side, owner.getId());
if (slot == 0) releaseBackPaddles();
if (slot == firstPlayerSlot()) releaseBackPaddles();
stateFor(slot).clear();
Log.i(TAG, "\"" + device.getName() + "\" (id " + id + ") joins \"" + owner.getName() + "\" as player " + (slot + 1));
return slot;
}
for (int slot = 0; slot < SLOTS; slot++) {
for (int slot = firstPlayerSlot(); slot < SLOTS; slot++) {
if (owners[slot] != NO_CONTROLLER) continue;
owners[slot] = id;
Log.i(TAG, "\"" + device.getName() + "\" (id " + id + ") is player " + (slot + 1));
return slot;
}
return 0;
return -1;
}
private PadState stateFor(int slot) {
@@ -561,7 +575,8 @@ public final class PadBridge {
private boolean isPrimary(KeyEvent event) {
int id = event.getDevice().getId();
return owners[0] == id || partners[0] == id;
int first = firstPlayerSlot();
return owners[first] == id || partners[first] == id;
}
private void releaseBackPaddles() {
@@ -580,7 +595,7 @@ public final class PadBridge {
clearJoyCons(slot);
if (slotControllers.get(slot) == id) slotControllers.set(slot, owners[slot]);
if (activeControllerId == id) activeControllerId = owners[slot];
if (slot == 0) releaseBackPaddles();
if (slot == firstPlayerSlot()) releaseBackPaddles();
stateFor(slot).clear();
publish(slot);
}
@@ -596,8 +611,8 @@ public final class PadBridge {
partners[slot] = NO_CONTROLLER;
clearJoyCons(slot);
slotControllers.set(slot, NO_CONTROLLER);
if (slot == firstPlayerSlot()) releaseBackPaddles();
if (slot == 0) {
releaseBackPaddles();
state.clear();
publish();
return;
@@ -714,7 +714,9 @@ class SessionService : Service() {
private fun addControllerEnvironment(guest: MutableList<String>, fakeInputDir: File, sessionDir: File) {
FakeInputWriter.prepareRingSlots(fakeInputDir, 4)
val builtinPad = SessionPrefs.builtinPad(this)
val hiddenPad = SessionState.mode == MODE_STEAM && !builtinPad
val hiddenPad = SessionState.mode == MODE_STEAM && !builtinPad &&
!com.droiddeck.launcher.input.PadBridge.anyControllerConnected()
com.droiddeck.launcher.input.PadBridge.setFirstSlot(if (hiddenPad) 1 else 0)
fakeInputDir.listFiles()?.forEach { file ->
val node = Regex("event(\\d+)").matchEntire(file.name)?.groupValues?.get(1)?.toIntOrNull()
if (file.name.startsWith(".uinput-") || (node != null && node >= FIRST_VIRTUAL_PAD) ||