Hold the joystick lock while opening the HID device on non-Android platforms On Windows the main thread can be enumerating DirectInput devices while the Windows.Gaming.Input thread is calling back with a new controller available, and in this case HIDAPI_IsDevicePresent() returned false since the controller initialization hadn't completed yet, creating a duplicate controller. Fixes https://github.com/libsdl-org/SDL/issues/7304 (cherry picked from commit ece8a7bb8e2dae9cb53115980cea9ef1213a0160)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
diff --git a/src/joystick/hidapi/SDL_hidapijoystick.c b/src/joystick/hidapi/SDL_hidapijoystick.c
index 47300bc..e7d2b91 100644
--- a/src/joystick/hidapi/SDL_hidapijoystick.c
+++ b/src/joystick/hidapi/SDL_hidapijoystick.c
@@ -380,44 +380,65 @@ static void HIDAPI_SetupDeviceDriver(SDL_HIDAPI_Device *device, SDL_bool *remove
if (HIDAPI_GetDeviceDriver(device)) {
/* We might have a device driver for this device, try opening it and see */
if (device->num_children == 0) {
+ SDL_hid_device *dev;
+
+ /* Wait a little bit for the device to initialize */
+ SDL_Delay(10);
+
+#ifdef __ANDROID__
/* On Android we need to leave joysticks unlocked because it calls
* out to the main thread for permissions and the main thread can
* be in the process of handling controller input.
*
* See https://github.com/libsdl-org/SDL/issues/6347 for details
*/
- int lock_count = 0;
- SDL_HIDAPI_Device *curr;
- SDL_hid_device *dev;
- char *path = SDL_strdup(device->path);
+ {
+ SDL_HIDAPI_Device *curr;
+ int lock_count = 0;
+ char *path = SDL_strdup(device->path);
- /* Wait a little bit for the device to initialize */
- SDL_Delay(10);
+ /* Wait a little bit for the device to initialize */
+ SDL_Delay(10);
- SDL_AssertJoysticksLocked();
- while (SDL_JoysticksLocked()) {
- ++lock_count;
- SDL_UnlockJoysticks();
- }
+ SDL_AssertJoysticksLocked();
+ while (SDL_JoysticksLocked()) {
+ ++lock_count;
+ SDL_UnlockJoysticks();
+ }
- dev = SDL_hid_open_path(path, 0);
+ dev = SDL_hid_open_path(path, 0);
- while (lock_count > 0) {
- --lock_count;
- SDL_LockJoysticks();
- }
- SDL_free(path);
+ while (lock_count > 0) {
+ --lock_count;
+ SDL_LockJoysticks();
+ }
+ SDL_free(path);
- /* Make sure the device didn't get removed while opening the HID path */
- for (curr = SDL_HIDAPI_devices; curr && curr != device; curr = curr->next) {
- }
- if (curr == NULL) {
- *removed = SDL_TRUE;
- if (dev) {
- SDL_hid_close(dev);
+ /* Make sure the device didn't get removed while opening the HID path */
+ for (curr = SDL_HIDAPI_devices; curr && curr != device; curr = curr->next) {
+ continue;
+ }
+ if (curr == NULL) {
+ *removed = SDL_TRUE;
+ if (dev) {
+ SDL_hid_close(dev);
+ }
+ return;
}
- return;
}
+#else
+ /* On other platforms we want to keep the lock so other threads wait for
+ * us to finish opening the controller before checking to see whether the
+ * HIDAPI driver is handling the device.
+ *
+ * On Windows, for example, the main thread can be enumerating DirectInput
+ * devices while the Windows.Gaming.Input thread is calling back with a new
+ * controller available.
+ *
+ * See https://github.com/libsdl-org/SDL/issues/7304 for details.
+ */
+ dev = SDL_hid_open_path(device->path, 0);
+#endif
if (dev == NULL) {
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,