Skip to content

Fix action binding device lookup (pause / reset VR binding not working)#160

Merged
gro-ove merged 1 commit into
gro-ove:masterfrom
chrisraff:claude/fix-action-bindings-PqxPJ
Jun 9, 2026
Merged

Fix action binding device lookup (pause / reset VR binding not working)#160
gro-ove merged 1 commit into
gro-ove:masterfrom
chrisraff:claude/fix-action-bindings-PqxPJ

Conversation

@chrisraff

@chrisraff chrisraff commented Apr 21, 2026

Copy link
Copy Markdown

This PR fixes a bug where non-gameplay action bindings (start race, pause, reset VR, menu navigation) would stop working on subsequent launches. In my experience, repeated launches would cause wheel and button box inputs to stop registering for these actions.
I have limited experience with C#, especially for this large of a project, so I used Claude to help author the fix. I've reviewed the changes myself and validated the behavior through about a week of normal gameplay. Happy to dig into this further or work with contributors if any changes are needed.

AI summary of change:

MemoryListener.Start() was looking up joysticks by raw positional index (ElementAtOrDefault(joySlot)) into a fresh DirectInput scan. The JOY slot values in controls.ini are written based on the device enumeration order at save time, but the MemoryListener's scan happens later—after AC has started and potentially after the background DirectInputScanner has refreshed _staticData with a new enumeration order.

AC itself identifies devices by GUID via the [CONTROLLERS] __IGUID entries, so it's immune to enumeration order changes. The MemoryListener was not, causing non-gameplay action bindings (pause, start race, reset VR, etc.) to silently map to the wrong or missing joystick on repeated launches.

Fix: read __IGUID{slot} from controls.ini [CONTROLLERS] in the constructor, then in Start() resolve each JOY slot to a joystick by matching instance GUID rather than by position. Falls back to positional lookup for older configs that lack __IGUID entries.

Also tighten the usedJoysticks filter from x.Joystick != null (always true, since JoystickHolder is always constructed) to x.Joystick.Device != null, so slots that resolve to no device are excluded upfront.

MemoryListener.Start() was looking up joysticks by raw positional index
(ElementAtOrDefault(joySlot)) into a fresh DirectInput scan. The JOY slot
values in controls.ini are written based on the device enumeration order at
save time, but the MemoryListener's scan happens later—after AC has started
and potentially after the background DirectInputScanner has refreshed
_staticData with a new enumeration order.

AC itself identifies devices by GUID via the [CONTROLLERS] __IGUID entries,
so it's immune to enumeration order changes. The MemoryListener was not,
causing non-gameplay action bindings (pause, start race, reset VR, etc.) to
silently map to the wrong or missing joystick on repeated launches.

Fix: read __IGUID{slot} from controls.ini [CONTROLLERS] in the constructor,
then in Start() resolve each JOY slot to a joystick by matching instance GUID
rather than by position. Falls back to positional lookup for older configs
that lack __IGUID entries.

Also tighten the usedJoysticks filter from `x.Joystick != null` (always true,
since JoystickHolder is always constructed) to `x.Joystick.Device != null`,
so slots that resolve to no device are excluded upfront.

https://claude.ai/code/session_01WpWqqEVanpbdUffLwYd3tV
@gro-ove

gro-ove commented Jun 9, 2026

Copy link
Copy Markdown
Owner

Wonderful addition, thank you! I added __IGUID for CSP to be able to remap devices properly, but didn’t update actual CM logic to use it.

@gro-ove gro-ove merged commit 7448ef2 into gro-ove:master Jun 9, 2026
1 check failed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants