fix/sdl3-gamepad-bugs #19

Merged
LotP merged 2 commits from Schuay/Ryubing:fix/sdl3-gamepad-bugs into master 2026-04-18 13:54:27 +00:00
Contributor

Four SDL3 gamepad fixes, all affecting real users with Switch controllers.

Crash on reconnect / broken motionGetFeaturesFlag() was calling SDL_DestroyProperties() on properties owned by SDL internally, causing a use-after-free. This breaks gyro after the first read and crashes on reconnect. Fix: just don't destroy them.

Thread safety in GetGamepads() — was locking the wrong objects and holding locks across yield boundaries, which is undefined behavior with System.Threading.Lock. Fix: snapshot IDs under _lock, iterate outside it.

Rumble NPE on disconnectUpdateRumble() called _gamepad.Rumble() without a null check; throws if the controller disconnects mid-update. Fix: _gamepad?.Rumble(...).

Linux: HIDAPI conflicts with hid_nintendo — when the hid_nintendo kernel module is loaded, it provides evdev nodes for both the gamepad and IMU that SDL3's evdev backend correctly combines. HIDAPI conflicts with it, breaking gyro and wireless hotplug. Fix: detect /sys/module/hid_nintendo at startup and disable HIDAPI for Switch controllers automatically. Overridable via SDL_JOYSTICK_HIDAPI_SWITCH=1.

Tested with an 8BitDo Ultimate Bluetooth Controller on Linux.

Four SDL3 gamepad fixes, all affecting real users with Switch controllers. **Crash on reconnect / broken motion** — `GetFeaturesFlag()` was calling `SDL_DestroyProperties()` on properties owned by SDL internally, causing a use-after-free. This breaks gyro after the first read and crashes on reconnect. Fix: just don't destroy them. **Thread safety in `GetGamepads()`** — was locking the wrong objects and holding locks across `yield` boundaries, which is undefined behavior with `System.Threading.Lock`. Fix: snapshot IDs under `_lock`, iterate outside it. **Rumble NPE on disconnect** — `UpdateRumble()` called `_gamepad.Rumble()` without a null check; throws if the controller disconnects mid-update. Fix: `_gamepad?.Rumble(...)`. **Linux: HIDAPI conflicts with `hid_nintendo`** — when the `hid_nintendo` kernel module is loaded, it provides evdev nodes for both the gamepad and IMU that SDL3's evdev backend correctly combines. HIDAPI conflicts with it, breaking gyro and wireless hotplug. Fix: detect `/sys/module/hid_nintendo` at startup and disable HIDAPI for Switch controllers automatically. Overridable via `SDL_JOYSTICK_HIDAPI_SWITCH=1`. Tested with an 8BitDo Ultimate Bluetooth Controller on Linux.
- Remove SDL_DestroyProperties call on SDL-owned properties in
  SDL3Gamepad.GetFeaturesFlag(). SDL_GetGamepadProperties returns
  properties owned internally by SDL, freed when SDL_CloseGamepad is
  called. Destroying them causes use-after-free, breaking motion sensor
  data retrieval and crashing on controller reconnect.

- Fix GetGamepads() using wrong lock objects (_gamepadsIds, _joyConsIds,
  _linkedJoyConsIds instead of _lock) and holding locks across yield
  boundaries, which is incompatible with System.Threading.Lock. Snapshot
  IDs under _lock and iterate outside it.

- Add null-conditional to _gamepad.Rumble() in NpadController.UpdateRumble()
  to prevent NullReferenceException if gamepad is disconnected mid-update.
Disable SDL3 HIDAPI Switch driver when hid_nintendo is loaded
All checks were successful
Pull Request Triage / triage (pull_request_target) Successful in 27s
Build PR / linux-arm64 (Release) (pull_request) Successful in 5m22s
Build PR / win-x64 (Release) (pull_request) Successful in 6m21s
Build PR / linux-x64 (Release) (pull_request) Successful in 7m15s
Build PR / macOS Universal (Release) (pull_request) Successful in 12m35s
b7f42de5a6
On Linux, the hid_nintendo kernel module creates separate evdev
devices for gamepad input and IMU (motion sensors), which SDL3's
evdev backend properly combines. When HIDAPI is active instead, it
conflicts with the kernel driver, breaking motion/gyro input and
controller hotplugging (especially via wireless dongles).

Automatically detect hid_nintendo via /sys/module and fall back to
the evdev backend. Can still be overridden with the env var
SDL_JOYSTICK_HIDAPI_SWITCH=1.
Owner

looks good to me, lgtm

looks good to me, lgtm
LotP merged commit 7f0e82fe48 into master 2026-04-18 13:54:27 +00:00
LotP referenced this pull request from a commit 2026-04-18 13:54:28 +00:00
Author
Contributor

@sh0inx wrote in #19 (comment):

@Schuay looks good to me, tho we're gonna wait for an approval from @LotP before merge. Do you want us to ping testers for this? Looks like it might be a good candidate for testing in our Discord server.

Thank you, yes additional testing would be great for other controllers / OS combinations.

@sh0inx wrote in https://git.ryujinx.app/projects/Ryubing/pulls/19#issuecomment-2928: > @Schuay looks good to me, tho we're gonna wait for an approval from @LotP before merge. Do you want us to ping testers for this? Looks like it might be a good candidate for testing in our Discord server. Thank you, yes additional testing would be great for other controllers / OS combinations.
Ghost added this to the 1.4.0 milestone 2026-06-27 15:52:01 +00:00
Ghost removed this from the 1.4.0 milestone 2026-06-27 22:57:22 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Reference
projects/Ryubing!19
No description provided.