SDL: joystick: get HID top-level collection preparsed data directly from RawInput API.

From c39df2fb0c0a1bc8e4a75688be46fc1358603136 Mon Sep 17 00:00:00 2001
From: Dimitriy Ryazantcev <[EMAIL REDACTED]>
Date: Wed, 22 Dec 2021 18:27:10 +0200
Subject: [PATCH] joystick: get HID top-level collection preparsed data
 directly from RawInput API.

---
 src/core/windows/SDL_hid.c                  |  8 ++-----
 src/core/windows/SDL_hid.h                  |  4 ----
 src/joystick/windows/SDL_rawinputjoystick.c | 25 ++++++++++++---------
 3 files changed, 16 insertions(+), 21 deletions(-)

diff --git a/src/core/windows/SDL_hid.c b/src/core/windows/SDL_hid.c
index da941359603..d9dd04fbef1 100644
--- a/src/core/windows/SDL_hid.c
+++ b/src/core/windows/SDL_hid.c
@@ -27,8 +27,6 @@
 
 HidD_GetString_t SDL_HidD_GetManufacturerString;
 HidD_GetString_t SDL_HidD_GetProductString;
-HidD_GetPreparsedData_t SDL_HidD_GetPreparsedData;
-HidD_FreePreparsedData_t SDL_HidD_FreePreparsedData;
 HidP_GetCaps_t SDL_HidP_GetCaps;
 HidP_GetButtonCaps_t SDL_HidP_GetButtonCaps;
 HidP_GetValueCaps_t SDL_HidP_GetValueCaps;
@@ -58,15 +56,13 @@ WIN_LoadHIDDLL(void)
 
     SDL_HidD_GetManufacturerString = (HidD_GetString_t)GetProcAddress(s_pHIDDLL, "HidD_GetManufacturerString");
     SDL_HidD_GetProductString = (HidD_GetString_t)GetProcAddress(s_pHIDDLL, "HidD_GetProductString");
-    SDL_HidD_GetPreparsedData = (HidD_GetPreparsedData_t)GetProcAddress(s_pHIDDLL, "HidD_GetPreparsedData");
-    SDL_HidD_FreePreparsedData = (HidD_FreePreparsedData_t)GetProcAddress(s_pHIDDLL, "HidD_FreePreparsedData");
     SDL_HidP_GetCaps = (HidP_GetCaps_t)GetProcAddress(s_pHIDDLL, "HidP_GetCaps");
     SDL_HidP_GetButtonCaps = (HidP_GetButtonCaps_t)GetProcAddress(s_pHIDDLL, "HidP_GetButtonCaps");
     SDL_HidP_GetValueCaps = (HidP_GetValueCaps_t)GetProcAddress(s_pHIDDLL, "HidP_GetValueCaps");
     SDL_HidP_MaxDataListLength = (HidP_MaxDataListLength_t)GetProcAddress(s_pHIDDLL, "HidP_MaxDataListLength");
     SDL_HidP_GetData = (HidP_GetData_t)GetProcAddress(s_pHIDDLL, "HidP_GetData");
