Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/xinput1_3/main.c | 53 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-)
diff --git a/dlls/xinput1_3/main.c b/dlls/xinput1_3/main.c index ae2670ba306..63f125ae528 100644 --- a/dlls/xinput1_3/main.c +++ b/dlls/xinput1_3/main.c @@ -119,6 +119,8 @@ static struct xinput_controller controllers[XUSER_MAX_COUNT] = };
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) { @@ -294,8 +296,12 @@ failed: return FALSE; }
+static BOOL WINAPI start_update_thread_once( INIT_ONCE *once, void *param, void **context ); + static 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; SP_DEVICE_INTERFACE_DATA iface = {sizeof(iface)}; @@ -308,6 +314,8 @@ static void HID_find_gamepads(void) GUID guid; int i;
+ InitOnceExecuteOnce(&init_once, start_update_thread_once, NULL, NULL); + idx = GetTickCount(); if ((idx - last_check) < 2000) return;
@@ -383,9 +391,16 @@ static void controller_destroy(struct xinput_controller *controller) LeaveCriticalSection(&controller->crit); }
-static void HID_destroy_gamepads(void) +static void 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++) controller_destroy(&controllers[i]); }
@@ -523,6 +538,40 @@ static void HID_update_state(struct xinput_controller *controller, XINPUT_STATE memcpy(state, &controller->state, sizeof(*state)); }
+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_once( 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 BOOL controller_lock(struct xinput_controller *controller) { if (!controller->device) return FALSE; @@ -552,7 +601,7 @@ BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, LPVOID reserved) break; case DLL_PROCESS_DETACH: if (reserved) break; - HID_destroy_gamepads(); + stop_update_thread(); break; } return TRUE;
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/xinput1_3/main.c | 49 +++++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 27 deletions(-)
diff --git a/dlls/xinput1_3/main.c b/dlls/xinput1_3/main.c index 63f125ae528..45ccb5f79db 100644 --- a/dlls/xinput1_3/main.c +++ b/dlls/xinput1_3/main.c @@ -118,7 +118,6 @@ static struct xinput_controller controllers[XUSER_MAX_COUNT] = {{ &controller_critsect_debug[3], -1, 0, 0, 0, 0 }}, };
-static DWORD last_check = 0; static HANDLE stop_event; static HANDLE done_event;
@@ -296,12 +295,8 @@ failed: return FALSE; }
-static BOOL WINAPI start_update_thread_once( INIT_ONCE *once, void *param, void **context ); - -static void HID_find_gamepads(void) +static void update_controller_list(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; SP_DEVICE_INTERFACE_DATA iface = {sizeof(iface)}; @@ -314,20 +309,6 @@ static void HID_find_gamepads(void) GUID guid; int i;
- InitOnceExecuteOnce(&init_once, start_update_thread_once, 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(&guid);
set = SetupDiGetClassDevsW(&guid, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); @@ -368,7 +349,6 @@ static void HID_find_gamepads(void) }
SetupDiDestroyDeviceInfoList(set); - LeaveCriticalSection(&xinput_crit); }
static void controller_destroy(struct xinput_controller *controller) @@ -541,14 +521,18 @@ static void HID_update_state(struct xinput_controller *controller, XINPUT_STATE 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); @@ -569,9 +553,20 @@ static BOOL WINAPI start_update_thread_once( INIT_ONCE *once, void *param, void if (!thread) ERR("failed to create update thread, error %u\n", GetLastError()); CloseHandle(thread);
+ /* do it once now, to resolve delayed imports and populate the initial list */ + EnterCriticalSection(&xinput_crit); + update_controller_list(); + LeaveCriticalSection(&xinput_crit); + return TRUE; }
+static void start_update_thread(void) +{ + static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT; + InitOnceExecuteOnce(&init_once, start_update_thread_once, NULL, NULL); +} + static BOOL controller_lock(struct xinput_controller *controller) { if (!controller->device) return FALSE; @@ -617,7 +612,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(); + start_update_thread();
for (index = 0; index < XUSER_MAX_COUNT; index++) { @@ -634,7 +629,7 @@ DWORD WINAPI DECLSPEC_HOTPATCH XInputSetState(DWORD index, XINPUT_VIBRATION *vib
TRACE("(index %u, vibration %p)\n", index, vibration);
- HID_find_gamepads(); + start_update_thread();
if (index >= XUSER_MAX_COUNT) return ERROR_BAD_ARGUMENTS; if (!controller_lock(&controllers[index])) return ERROR_DEVICE_NOT_CONNECTED; @@ -652,7 +647,7 @@ static DWORD xinput_get_state(DWORD index, XINPUT_STATE *state) { if (!state) return ERROR_BAD_ARGUMENTS;
- HID_find_gamepads(); + start_update_thread();
if (index >= XUSER_MAX_COUNT) return ERROR_BAD_ARGUMENTS; if (!controller_lock(&controllers[index])) return ERROR_DEVICE_NOT_CONNECTED; @@ -908,7 +903,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(); + start_update_thread();
if (index >= XUSER_MAX_COUNT) return ERROR_BAD_ARGUMENTS;
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/xinput1_3/main.c | 235 +++++++++++++++++++++--------------------- 1 file changed, 118 insertions(+), 117 deletions(-)
diff --git a/dlls/xinput1_3/main.c b/dlls/xinput1_3/main.c index 45ccb5f79db..4770b64681e 100644 --- a/dlls/xinput1_3/main.c +++ b/dlls/xinput1_3/main.c @@ -70,7 +70,10 @@ struct xinput_controller HIDP_VALUE_CAPS ry_caps; HIDP_VALUE_CAPS rt_caps;
- char *input_report_buf[2]; + HANDLE read_event; + OVERLAPPED read_ovl; + + char *input_report_buf; char *output_report_buf; } hid; }; @@ -120,6 +123,7 @@ static struct xinput_controller controllers[XUSER_MAX_COUNT] =
static HANDLE stop_event; static HANDLE done_event; +static HANDLE update_event;
static BOOL find_opened_device(SP_DEVICE_INTERFACE_DETAIL_DATA_W *detail, int *free_slot) { @@ -252,6 +256,11 @@ static void controller_enable(struct xinput_controller *controller) if (controller->enabled) return; if (controller->caps.Flags & XINPUT_CAPS_FFB_SUPPORTED) HID_set_state(controller, &state); controller->enabled = TRUE; + + memset(&controller->hid.read_ovl, 0, sizeof(controller->hid.read_ovl)); + controller->hid.read_ovl.hEvent = controller->hid.read_event; + ReadFile(controller->device, controller->hid.input_report_buf, controller->hid.caps.InputReportByteLength, NULL, &controller->hid.read_ovl); + SetEvent(update_event); }
static void controller_disable(struct xinput_controller *controller) @@ -261,19 +270,25 @@ static void controller_disable(struct xinput_controller *controller) if (!controller->enabled) return; if (controller->caps.Flags & XINPUT_CAPS_FFB_SUPPORTED) HID_set_state(controller, &state); controller->enabled = FALSE; + + CancelIoEx(controller->device, &controller->hid.read_ovl); + SetEvent(update_event); }
static BOOL controller_init(struct xinput_controller *controller, PHIDP_PREPARSED_DATA preparsed, HIDP_CAPS *caps, HANDLE device, WCHAR *device_path) { + HANDLE event = NULL; + controller->hid.caps = *caps; if (!controller_check_caps(controller, preparsed)) goto failed; + if (!(event = CreateEventA(NULL, FALSE, FALSE, NULL))) goto failed;
TRACE("Found gamepad %s\n", debugstr_w(device_path));
controller->hid.preparsed = preparsed; - if (!(controller->hid.input_report_buf[0] = calloc(1, controller->hid.caps.InputReportByteLength))) goto failed; - if (!(controller->hid.input_report_buf[1] = calloc(1, controller->hid.caps.InputReportByteLength))) goto failed; + controller->hid.read_event = event; + if (!(controller->hid.input_report_buf = calloc(1, controller->hid.caps.InputReportByteLength))) goto failed; if (!(controller->hid.output_report_buf = calloc(1, controller->hid.caps.OutputReportByteLength))) goto failed;
memset(&controller->state, 0, sizeof(controller->state)); @@ -288,10 +303,10 @@ static BOOL controller_init(struct xinput_controller *controller, PHIDP_PREPARSE return TRUE;
failed: - free(controller->hid.input_report_buf[0]); - free(controller->hid.input_report_buf[1]); + free(controller->hid.input_report_buf); free(controller->hid.output_report_buf); memset(&controller->hid, 0, sizeof(controller->hid)); + CloseHandle(event); return FALSE; }
@@ -326,7 +341,8 @@ static void update_controller_list(void) 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); + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, + FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, NULL); if (device == INVALID_HANDLE_VALUE) continue;
preparsed = NULL; @@ -361,8 +377,7 @@ static void controller_destroy(struct xinput_controller *controller) CloseHandle(controller->device); controller->device = NULL;
- free(controller->hid.input_report_buf[0]); - free(controller->hid.input_report_buf[1]); + free(controller->hid.input_report_buf); free(controller->hid.output_report_buf); HidD_FreePreparsedData(controller->hid.preparsed); memset(&controller->hid, 0, sizeof(controller->hid)); @@ -380,6 +395,7 @@ static void stop_update_thread(void)
CloseHandle(stop_event); CloseHandle(done_event); + CloseHandle(update_event);
for (i = 0; i < XUSER_MAX_COUNT; i++) controller_destroy(&controllers[i]); } @@ -399,136 +415,126 @@ static LONG scale_value(ULONG value, const HIDP_VALUE_CAPS *caps, LONG min, LONG return min + MulDiv(tmp - caps->LogicalMin, max - min, caps->LogicalMax - caps->LogicalMin); }
-static void HID_update_state(struct xinput_controller *controller, XINPUT_STATE *state) +static void read_controller_state(struct xinput_controller *controller) { - int i; - char **report_buf = controller->hid.input_report_buf, *tmp; - ULONG report_len = controller->hid.caps.InputReportByteLength; + ULONG read_len, report_len = controller->hid.caps.InputReportByteLength; + char *report_buf = controller->hid.input_report_buf; + XINPUT_STATE state; NTSTATUS status; - USAGE buttons[11]; - ULONG button_length, value; + ULONG i, button_length, value;
- if (!controller->enabled) return; - - if (!HidD_GetInputReport(controller->device, report_buf[0], report_len)) + if (!GetOverlappedResult(controller->device, &controller->hid.read_ovl, &read_len, TRUE)) { - if (GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == ERROR_INVALID_HANDLE) - { - EnterCriticalSection(&xinput_crit); - controller_destroy(controller); - LeaveCriticalSection(&xinput_crit); - } - else ERR("Failed to get input report, HidD_GetInputReport failed with error %u\n", GetLastError()); + if (GetLastError() == ERROR_OPERATION_ABORTED) return; + if (GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == ERROR_INVALID_HANDLE) controller_destroy(controller); + else ERR("Failed to read input report, GetOverlappedResult failed with error %u\n", GetLastError()); return; }
- if (memcmp(report_buf[0], report_buf[1], report_len) != 0) - { - controller->state.dwPacketNumber++; - button_length = ARRAY_SIZE(buttons); - status = HidP_GetUsages(HidP_Input, HID_USAGE_PAGE_BUTTON, 0, buttons, &button_length, controller->hid.preparsed, report_buf[0], report_len); - if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetUsages HID_USAGE_PAGE_BUTTON returned %#x\n", status); + button_length = ARRAY_SIZE(buttons); + status = HidP_GetUsages(HidP_Input, HID_USAGE_PAGE_BUTTON, 0, buttons, &button_length, controller->hid.preparsed, report_buf, report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetUsages HID_USAGE_PAGE_BUTTON returned %#x\n", status);
- controller->state.Gamepad.wButtons = 0; - for (i = 0; i < button_length; i++) + state.Gamepad.wButtons = 0; + for (i = 0; i < button_length; i++) + { + switch (buttons[i]) { - switch (buttons[i]) - { - case 1: controller->state.Gamepad.wButtons |= XINPUT_GAMEPAD_A; break; - case 2: controller->state.Gamepad.wButtons |= XINPUT_GAMEPAD_B; break; - case 3: controller->state.Gamepad.wButtons |= XINPUT_GAMEPAD_X; break; - case 4: controller->state.Gamepad.wButtons |= XINPUT_GAMEPAD_Y; break; - case 5: controller->state.Gamepad.wButtons |= XINPUT_GAMEPAD_LEFT_SHOULDER; break; - case 6: controller->state.Gamepad.wButtons |= XINPUT_GAMEPAD_RIGHT_SHOULDER; break; - case 7: controller->state.Gamepad.wButtons |= XINPUT_GAMEPAD_BACK; break; - case 8: controller->state.Gamepad.wButtons |= XINPUT_GAMEPAD_START; break; - case 9: controller->state.Gamepad.wButtons |= XINPUT_GAMEPAD_LEFT_THUMB; break; - case 10: controller->state.Gamepad.wButtons |= XINPUT_GAMEPAD_RIGHT_THUMB; break; - case 11: controller->state.Gamepad.wButtons |= XINPUT_GAMEPAD_GUIDE; break; - } + case 1: state.Gamepad.wButtons |= XINPUT_GAMEPAD_A; break; + case 2: state.Gamepad.wButtons |= XINPUT_GAMEPAD_B; break; + case 3: state.Gamepad.wButtons |= XINPUT_GAMEPAD_X; break; + case 4: state.Gamepad.wButtons |= XINPUT_GAMEPAD_Y; break; + case 5: state.Gamepad.wButtons |= XINPUT_GAMEPAD_LEFT_SHOULDER; break; + case 6: state.Gamepad.wButtons |= XINPUT_GAMEPAD_RIGHT_SHOULDER; break; + case 7: state.Gamepad.wButtons |= XINPUT_GAMEPAD_BACK; break; + case 8: state.Gamepad.wButtons |= XINPUT_GAMEPAD_START; break; + case 9: state.Gamepad.wButtons |= XINPUT_GAMEPAD_LEFT_THUMB; break; + case 10: state.Gamepad.wButtons |= XINPUT_GAMEPAD_RIGHT_THUMB; break; + case 11: state.Gamepad.wButtons |= XINPUT_GAMEPAD_GUIDE; break; } + }
- status = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_HATSWITCH, &value, controller->hid.preparsed, report_buf[0], report_len); - if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetUsageValue HID_USAGE_PAGE_GENERIC / HID_USAGE_GENERIC_HATSWITCH returned %#x\n", status); - else - { - switch (value) - { - /* 8 1 2 - * 7 0 3 - * 6 5 4 */ - case 0: - break; - case 1: - controller->state.Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_UP; - break; - case 2: - controller->state.Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_UP | XINPUT_GAMEPAD_DPAD_RIGHT; - break; - case 3: - controller->state.Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_RIGHT; - break; - case 4: - controller->state.Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_RIGHT | XINPUT_GAMEPAD_DPAD_DOWN; - break; - case 5: - controller->state.Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_DOWN; - break; - case 6: - controller->state.Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_DOWN | XINPUT_GAMEPAD_DPAD_LEFT; - break; - case 7: - controller->state.Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_LEFT; - break; - case 8: - controller->state.Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_LEFT | XINPUT_GAMEPAD_DPAD_UP; - break; - } - } + status = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_HATSWITCH, &value, controller->hid.preparsed, report_buf, report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetUsageValue HID_USAGE_PAGE_GENERIC / HID_USAGE_GENERIC_HATSWITCH returned %#x\n", status); + else switch (value) + { + /* 8 1 2 + * 7 0 3 + * 6 5 4 */ + case 0: break; + case 1: state.Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_UP; break; + case 2: state.Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_UP | XINPUT_GAMEPAD_DPAD_RIGHT; break; + case 3: state.Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_RIGHT; break; + case 4: state.Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_RIGHT | XINPUT_GAMEPAD_DPAD_DOWN; break; + case 5: state.Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_DOWN; break; + case 6: state.Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_DOWN | XINPUT_GAMEPAD_DPAD_LEFT; break; + case 7: state.Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_LEFT; break; + case 8: state.Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_LEFT | XINPUT_GAMEPAD_DPAD_UP; break; + }
- status = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_X, &value, controller->hid.preparsed, report_buf[0], report_len); - if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetUsageValue HID_USAGE_PAGE_GENERIC / HID_USAGE_GENERIC_X returned %#x\n", status); - else controller->state.Gamepad.sThumbLX = scale_value(value, &controller->hid.lx_caps, -32768, 32767); + status = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_X, &value, controller->hid.preparsed, report_buf, report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetUsageValue HID_USAGE_PAGE_GENERIC / HID_USAGE_GENERIC_X returned %#x\n", status); + else state.Gamepad.sThumbLX = scale_value(value, &controller->hid.lx_caps, -32768, 32767);
- status = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Y, &value, controller->hid.preparsed, report_buf[0], report_len); - if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetUsageValue HID_USAGE_PAGE_GENERIC / HID_USAGE_GENERIC_Y returned %#x\n", status); - else controller->state.Gamepad.sThumbLY = -scale_value(value, &controller->hid.ly_caps, -32768, 32767) - 1; + status = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Y, &value, controller->hid.preparsed, report_buf, report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetUsageValue HID_USAGE_PAGE_GENERIC / HID_USAGE_GENERIC_Y returned %#x\n", status); + else state.Gamepad.sThumbLY = -scale_value(value, &controller->hid.ly_caps, -32768, 32767) - 1;
- status = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_RX, &value, controller->hid.preparsed, report_buf[0], report_len); - if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetUsageValue HID_USAGE_PAGE_GENERIC / HID_USAGE_GENERIC_RX returned %#x\n", status); - else controller->state.Gamepad.sThumbRX = scale_value(value, &controller->hid.rx_caps, -32768, 32767); + status = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_RX, &value, controller->hid.preparsed, report_buf, report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetUsageValue HID_USAGE_PAGE_GENERIC / HID_USAGE_GENERIC_RX returned %#x\n", status); + else state.Gamepad.sThumbRX = scale_value(value, &controller->hid.rx_caps, -32768, 32767);
- status = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_RY, &value, controller->hid.preparsed, report_buf[0], report_len); - if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetUsageValue HID_USAGE_PAGE_GENERIC / HID_USAGE_GENERIC_RY returned %#x\n", status); - else controller->state.Gamepad.sThumbRY = -scale_value(value, &controller->hid.ry_caps, -32768, 32767) - 1; + status = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_RY, &value, controller->hid.preparsed, report_buf, report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetUsageValue HID_USAGE_PAGE_GENERIC / HID_USAGE_GENERIC_RY returned %#x\n", status); + else state.Gamepad.sThumbRY = -scale_value(value, &controller->hid.ry_caps, -32768, 32767) - 1;
- status = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_RZ, &value, controller->hid.preparsed, report_buf[0], report_len); - if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetUsageValue HID_USAGE_PAGE_GENERIC / HID_USAGE_GENERIC_RZ returned %#x\n", status); - else controller->state.Gamepad.bRightTrigger = scale_value(value, &controller->hid.rt_caps, 0, 255); + status = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_RZ, &value, controller->hid.preparsed, report_buf, report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetUsageValue HID_USAGE_PAGE_GENERIC / HID_USAGE_GENERIC_RZ returned %#x\n", status); + else state.Gamepad.bRightTrigger = scale_value(value, &controller->hid.rt_caps, 0, 255);
- status = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Z, &value, controller->hid.preparsed, report_buf[0], report_len); - if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetUsageValue HID_USAGE_PAGE_GENERIC / HID_USAGE_GENERIC_Z returned %#x\n", status); - else controller->state.Gamepad.bLeftTrigger = scale_value(value, &controller->hid.lt_caps, 0, 255); - } + status = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Z, &value, controller->hid.preparsed, report_buf, report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetUsageValue HID_USAGE_PAGE_GENERIC / HID_USAGE_GENERIC_Z returned %#x\n", status); + else state.Gamepad.bLeftTrigger = scale_value(value, &controller->hid.lt_caps, 0, 255);
- tmp = report_buf[0]; - report_buf[0] = report_buf[1]; - report_buf[1] = tmp; - memcpy(state, &controller->state, sizeof(*state)); + EnterCriticalSection(&controller->crit); + if (controller->enabled) + { + state.dwPacketNumber = controller->state.dwPacketNumber + 1; + controller->state = state; + memset(&controller->hid.read_ovl, 0, sizeof(controller->hid.read_ovl)); + controller->hid.read_ovl.hEvent = controller->hid.read_event; + ReadFile(controller->device, controller->hid.input_report_buf, controller->hid.caps.InputReportByteLength, NULL, &controller->hid.read_ovl); + } + LeaveCriticalSection(&controller->crit); }
static DWORD WINAPI hid_update_thread_proc(void *param) { - HANDLE events[1]; - DWORD count, ret = WAIT_TIMEOUT; + struct xinput_controller *devices[XUSER_MAX_COUNT + 2]; + HANDLE events[XUSER_MAX_COUNT + 2]; + DWORD i, count = 2, ret = WAIT_TIMEOUT;
do { EnterCriticalSection(&xinput_crit); if (ret == WAIT_TIMEOUT) update_controller_list(); + if (ret < count - 2) read_controller_state(devices[ret]);
count = 0; + for (i = 0; i < XUSER_MAX_COUNT; ++i) + { + if (!controllers[i].device) continue; + EnterCriticalSection(&controllers[i].crit); + if (controllers[i].enabled) + { + devices[count] = controllers + i; + events[count] = controllers[i].hid.read_event; + count++; + } + LeaveCriticalSection(&controllers[i].crit); + } + events[count++] = update_event; events[count++] = stop_event; LeaveCriticalSection(&xinput_crit); } @@ -549,6 +555,9 @@ static BOOL WINAPI start_update_thread_once( INIT_ONCE *once, void *param, void done_event = CreateEventA(NULL, FALSE, FALSE, NULL); if (!done_event) ERR("failed to create stop event, error %u\n", GetLastError());
+ update_event = CreateEventA(NULL, FALSE, FALSE, NULL); + if (!update_event) ERR("failed to create update 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); @@ -652,15 +661,7 @@ static DWORD xinput_get_state(DWORD index, XINPUT_STATE *state) if (index >= XUSER_MAX_COUNT) return ERROR_BAD_ARGUMENTS; if (!controller_lock(&controllers[index])) return ERROR_DEVICE_NOT_CONNECTED;
- HID_update_state(&controllers[index], state); - - if (!controllers[index].device) - { - /* update_state may have disconnected the controller */ - controller_unlock(&controllers[index]); - return ERROR_DEVICE_NOT_CONNECTED; - } - + *state = controllers[index].state; controller_unlock(&controllers[index]);
return ERROR_SUCCESS;