Signed-off-by: Rémi Bernon rbernon@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;