SDL: SDL_DINPUT_JoystickPresent() needs to do the full device enumeration

From 205b951b46b16ce08221c9ed17e7c518d83da4ea Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Fri, 25 Jun 2021 14:20:08 -0700
Subject: [PATCH] SDL_DINPUT_JoystickPresent() needs to do the full device
 enumeration

It is called from WGI before the normal joystick detection has been run, so it needs to actually enumerate currently connected devices.

We can skip the logic checking for other drivers also supporting this device, because that logic is duplicated from the call site.
---
 src/joystick/windows/SDL_dinputjoystick.c | 57 ++++++++++++++++-------
 1 file changed, 41 insertions(+), 16 deletions(-)

diff --git a/src/joystick/windows/SDL_dinputjoystick.c b/src/joystick/windows/SDL_dinputjoystick.c
index 98c6499ed..557cab04a 100644
--- a/src/joystick/windows/SDL_dinputjoystick.c
+++ b/src/joystick/windows/SDL_dinputjoystick.c
@@ -425,7 +425,7 @@ SDL_DINPUT_JoystickInit(void)
 
 /* helper function for direct input, gets called for each connected joystick */
 static BOOL CALLBACK
-EnumJoysticksCallback(LPCDIDEVICEINSTANCE pDeviceInstance, LPVOID pContext)
+EnumJoystickDetectCallback(LPCDIDEVICEINSTANCE pDeviceInstance, LPVOID pContext)
 {
 #define CHECK(exp) { if(!(exp)) goto err; }
     JoyStick_DeviceData *pNewJoystick = NULL;
@@ -534,31 +534,56 @@ EnumJoysticksCallback(LPCDIDEVICEINSTANCE pDeviceInstance, LPVOID pContext)
 void
 SDL_DINPUT_JoystickDetect(JoyStick_DeviceData **pContext)
 {
-    IDirectInput8_EnumDevices(dinput, DI8DEVCLASS_GAMECTRL, EnumJoysticksCallback, pContext, DIEDFL_ATTACHEDONLY);
+    IDirectInput8_EnumDevices(dinput, DI8DEVCLASS_GAMECTRL, EnumJoystickDetectCallback, pContext, DIEDFL_ATTACHEDONLY);
 }
 
-SDL_bool
-SDL_DINPUT_JoystickPresent(Uint16 vendor_id, Uint16 product_id, Uint16 version_number)
+/* helper function for direct input, gets called for each connected joystick */
+typedef struct
 {
-    JoyStick_DeviceData* joystick = SYS_Joystick;
+    Uint16 vendor;
+    Uint16 product;
+    SDL_bool present;
+} Joystick_PresentData;
+
+static BOOL CALLBACK
+EnumJoystickPresentCallback(LPCDIDEVICEINSTANCE pDeviceInstance, LPVOID pContext)
+{
+#define CHECK(exp) { if(!(exp)) goto err; }
+    Joystick_PresentData *pData = (Joystick_PresentData *)pContext;
     Uint16 vendor = 0;
     Uint16 product = 0;
-    Uint16 version = 0;
+    LPDIRECTINPUTDEVICE8 device = NULL;
 
-    while (joystick) {
-        SDL_GetJoystickGUIDInfo(joystick->guid, &vendor, &product, &version);
+    /* We are only supporting HID devices. */
+    CHECK((pDeviceInstance->dwDevType & DIDEVTYPE_HID) != 0);
 
-        if (!joystick->bXInputDevice &&
-            vendor == vendor_id &&
-            product == product_id &&
-            version == version_number) {
-            return SDL_TRUE;
-        }
+    CHECK(SUCCEEDED(IDirectInput8_CreateDevice(dinput, &pDeviceInstance->guidInstance, &device, NULL)));
+    CHECK(QueryDeviceInfo(device, &vendor, &product));
 
-        joystick = joystick->pNext;
+    if (vendor == pData->vendor && product == pData->product) {
+        pData->present = SDL_TRUE;
+        return DIENUM_STOP; /* get next device, please */
     }
 
-    return SDL_FALSE;
+err:
+    if (device) {
+        IDirectInputDevice8_Release(device);
+    }
+
+    return DIENUM_CONTINUE; /* get next device, please */
+#undef CHECK
+}
+
+SDL_bool
+SDL_DINPUT_JoystickPresent(Uint16 vendor_id, Uint16 product_id, Uint16 version_number)
+{
+    Joystick_PresentData data;
+
+    data.vendor = vendor_id;
+    data.product = product_id;
+    data.present = SDL_FALSE;
+    IDirectInput8_EnumDevices(dinput, DI8DEVCLASS_GAMECTRL, EnumJoystickPresentCallback, &data, DIEDFL_ATTACHEDONLY);
+    return data.present;
 }
 
 static BOOL CALLBACK