-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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_JoystickDisconnectedto 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_CreateDeviceNotificationto something more unique. - extending
WINDOWS_JoystickInitto (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.