Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/xinput1_3/hid.c | 49 ++++++++++++++++++++++++++++++++- dlls/xinput1_3/xinput_main.c | 2 +- dlls/xinput1_3/xinput_private.h | 2 +- 3 files changed, 50 insertions(+), 3 deletions(-)
diff --git a/dlls/xinput1_3/hid.c b/dlls/xinput1_3/hid.c index 00907b54bed..176e18fd95c 100644 --- a/dlls/xinput1_3/hid.c +++ b/dlls/xinput1_3/hid.c @@ -70,6 +70,8 @@ struct hid_platform_private { };
static DWORD last_check = 0; +static HANDLE stop_event; +static HANDLE done_event;
static BOOL find_opened_device(SP_DEVICE_INTERFACE_DETAIL_DATA_W *detail, int *free_slot) { @@ -85,6 +87,40 @@ static BOOL find_opened_device(SP_DEVICE_INTERFACE_DETAIL_DATA_W *detail, int *f return FALSE; }
+static DWORD WINAPI hid_update_thread_proc(void *param) +{ + HANDLE events[1]; + DWORD count, ret; + + do + { + count = 0; + events[count++] = stop_event; + } + while ((ret = WaitForMultipleObjectsEx( count, events, FALSE, INFINITE, TRUE )) < count - 1); + + if (ret != count - 1) ERR("update thread exited unexpectedly, ret %u\n", ret); + SetEvent(done_event); + return ret; +} + +static BOOL WINAPI start_update_thread( INIT_ONCE *once, void *param, void **context ) +{ + HANDLE thread; + + stop_event = CreateEventA(NULL, FALSE, FALSE, NULL); + if (!stop_event) ERR("failed to create stop event, error %u\n", GetLastError()); + + done_event = CreateEventA(NULL, FALSE, FALSE, NULL); + if (!done_event) ERR("failed to create stop event, error %u\n", GetLastError()); + + thread = CreateThread(NULL, 0, hid_update_thread_proc, NULL, 0, NULL); + if (!thread) ERR("failed to create update thread, error %u\n", GetLastError()); + CloseHandle(thread); + + return TRUE; +} + static void MarkUsage(struct hid_platform_private *private, WORD usage, LONG min, LONG max, USHORT bits) { struct axis_info info = {min, max-min, bits}; @@ -223,6 +259,8 @@ failed:
void HID_find_gamepads(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; @@ -235,6 +273,8 @@ void HID_find_gamepads(void) DWORD idx; int i;
+ InitOnceExecuteOnce(&init_once, start_update_thread, NULL, NULL); + idx = GetTickCount(); if ((idx - last_check) < 2000) return; @@ -317,9 +357,16 @@ static void remove_gamepad(xinput_controller *device) LeaveCriticalSection(&device->crit); }
-void HID_destroy_gamepads(void) +void HID_stop_update_thread(void) { int i; + + SetEvent(stop_event); + WaitForSingleObject(done_event, INFINITE); + + CloseHandle(stop_event); + CloseHandle(done_event); + for (i = 0; i < XUSER_MAX_COUNT; i++) remove_gamepad(&controllers[i]); } diff --git a/dlls/xinput1_3/xinput_main.c b/dlls/xinput1_3/xinput_main.c index 2d9f54c83f2..547247dc76e 100644 --- a/dlls/xinput1_3/xinput_main.c +++ b/dlls/xinput1_3/xinput_main.c @@ -104,7 +104,7 @@ BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, LPVOID reserved) break; case DLL_PROCESS_DETACH: if (reserved) break; - HID_destroy_gamepads(); + HID_stop_update_thread(); break; } return TRUE; diff --git a/dlls/xinput1_3/xinput_private.h b/dlls/xinput1_3/xinput_private.h index 2bf16c0ffce..79c3023c543 100644 --- a/dlls/xinput1_3/xinput_private.h +++ b/dlls/xinput1_3/xinput_private.h @@ -31,7 +31,7 @@ extern CRITICAL_SECTION xinput_crit; extern xinput_controller controllers[XUSER_MAX_COUNT];
void HID_find_gamepads(void) DECLSPEC_HIDDEN; -void HID_destroy_gamepads(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; void HID_enable(xinput_controller* device, BOOL enable) DECLSPEC_HIDDEN;