[PATCH 2/3] xinput1_3: Update the controller list in the update thread.

Rémi Bernon rbernon at codeweavers.com
Fri Aug 6 04:05:57 CDT 2021


Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 dlls/xinput1_3/hid.c            | 144 +++++++++++++++-----------------
 dlls/xinput1_3/xinput_main.c    |   8 +-
 dlls/xinput1_3/xinput_private.h |   2 +-
 3 files changed, 73 insertions(+), 81 deletions(-)

diff --git a/dlls/xinput1_3/hid.c b/dlls/xinput1_3/hid.c
index 176e18fd95c..6aacf0ac9cd 100644
--- a/dlls/xinput1_3/hid.c
+++ b/dlls/xinput1_3/hid.c
@@ -69,7 +69,6 @@ struct hid_platform_private {
     struct axis_info lx, ly, ltrigger, rx, ry, rtrigger;
 };
 
-static DWORD last_check = 0;
 static HANDLE stop_event;
 static HANDLE done_event;
 
@@ -87,17 +86,80 @@ static BOOL find_opened_device(SP_DEVICE_INTERFACE_DETAIL_DATA_W *detail, int *f
     return FALSE;
 }
 
+static BOOL init_controller(xinput_controller *controller, PHIDP_PREPARSED_DATA ppd,
+                            HIDP_CAPS *caps, HANDLE device, WCHAR *device_path);
+
+static void update_controller_list(void)
+{
+    char buffer[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + MAX_PATH * sizeof(WCHAR)];
+    SP_DEVICE_INTERFACE_DETAIL_DATA_W *detail = (SP_DEVICE_INTERFACE_DETAIL_DATA_W *)buffer;
+    SP_DEVICE_INTERFACE_DATA iface = {sizeof(iface)};
+    PHIDP_PREPARSED_DATA preparsed;
+    NTSTATUS status;
+    HIDP_CAPS caps;
+    HANDLE device;
+    HDEVINFO set;
+    DWORD idx;
+    GUID guid;
+    int i;
+
+    HidD_GetHidGuid(&guid);
+
+    set = SetupDiGetClassDevsW(&guid, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
+    detail->cbSize = sizeof(*detail);
+
+    idx = 0;
+    while (SetupDiEnumDeviceInterfaces(set, NULL, &guid, idx++, &iface))
+    {
+        if (!SetupDiGetDeviceInterfaceDetailW(set, &iface, detail, sizeof(buffer), NULL, NULL))
+            continue;
+
+        if (!wcsstr(detail->DevicePath, L"IG_")) continue;
+
+        if (find_opened_device(detail, &i)) continue; /* already opened */
+        if (i == XUSER_MAX_COUNT) break; /* no more slots */
+
+        device = CreateFileW(detail->DevicePath, GENERIC_READ | GENERIC_WRITE,
+                             FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
+        if (device == INVALID_HANDLE_VALUE) continue;
+
+        preparsed = NULL;
+        if (!HidD_GetPreparsedData(device, &preparsed))
+            WARN("ignoring HID device, HidD_GetPreparsedData failed with error %u\n", GetLastError());
+        else if ((status = HidP_GetCaps(preparsed, &caps)) != HIDP_STATUS_SUCCESS)
+            WARN("ignoring HID device, HidP_GetCaps returned %#x\n", status);
+        else if (caps.UsagePage != HID_USAGE_PAGE_GENERIC)
+            WARN("ignoring HID device, unsupported usage page %04x\n", caps.UsagePage);
+        else if (caps.Usage != HID_USAGE_GENERIC_GAMEPAD && caps.Usage != HID_USAGE_GENERIC_JOYSTICK &&
+                 caps.Usage != HID_USAGE_GENERIC_MULTI_AXIS_CONTROLLER)
+            WARN("ignoring HID device, unsupported usage %04x:%04x\n", caps.UsagePage, caps.Usage);
+        else if (!init_controller(&controllers[i], preparsed, &caps, device, detail->DevicePath))
+            WARN("ignoring HID device, failed to initialize\n");
+        else
+            continue;
+
+        CloseHandle(device);
+        HidD_FreePreparsedData(preparsed);
+    }
+
+    SetupDiDestroyDeviceInfoList(set);
+}
+
 static DWORD WINAPI hid_update_thread_proc(void *param)
 {
     HANDLE events[1];
-    DWORD count, ret;
+    DWORD count, ret = WAIT_TIMEOUT;
 
     do
     {
+        EnterCriticalSection(&xinput_crit);
+        if (ret == WAIT_TIMEOUT) update_controller_list();
+
         count = 0;
         events[count++] = stop_event;
+        LeaveCriticalSection(&xinput_crit);
     }
-    while ((ret = WaitForMultipleObjectsEx( count, events, FALSE, INFINITE, TRUE )) < count - 1);
+    while ((ret = WaitForMultipleObjectsEx( count, events, FALSE, 2000, TRUE )) < count - 1 || ret == WAIT_TIMEOUT);
 
     if (ret != count - 1) ERR("update thread exited unexpectedly, ret %u\n", ret);
     SetEvent(done_event);
@@ -245,7 +307,9 @@ static BOOL init_controller(xinput_controller *controller, PHIDP_PREPARSED_DATA
     memset(&controller->state, 0, sizeof(controller->state));
     memset(&controller->vibration, 0, sizeof(controller->vibration));
 
+    EnterCriticalSection(&controller->crit);
     controller->platform_private = private;
+    LeaveCriticalSection(&controller->crit);
     return TRUE;
 
 failed:
@@ -257,82 +321,10 @@ failed:
     return FALSE;
 }
 
-void HID_find_gamepads(void)
+void HID_start_update_thread(void)
 {
     static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
-
-    char buffer[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + MAX_PATH * sizeof(WCHAR)];
-    SP_DEVICE_INTERFACE_DETAIL_DATA_W *detail = (SP_DEVICE_INTERFACE_DETAIL_DATA_W *)buffer;
-    HDEVINFO device_info_set;
-    GUID hid_guid;
-    SP_DEVICE_INTERFACE_DATA interface_data;
-    PHIDP_PREPARSED_DATA ppd;
-    HANDLE device;
-    HIDP_CAPS caps;
-    NTSTATUS status;
-    DWORD idx;
-    int i;
-
     InitOnceExecuteOnce(&init_once, start_update_thread, NULL, NULL);
-
-    idx = GetTickCount();
-    if ((idx - last_check) < 2000)
-        return;
-
-    EnterCriticalSection(&xinput_crit);
-
-    if ((idx - last_check) < 2000)
-    {
-        LeaveCriticalSection(&xinput_crit);
-        return;
-    }
-    last_check = idx;
-
-    HidD_GetHidGuid(&hid_guid);
-
-    device_info_set = SetupDiGetClassDevsW(&hid_guid, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
-    detail->cbSize = sizeof(*detail);
-
-    ZeroMemory(&interface_data, sizeof(interface_data));
-    interface_data.cbSize = sizeof(interface_data);
-
-    idx = 0;
-    while (SetupDiEnumDeviceInterfaces(device_info_set, NULL, &hid_guid, idx++,
-           &interface_data))
-    {
-        if (!SetupDiGetDeviceInterfaceDetailW(device_info_set, &interface_data, detail, sizeof(buffer), NULL, NULL))
-            continue;
-
-        if (!wcsstr(detail->DevicePath, L"IG_"))
-            continue;
-
-        if (find_opened_device(detail, &i)) continue; /* already opened */
-        if (i == XUSER_MAX_COUNT) break; /* no more slots */
-
-        device = CreateFileW(detail->DevicePath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 );
-        if (device == INVALID_HANDLE_VALUE)
-            continue;
-
-        ppd = NULL;
-        if (!HidD_GetPreparsedData(device, &ppd))
-            WARN("ignoring HID device, HidD_GetPreparsedData failed with error %u\n", GetLastError());
-        else if ((status = HidP_GetCaps(ppd, &caps)) != HIDP_STATUS_SUCCESS)
-            WARN("ignoring HID device, HidP_GetCaps returned %#x\n", status);
-        else if (caps.UsagePage != HID_USAGE_PAGE_GENERIC)
-            WARN("ignoring HID device, unsupported usage page %04x\n", caps.UsagePage);
-        else if (caps.Usage != HID_USAGE_GENERIC_GAMEPAD && caps.Usage != HID_USAGE_GENERIC_JOYSTICK && caps.Usage != HID_USAGE_GENERIC_MULTI_AXIS_CONTROLLER)
-            WARN("ignoring HID device, unsupported usage %04x:%04x\n", caps.UsagePage, caps.Usage);
-        else if (!init_controller(&controllers[i], ppd, &caps, device, detail->DevicePath))
-            WARN("ignoring HID device, failed to initialize\n");
-        else
-            continue;
-
-        CloseHandle(device);
-        HidD_FreePreparsedData(ppd);
-    }
-
-    SetupDiDestroyDeviceInfoList(device_info_set);
-    LeaveCriticalSection(&xinput_crit);
 }
 
 static void remove_gamepad(xinput_controller *device)
diff --git a/dlls/xinput1_3/xinput_main.c b/dlls/xinput1_3/xinput_main.c
index 547247dc76e..56a5802fc6a 100644
--- a/dlls/xinput1_3/xinput_main.c
+++ b/dlls/xinput1_3/xinput_main.c
@@ -120,7 +120,7 @@ void WINAPI DECLSPEC_HOTPATCH XInputEnable(BOOL enable)
     to the controllers. Setting to true will send the last vibration
     value (sent to XInputSetState) to the controller and allow messages to
     be sent */
-    HID_find_gamepads();
+    HID_start_update_thread();
 
     for (index = 0; index < XUSER_MAX_COUNT; index ++)
     {
@@ -136,7 +136,7 @@ DWORD WINAPI DECLSPEC_HOTPATCH XInputSetState(DWORD index, XINPUT_VIBRATION* vib
 
     TRACE("(index %u, vibration %p)\n", index, vibration);
 
-    HID_find_gamepads();
+    HID_start_update_thread();
 
     if (index >= XUSER_MAX_COUNT)
         return ERROR_BAD_ARGUMENTS;
@@ -157,7 +157,7 @@ static DWORD xinput_get_state(DWORD index, XINPUT_STATE *state)
     if (!state)
         return ERROR_BAD_ARGUMENTS;
 
-    HID_find_gamepads();
+    HID_start_update_thread();
 
     if (index >= XUSER_MAX_COUNT)
         return ERROR_BAD_ARGUMENTS;
@@ -421,7 +421,7 @@ DWORD WINAPI DECLSPEC_HOTPATCH XInputGetCapabilities(DWORD index, DWORD flags, X
 {
     TRACE("(index %u, flags 0x%x, capabilities %p)\n", index, flags, capabilities);
 
-    HID_find_gamepads();
+    HID_start_update_thread();
 
     if (index >= XUSER_MAX_COUNT)
         return ERROR_BAD_ARGUMENTS;
diff --git a/dlls/xinput1_3/xinput_private.h b/dlls/xinput1_3/xinput_private.h
index 79c3023c543..b2bd8a1ed57 100644
--- a/dlls/xinput1_3/xinput_private.h
+++ b/dlls/xinput1_3/xinput_private.h
@@ -30,7 +30,7 @@ typedef struct _xinput_controller
 extern CRITICAL_SECTION xinput_crit;
 extern xinput_controller controllers[XUSER_MAX_COUNT];
 
-void HID_find_gamepads(void) DECLSPEC_HIDDEN;
+void HID_start_update_thread(void) DECLSPEC_HIDDEN;
 void HID_stop_update_thread(void) DECLSPEC_HIDDEN;
 void HID_update_state(xinput_controller* device, XINPUT_STATE *state) DECLSPEC_HIDDEN;
 DWORD HID_set_state(xinput_controller* device, XINPUT_VIBRATION* state) DECLSPEC_HIDDEN;
-- 
2.32.0




More information about the wine-devel mailing list