-    if (!SDL_HidD_GetManufacturerString || !SDL_HidD_GetProductString || !SDL_HidD_GetPreparsedData ||
-        !SDL_HidD_FreePreparsedData || !SDL_HidP_GetCaps || !SDL_HidP_GetButtonCaps ||
+    if (!SDL_HidD_GetManufacturerString || !SDL_HidD_GetProductString ||
+        !SDL_HidP_GetCaps || !SDL_HidP_GetButtonCaps ||
         !SDL_HidP_GetValueCaps || !SDL_HidP_MaxDataListLength || !SDL_HidP_GetData) {
         WIN_UnloadHIDDLL();
         return -1;
diff --git a/src/core/windows/SDL_hid.h b/src/core/windows/SDL_hid.h
index 54b9feb5267..82a001a2e4b 100644
--- a/src/core/windows/SDL_hid.h
+++ b/src/core/windows/SDL_hid.h
@@ -183,8 +183,6 @@ extern int WIN_LoadHIDDLL(void);
 extern void WIN_UnloadHIDDLL(void);
 
 typedef BOOLEAN (WINAPI *HidD_GetString_t)(HANDLE HidDeviceObject, PVOID Buffer, ULONG BufferLength);
-typedef BOOLEAN (WINAPI *HidD_GetPreparsedData_t)(HANDLE HidDeviceObject, PHIDP_PREPARSED_DATA *PreparsedData);
-typedef BOOLEAN (WINAPI *HidD_FreePreparsedData_t)(PHIDP_PREPARSED_DATA PreparsedData);
 typedef NTSTATUS (WINAPI *HidP_GetCaps_t)(PHIDP_PREPARSED_DATA PreparsedData, PHIDP_CAPS Capabilities);
 typedef NTSTATUS (WINAPI *HidP_GetButtonCaps_t)(HIDP_REPORT_TYPE ReportType, PHIDP_BUTTON_CAPS ButtonCaps, PUSHORT ButtonCapsLength, PHIDP_PREPARSED_DATA PreparsedData);
 typedef NTSTATUS (WINAPI *HidP_GetValueCaps_t)(HIDP_REPORT_TYPE ReportType, PHIDP_VALUE_CAPS ValueCaps, PUSHORT ValueCapsLength, PHIDP_PREPARSED_DATA PreparsedData);
@@ -193,8 +191,6 @@ typedef NTSTATUS (WINAPI *HidP_GetData_t)(HIDP_REPORT_TYPE ReportType, PHIDP_DAT
 
 extern HidD_GetString_t SDL_HidD_GetManufacturerString;
 extern HidD_GetString_t SDL_HidD_GetProductString;
-extern HidD_GetPreparsedData_t SDL_HidD_GetPreparsedData;
-extern HidD_FreePreparsedData_t SDL_HidD_FreePreparsedData;
 extern HidP_GetCaps_t SDL_HidP_GetCaps;
 extern HidP_GetButtonCaps_t SDL_HidP_GetButtonCaps;
 extern HidP_GetValueCaps_t SDL_HidP_GetValueCaps;
diff --git a/src/joystick/windows/SDL_rawinputjoystick.c b/src/joystick/windows/SDL_rawinputjoystick.c
index cb982787965..c9a92bc4b7a 100644
--- a/src/joystick/windows/SDL_rawinputjoystick.c
+++ b/src/joystick/windows/SDL_rawinputjoystick.c
@@ -689,9 +689,7 @@ RAWINPUT_ReleaseDevice(SDL_RAWINPUT_Device *device)
 #endif /* SDL_JOYSTICK_RAWINPUT_XINPUT */
 
     if (SDL_AtomicDecRef(&device->refcount)) {
-        if (device->preparsed_data) {
-            SDL_HidD_FreePreparsedData(device->preparsed_data);
-        }
+        SDL_free(device->preparsed_data);
         SDL_free(device->name);
         SDL_free(device);
     }
@@ -716,9 +714,8 @@ RAWINPUT_AddDevice(HANDLE hDevice)
     SDL_RAWINPUT_Device *device = NULL;
     SDL_RAWINPUT_Device *curr, *last;
     RID_DEVICE_INFO rdi;
-    UINT rdi_size = sizeof(rdi);
+    UINT size;
     char dev_name[MAX_PATH];
-    UINT name_size = SDL_arraysize(dev_name);
     HANDLE hFile = INVALID_HANDLE_VALUE;
 
     /* Make sure we're not trying to add the same device twice */
@@ -727,11 +724,13 @@ RAWINPUT_AddDevice(HANDLE hDevice)
     }
 
     /* Figure out what kind of device it is */
-    CHECK(GetRawInputDeviceInfoA(hDevice, RIDI_DEVICEINFO, &rdi, &rdi_size) != (UINT)-1);
+    size = sizeof(rdi);
+    CHECK(GetRawInputDeviceInfoA(hDevice, RIDI_DEVICEINFO, &rdi, &size) != (UINT)-1);
     CHECK(rdi.dwType == RIM_TYPEHID);
 
     /* Get the device "name" (HID Path) */
-    CHECK(GetRawInputDeviceInfoA(hDevice, RIDI_DEVICENAME, dev_name, &name_size) != (UINT)-1);
+    size = SDL_arraysize(dev_name);
+    CHECK(GetRawInputDeviceInfoA(hDevice, RIDI_DEVICENAME, dev_name, &size) != (UINT)-1);
     /* Only take XInput-capable devices */
     CHECK(SDL_strstr(dev_name, "IG_") != NULL);
 #ifdef SDL_JOYSTICK_HIDAPI
@@ -747,6 +746,12 @@ RAWINPUT_AddDevice(HANDLE hDevice)
     device->is_xinput = SDL_TRUE;
     device->is_xboxone = GuessControllerType(device->vendor_id, device->product_id) == k_eControllerType_XBoxOneController;
 
+    /* Get HID Top-Level Collection Preparsed Data */
+    size = 0;
+    CHECK(GetRawInputDeviceInfoA(hDevice, RIDI_PREPARSEDDATA, NULL, &size) != (UINT)-1);
+    CHECK(device->preparsed_data = (PHIDP_PREPARSED_DATA)SDL_calloc(size, sizeof(BYTE)));
+    CHECK(GetRawInputDeviceInfoA(hDevice, RIDI_PREPARSEDDATA, device->preparsed_data, &size) != (UINT)-1);
+
     {
         const Uint16 vendor = device->vendor_id;
         const Uint16 product = device->product_id;
@@ -792,8 +797,6 @@ RAWINPUT_AddDevice(HANDLE hDevice)
         }
     }
 
-    CHECK(SDL_HidD_GetPreparsedData(hFile, &device->preparsed_data));
-
     CloseHandle(hFile);
     hFile = INVALID_HANDLE_VALUE;
 
@@ -1312,7 +1315,7 @@ RAWINPUT_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint
 {
 #if defined(SDL_JOYSTICK_RAWINPUT_WGI)
     RAWINPUT_DeviceContext *ctx = joystick->hwdata;
-    
+
     if (ctx->wgi_correlated) {
         WindowsGamingInputGamepadState *gamepad_state = ctx->wgi_slot;
         HRESULT hr;
@@ -1911,7 +1914,7 @@ RAWINPUT_UnregisterNotifications()
         return;
     }
 }
-    
+
 LRESULT CALLBACK
 RAWINPUT_WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {