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;
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;
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=95172
Your paranoid android.
=== debiant2 (32 bit report) ===
xinput1_3: xinput: Timeout
=== debiant2 (32 bit Chinese:China report) ===
xinput1_3: xinput: Timeout
=== debiant2 (32 bit WoW report) ===
xinput1_3: xinput: Timeout
=== debiant2 (64 bit WoW report) ===
xinput1_3: xinput: Timeout
On 8/6/21 11:21 AM, Marvin wrote:
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=95172
Your paranoid android.
=== debiant2 (32 bit report) ===
xinput1_3: xinput: Timeout
=== debiant2 (32 bit Chinese:China report) ===
xinput1_3: xinput: Timeout
=== debiant2 (32 bit WoW report) ===
xinput1_3: xinput: Timeout
=== debiant2 (64 bit WoW report) ===
xinput1_3: xinput: Timeout
Oops, please ignore this.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/xinput1_3/hid.c | 230 +++++++++++++++++--------------- dlls/xinput1_3/xinput_main.c | 10 +- dlls/xinput1_3/xinput_private.h | 1 - 3 files changed, 123 insertions(+), 118 deletions(-)
diff --git a/dlls/xinput1_3/hid.c b/dlls/xinput1_3/hid.c index 6aacf0ac9cd..79fa2104b1f 100644 --- a/dlls/xinput1_3/hid.c +++ b/dlls/xinput1_3/hid.c @@ -60,10 +60,12 @@ struct hid_platform_private { HIDP_CAPS caps;
HANDLE device; + HANDLE read_event; + OVERLAPPED read_ovl; WCHAR *device_path; BOOL enabled;
- char *input_report_buf[2]; + char *input_report_buf; char *output_report_buf;
struct axis_info lx, ly, ltrigger, rx, ry, rtrigger; @@ -71,6 +73,7 @@ struct hid_platform_private {
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) { @@ -120,7 +123,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; @@ -145,17 +149,35 @@ static void update_controller_list(void) SetupDiDestroyDeviceInfoList(set); }
+static void read_controller_state(xinput_controller *device); + static DWORD WINAPI hid_update_thread_proc(void *param) { - HANDLE events[1]; - DWORD count, ret = WAIT_TIMEOUT; + struct hid_platform_private *private; + 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 (!(private = controllers[i].platform_private)) continue; + EnterCriticalSection(&controllers[i].crit); + if (private->enabled) + { + devices[count] = controllers + i; + events[count] = private->read_event; + count++; + } + LeaveCriticalSection(&controllers[i].crit); + } + events[count++] = update_event; events[count++] = stop_event; LeaveCriticalSection(&xinput_crit); } @@ -176,6 +198,9 @@ static BOOL WINAPI start_update_thread( INIT_ONCE *once, void *param, void **con 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); @@ -287,36 +312,39 @@ static BOOL init_controller(xinput_controller *controller, PHIDP_PREPARSED_DATA { size_t size; struct hid_platform_private *private; + HANDLE event = NULL;
if (!(private = calloc(1, sizeof(struct hid_platform_private)))) return FALSE; private->caps = *caps; if (!VerifyGamepad(ppd, &controller->caps, private)) goto failed; + if (!(event = CreateEventA(NULL, FALSE, FALSE, NULL))) goto failed;
TRACE("Found gamepad %s\n", debugstr_w(device_path));
private->ppd = ppd; + private->read_event = event; private->device = device; - if (!(private->input_report_buf[0] = calloc(1, private->caps.InputReportByteLength))) goto failed; - if (!(private->input_report_buf[1] = calloc(1, private->caps.InputReportByteLength))) goto failed; + if (!(private->input_report_buf = calloc(1, private->caps.InputReportByteLength))) goto failed; if (!(private->output_report_buf = calloc(1, private->caps.OutputReportByteLength))) goto failed; size = (lstrlenW(device_path) + 1) * sizeof(WCHAR); if (!(private->device_path = malloc(size))) goto failed; memcpy(private->device_path, device_path, size); - private->enabled = TRUE; + private->enabled = FALSE;
memset(&controller->state, 0, sizeof(controller->state)); memset(&controller->vibration, 0, sizeof(controller->vibration));
EnterCriticalSection(&controller->crit); controller->platform_private = private; + HID_enable(controller, TRUE); LeaveCriticalSection(&controller->crit); return TRUE;
failed: free(private->device_path); - free(private->input_report_buf[0]); - free(private->input_report_buf[1]); + free(private->input_report_buf); free(private->output_report_buf); + CloseHandle(event); free(private); return FALSE; } @@ -335,11 +363,11 @@ static void remove_gamepad(xinput_controller *device) { struct hid_platform_private *private = device->platform_private;
+ HID_enable(device, FALSE); device->platform_private = NULL;
CloseHandle(private->device); - free(private->input_report_buf[0]); - free(private->input_report_buf[1]); + free(private->input_report_buf); free(private->output_report_buf); free(private->device_path); HidD_FreePreparsedData(private->ppd); @@ -358,6 +386,7 @@ void HID_stop_update_thread(void)
CloseHandle(stop_event); CloseHandle(done_event); + CloseHandle(update_event);
for (i = 0; i < XUSER_MAX_COUNT; i++) remove_gamepad(&controllers[i]); @@ -373,125 +402,100 @@ static BYTE scale_byte(LONG value, const struct axis_info *axis) return (((ULONGLONG)(value - axis->min)) * 0xff) / axis->range; }
-void HID_update_state(xinput_controller *device, XINPUT_STATE *state) +static void read_controller_state(xinput_controller *device) { struct hid_platform_private *private = device->platform_private; - int i; - char **report_buf = private->input_report_buf, *tmp; - ULONG report_len = private->caps.InputReportByteLength; + ULONG read_len, report_len = private->caps.InputReportByteLength; + char *report_buf = private->input_report_buf; + XINPUT_STATE state; NTSTATUS status; - USAGE buttons[11]; ULONG button_length, hat_value; - LONG value; + LONG i, value;
- if (!private->enabled) + if (!GetOverlappedResult(private->device, &private->read_ovl, &read_len, TRUE)) + { + if (GetLastError() == ERROR_OPERATION_ABORTED) return; + if (GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == ERROR_INVALID_HANDLE) remove_gamepad(device); + else ERR("Failed to read input report, GetOverlappedResult failed with error %u\n", GetLastError()); return; + } + + button_length = ARRAY_SIZE(buttons); + status = HidP_GetUsages(HidP_Input, HID_USAGE_PAGE_BUTTON, 0, buttons, &button_length, private->ppd, report_buf, report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetUsages HID_USAGE_PAGE_BUTTON returned %#x\n", status);
- if (!HidD_GetInputReport(private->device, report_buf[0], report_len)) + state.Gamepad.wButtons = 0; + for (i = 0; i < button_length; i++) { - if (GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == ERROR_INVALID_HANDLE) + switch (buttons[i]) { - EnterCriticalSection(&xinput_crit); - remove_gamepad(device); - LeaveCriticalSection(&xinput_crit); + 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; } - else ERR("Failed to get input report, HidD_GetInputReport failed with error %u\n", GetLastError()); - return; }
- if (memcmp(report_buf[0], report_buf[1], report_len) != 0) + status = HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_HATSWITCH, &hat_value, private->ppd, 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 (hat_value) { - device->state.dwPacketNumber++; - button_length = ARRAY_SIZE(buttons); - status = HidP_GetUsages(HidP_Input, HID_USAGE_PAGE_BUTTON, 0, buttons, &button_length, private->ppd, report_buf[0], report_len); - if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetUsages HID_USAGE_PAGE_BUTTON returned %#x\n", status); - - device->state.Gamepad.wButtons = 0; - for (i = 0; i < button_length; i++) - { - switch (buttons[i]) - { - case 1: device->state.Gamepad.wButtons |= XINPUT_GAMEPAD_A; break; - case 2: device->state.Gamepad.wButtons |= XINPUT_GAMEPAD_B; break; - case 3: device->state.Gamepad.wButtons |= XINPUT_GAMEPAD_X; break; - case 4: device->state.Gamepad.wButtons |= XINPUT_GAMEPAD_Y; break; - case 5: device->state.Gamepad.wButtons |= XINPUT_GAMEPAD_LEFT_SHOULDER; break; - case 6: device->state.Gamepad.wButtons |= XINPUT_GAMEPAD_RIGHT_SHOULDER; break; - case 7: device->state.Gamepad.wButtons |= XINPUT_GAMEPAD_BACK; break; - case 8: device->state.Gamepad.wButtons |= XINPUT_GAMEPAD_START; break; - case 9: device->state.Gamepad.wButtons |= XINPUT_GAMEPAD_LEFT_THUMB; break; - case 10: device->state.Gamepad.wButtons |= XINPUT_GAMEPAD_RIGHT_THUMB; break; - case 11: device->state.Gamepad.wButtons |= XINPUT_GAMEPAD_GUIDE; break; - } - } + /* 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_HATSWITCH, &hat_value, private->ppd, 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(hat_value){ - /* 8 1 2 - * 7 0 3 - * 6 5 4 */ - case 0: - break; - case 1: - device->state.Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_UP; - break; - case 2: - device->state.Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_UP | XINPUT_GAMEPAD_DPAD_RIGHT; - break; - case 3: - device->state.Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_RIGHT; - break; - case 4: - device->state.Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_RIGHT | XINPUT_GAMEPAD_DPAD_DOWN; - break; - case 5: - device->state.Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_DOWN; - break; - case 6: - device->state.Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_DOWN | XINPUT_GAMEPAD_DPAD_LEFT; - break; - case 7: - device->state.Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_LEFT; - break; - case 8: - device->state.Gamepad.wButtons |= XINPUT_GAMEPAD_DPAD_LEFT | XINPUT_GAMEPAD_DPAD_UP; - break; - } - } + status = HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_X, &value, private->ppd, report_buf, report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetScaledUsageValue HID_USAGE_PAGE_GENERIC / HID_USAGE_GENERIC_X returned %#x\n", status); + else state.Gamepad.sThumbLX = scale_short(value, &private->lx);
- status = HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_X, &value, private->ppd, report_buf[0], report_len); - if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetScaledUsageValue HID_USAGE_PAGE_GENERIC / HID_USAGE_GENERIC_X returned %#x\n", status); - else device->state.Gamepad.sThumbLX = scale_short(value, &private->lx); + status = HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Y, &value, private->ppd, report_buf, report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetScaledUsageValue HID_USAGE_PAGE_GENERIC / HID_USAGE_GENERIC_Y returned %#x\n", status); + else state.Gamepad.sThumbLY = -scale_short(value, &private->ly) - 1;
- status = HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Y, &value, private->ppd, report_buf[0], report_len); - if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetScaledUsageValue HID_USAGE_PAGE_GENERIC / HID_USAGE_GENERIC_Y returned %#x\n", status); - else device->state.Gamepad.sThumbLY = -scale_short(value, &private->ly) - 1; + status = HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_RX, &value, private->ppd, report_buf, report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetScaledUsageValue HID_USAGE_PAGE_GENERIC / HID_USAGE_GENERIC_RX returned %#x\n", status); + else state.Gamepad.sThumbRX = scale_short(value, &private->rx);
- status = HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_RX, &value, private->ppd, report_buf[0], report_len); - if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetScaledUsageValue HID_USAGE_PAGE_GENERIC / HID_USAGE_GENERIC_RX returned %#x\n", status); - else device->state.Gamepad.sThumbRX = scale_short(value, &private->rx); + status = HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_RY, &value, private->ppd, report_buf, report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetScaledUsageValue HID_USAGE_PAGE_GENERIC / HID_USAGE_GENERIC_RY returned %#x\n", status); + else state.Gamepad.sThumbRY = -scale_short(value, &private->ry) - 1;
- status = HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_RY, &value, private->ppd, report_buf[0], report_len); - if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetScaledUsageValue HID_USAGE_PAGE_GENERIC / HID_USAGE_GENERIC_RY returned %#x\n", status); - else device->state.Gamepad.sThumbRY = -scale_short(value, &private->ry) - 1; + status = HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_RZ, &value, private->ppd, report_buf, report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetScaledUsageValue HID_USAGE_PAGE_GENERIC / HID_USAGE_GENERIC_RZ returned %#x\n", status); + else state.Gamepad.bRightTrigger = scale_byte(value, &private->rtrigger);
- status = HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_RZ, &value, private->ppd, report_buf[0], report_len); - if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetScaledUsageValue HID_USAGE_PAGE_GENERIC / HID_USAGE_GENERIC_RZ returned %#x\n", status); - else device->state.Gamepad.bRightTrigger = scale_byte(value, &private->rtrigger); + status = HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Z, &value, private->ppd, report_buf, report_len); + if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetScaledUsageValue HID_USAGE_PAGE_GENERIC / HID_USAGE_GENERIC_Z returned %#x\n", status); + else state.Gamepad.bLeftTrigger = scale_byte(value, &private->ltrigger);
- status = HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Z, &value, private->ppd, report_buf[0], report_len); - if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetScaledUsageValue HID_USAGE_PAGE_GENERIC / HID_USAGE_GENERIC_Z returned %#x\n", status); - else device->state.Gamepad.bLeftTrigger = scale_byte(value, &private->ltrigger); + EnterCriticalSection(&device->crit); + if (private->enabled) + { + state.dwPacketNumber = device->state.dwPacketNumber + 1; + device->state = state; + memset(&private->read_ovl, 0, sizeof(private->read_ovl)); + private->read_ovl.hEvent = private->read_event; + ReadFile(private->device, private->input_report_buf, private->caps.InputReportByteLength, NULL, &private->read_ovl); } - - tmp = report_buf[0]; - report_buf[0] = report_buf[1]; - report_buf[1] = tmp; - memcpy(state, &device->state, sizeof(*state)); + LeaveCriticalSection(&device->crit); }
DWORD HID_set_state(xinput_controller* device, XINPUT_VIBRATION* state) @@ -545,5 +549,15 @@ void HID_enable(xinput_controller* device, BOOL enable) } }
+ if (private->enabled && !enable) + CancelIoEx(private->device, &private->read_ovl); + else if (!private->enabled && enable) + { + memset(&private->read_ovl, 0, sizeof(private->read_ovl)); + private->read_ovl.hEvent = private->read_event; + ReadFile(private->device, private->input_report_buf, private->caps.InputReportByteLength, NULL, &private->read_ovl); + } + + if (private->enabled != enable) SetEvent(update_event); private->enabled = enable; } diff --git a/dlls/xinput1_3/xinput_main.c b/dlls/xinput1_3/xinput_main.c index 56a5802fc6a..cac5af74b8d 100644 --- a/dlls/xinput1_3/xinput_main.c +++ b/dlls/xinput1_3/xinput_main.c @@ -164,15 +164,7 @@ static DWORD xinput_get_state(DWORD index, XINPUT_STATE *state) if (!verify_and_lock_device(&controllers[index])) return ERROR_DEVICE_NOT_CONNECTED;
- HID_update_state(&controllers[index], state); - - if (!controllers[index].platform_private) - { - /* update_state may have disconnected the controller */ - unlock_device(&controllers[index]); - return ERROR_DEVICE_NOT_CONNECTED; - } - + *state = controllers[index].state; unlock_device(&controllers[index]);
return ERROR_SUCCESS; diff --git a/dlls/xinput1_3/xinput_private.h b/dlls/xinput1_3/xinput_private.h index b2bd8a1ed57..96ec1fc88ad 100644 --- a/dlls/xinput1_3/xinput_private.h +++ b/dlls/xinput1_3/xinput_private.h @@ -32,6 +32,5 @@ extern xinput_controller controllers[XUSER_MAX_COUNT];
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; void HID_enable(xinput_controller* device, BOOL enable) DECLSPEC_HIDDEN;
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=95173
Your paranoid android.
=== debiant2 (32 bit report) ===
xinput1_3: xinput: Timeout
=== debiant2 (32 bit Chinese:China report) ===
xinput1_3: xinput: Timeout
=== debiant2 (32 bit WoW report) ===
xinput1_3: xinput: Timeout
=== debiant2 (64 bit WoW report) ===
xinput1_3: xinput: Timeout