Description
I have this observed buggy behavior on SDL 1.0.21 on windows 11:
- connect ps4 controller via usb
- device gets recognized and HIDAPI SDL driver claims it (good!)
- my code calls
SDL_JoystickOpen
,SDL_GameControllerOpen
- disconnect controller from usb
- my code calls
SDL_GameControllerClose
,SDL_JoystickClose
. I can see that SDL frees theSDL_Joystick*
(no more refs) - removal triggers
HIDAPI_JoystickDisconnected
to be called fromHIDAPI_DriverPS4_UpdateDevice
- reconnect usb
- SDL attaches the WINDOWS driver to it instead of HIDAPI (bad!)
This appears be because EnumJoystickDetectCallback
-> HIDAPI_IsDevicePresent
-> HIDAPI_UpdateDeviceList
still sees the old device in the SDL_HIDAPI_devices
list, and therefor skips calling HIDAPI_AddDevice
(instead, it notices the list entry is dangling and removes it). I tested that settings SDL_HIDAPI_devices
to NULL
between steps 6 and 7 makes the code behave as expected (the reconnect attaches HIDAPI driver again).
I'm curious if I'm using the API incorrectly, if this is a real bug, etc. :) If it's a bug, possible fix could just be duplicating the HIDAPI_DelDevice
loop in HIDAPI_UpdateDeviceList
to the first walk of the list, as well?
It looks like HIDAPI_JoystickDetect
is supposed to detect the change in device count and trigger the HIDAPI_UpdateDeviceList
which would get HIDAPI_DelDevice
called, but it doesn't see the device count change (stays at 1).
In HIDAPI_InitializeDiscovery
, RegisterDeviceNotification
does return success, but ControllerWndProc
is never called.
I ripped out the WM_DEVICECHANGE
-related code into a standalone test app, and it seems the issue is that the thread which created the m_hwndMsg
must also be processing window messages. Seems conflicting as the SDL thread of the app falls into a SDL_WaitEvent
loop (why doesn't something within SDL_WaitEvent
handle window messages?)
OK, so I've found similar code in the Joystick code. It has a minor issue - the class name it uses is too generic ("Message") and so RegisterClassEx
fails because something already registered that name. However, the non-threaded method in this file (using cfgmgr32) was already working, it's just that the variable they control (s_bWindowsDeviceChanged
) is not used for the HIDAPI layer.
So...I propose:
- Replacing window-message based notification in SDL_hidapi.c with the cfgmgr32 method.
- changing the wndclass registered by
SDL_CreateDeviceNotification
to something more unique. - extending
WINDOWS_JoystickInit
to (optionally, based on a hint?) disable window message-based detection of device change all together, since this is already accomplished bySDL_CreateDeviceNotificationFunc
.
I've tested, and replacing RegisterDeviceNotification
with CM_Register_Notification
in SDL_hidapi.c is working, with either GUID_DEVINTERFACE_USB_DEVICE
or GUID_DEVINTERFACE_HID
.