From 4d3db6d2d743ea8fc61ed122f27baeddf30ee2ea Mon Sep 17 00:00:00 2001 From: Andrew Eikum Date: Tue, 22 Oct 2019 15:00:26 -0500 Subject: [PATCH] xinput: Make device hotplugging thread-safe. Signed-off-by: Andrew Eikum Signed-off-by: Alexandre Julliard --- dlls/xinput1_3/hid.c | 251 ++++++++++++++++---------------- dlls/xinput1_3/xinput_main.c | 101 +++++++++++-- dlls/xinput1_3/xinput_private.h | 7 +- 3 files changed, 219 insertions(+), 140 deletions(-) diff --git a/dlls/xinput1_3/hid.c b/dlls/xinput1_3/hid.c index 38c93beb80f..477d5304cac 100644 --- a/dlls/xinput1_3/hid.c +++ b/dlls/xinput1_3/hid.c @@ -47,15 +47,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(xinput); #define XINPUT_GAMEPAD_GUIDE 0x0400 -static CRITICAL_SECTION hid_xinput_crit; -static CRITICAL_SECTION_DEBUG hid_critsect_debug = -{ - 0, 0, &hid_xinput_crit, - { &hid_critsect_debug.ProcessLocksList, &hid_critsect_debug.ProcessLocksList }, - 0, 0, { (DWORD_PTR)(__FILE__ ": hid_xinput_crit") } -}; -static CRITICAL_SECTION hid_xinput_crit = { &hid_critsect_debug, -1, 0, 0, 0, 0 }; - struct axis_info { LONG min; @@ -69,8 +60,6 @@ struct hid_platform_private { WCHAR *device_path; BOOL enabled; - CRITICAL_SECTION crit; - DWORD report_length; BYTE current_report; CHAR *reports[2]; @@ -195,9 +184,6 @@ static void build_private(struct hid_platform_private *private, PHIDP_PREPARSED_ private->device_path = HeapAlloc(GetProcessHeap(), 0, size); memcpy(private->device_path, path, size); private->enabled = TRUE; - - InitializeCriticalSection(&private->crit); - private->crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JoystickImpl*->generic.base.crit"); } void HID_find_gamepads(xinput_controller *devices) @@ -208,20 +194,26 @@ void HID_find_gamepads(xinput_controller *devices) SP_DEVICE_INTERFACE_DETAIL_DATA_W *data; PHIDP_PREPARSED_DATA ppd; DWORD detail_size = MAX_PATH * sizeof(WCHAR); - HANDLE device = INVALID_HANDLE_VALUE; + HANDLE device; HIDP_CAPS Caps; - DWORD idx,didx; - int i; + DWORD idx; + int i, open_device_idx; 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); - EnterCriticalSection(&hid_xinput_crit); - device_info_set = SetupDiGetClassDevsW(&hid_guid, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); data = HeapAlloc(GetProcessHeap(), 0 , sizeof(*data) + detail_size); @@ -230,9 +222,9 @@ void HID_find_gamepads(xinput_controller *devices) ZeroMemory(&interface_data, sizeof(interface_data)); interface_data.cbSize = sizeof(interface_data); - idx = didx = 0; + idx = 0; while (SetupDiEnumDeviceInterfaces(device_info_set, NULL, &hid_guid, idx++, - &interface_data) && didx < XUSER_MAX_COUNT) + &interface_data)) { static const WCHAR ig[] = {'I','G','_',0}; if (!SetupDiGetDeviceInterfaceDetailW(device_info_set, @@ -242,14 +234,24 @@ void HID_find_gamepads(xinput_controller *devices) if (!wcsstr(data->DevicePath, ig)) continue; + open_device_idx = -1; for (i = 0; i < XUSER_MAX_COUNT; i++) { struct hid_platform_private *private = devices[i].platform_private; - if (devices[i].connected && !wcscmp(data->DevicePath, private->device_path)) - break; + if (devices[i].connected) + { + if (!wcscmp(data->DevicePath, private->device_path)) + break; + } + else if(open_device_idx < 0) + open_device_idx = i; } if (i != XUSER_MAX_COUNT) + /* this device is already opened */ continue; + if (open_device_idx < 0) + /* no open device slots */ + break; device = CreateFileW(data->DevicePath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 ); if (device == INVALID_HANDLE_VALUE) continue; @@ -262,13 +264,12 @@ void HID_find_gamepads(xinput_controller *devices) Caps.Usage == 0x8 /* Multi-axis Controller */)) { struct hid_platform_private *private = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct hid_platform_private)); - if (VerifyGamepad(ppd, &(devices[didx].caps), private, &Caps)) + if (VerifyGamepad(ppd, &devices[open_device_idx].caps, private, &Caps)) { - TRACE("Found gamepad %i %s\n",didx, debugstr_w(data->DevicePath)); - devices[didx].connected = TRUE; + TRACE("Found gamepad %i %s\n", open_device_idx, debugstr_w(data->DevicePath)); build_private(private, ppd, &Caps, device, data->DevicePath); - devices[didx].platform_private = private; - didx++; + devices[open_device_idx].platform_private = private; + devices[open_device_idx].connected = TRUE; } else { @@ -282,41 +283,39 @@ void HID_find_gamepads(xinput_controller *devices) CloseHandle(device); HidD_FreePreparsedData(ppd); } - device = INVALID_HANDLE_VALUE; } HeapFree(GetProcessHeap(), 0, data); SetupDiDestroyDeviceInfoList(device_info_set); - LeaveCriticalSection(&hid_xinput_crit); - return; + LeaveCriticalSection(&xinput_crit); } static void remove_gamepad(xinput_controller *device) { + EnterCriticalSection(&device->crit); + if (device->connected) { struct hid_platform_private *private = device->platform_private; - EnterCriticalSection(&private->crit); + device->connected = FALSE; + CloseHandle(private->device); HeapFree(GetProcessHeap(), 0, private->reports[0]); HeapFree(GetProcessHeap(), 0, private->reports[1]); HeapFree(GetProcessHeap(), 0, private->device_path); HidD_FreePreparsedData(private->ppd); device->platform_private = NULL; - device->connected = FALSE; - LeaveCriticalSection(&private->crit); - DeleteCriticalSection(&private->crit); HeapFree(GetProcessHeap(), 0, private); } + + LeaveCriticalSection(&device->crit); } void HID_destroy_gamepads(xinput_controller *devices) { int i; - EnterCriticalSection(&hid_xinput_crit); for (i = 0; i < XUSER_MAX_COUNT; i++) remove_gamepad(&devices[i]); - LeaveCriticalSection(&hid_xinput_crit); } static SHORT scale_short(LONG value, const struct axis_info *axis) @@ -329,7 +328,7 @@ 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) +void HID_update_state(xinput_controller *device, XINPUT_STATE *state) { struct hid_platform_private *private = device->platform_private; int i; @@ -343,107 +342,107 @@ void HID_update_state(xinput_controller* device) if (!private->enabled) return; - EnterCriticalSection(&private->crit); if (!HidD_GetInputReport(private->device, target_report, private->report_length)) { if (GetLastError() == ERROR_ACCESS_DENIED || GetLastError() == ERROR_INVALID_HANDLE) + { + EnterCriticalSection(&xinput_crit); remove_gamepad(device); + LeaveCriticalSection(&xinput_crit); + } else ERR("Failed to get Input Report (%x)\n", GetLastError()); - LeaveCriticalSection(&private->crit); return; } - if (memcmp(report, target_report, private->report_length) == 0) + if (memcmp(report, target_report, private->report_length) != 0) { - LeaveCriticalSection(&private->crit); - return; - } + private->current_report = (private->current_report+1)%2; - private->current_report = (private->current_report+1)%2; + device->state.dwPacketNumber++; + button_length = ARRAY_SIZE(buttons); + HidP_GetUsages(HidP_Input, HID_USAGE_PAGE_BUTTON, 0, buttons, &button_length, private->ppd, target_report, private->report_length); - device->state.dwPacketNumber++; - button_length = ARRAY_SIZE(buttons); - HidP_GetUsages(HidP_Input, HID_USAGE_PAGE_BUTTON, 0, buttons, &button_length, private->ppd, target_report, private->report_length); - - device->state.Gamepad.wButtons = 0; - for (i = 0; i < button_length; i++) - { - switch (buttons[i]) + device->state.Gamepad.wButtons = 0; + for (i = 0; i < button_length; 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; + 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; + } } + + if(HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_HATSWITCH, &hat_value, + private->ppd, target_report, private->report_length) == HIDP_STATUS_SUCCESS) + { + 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; + } + } + + if(HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_X, &value, + private->ppd, target_report, private->report_length) == HIDP_STATUS_SUCCESS) + device->state.Gamepad.sThumbLX = scale_short(value, &private->lx); + + if(HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Y, &value, + private->ppd, target_report, private->report_length) == HIDP_STATUS_SUCCESS) + device->state.Gamepad.sThumbLY = -scale_short(value, &private->ly) - 1; + + if(HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_RX, &value, + private->ppd, target_report, private->report_length) == HIDP_STATUS_SUCCESS) + device->state.Gamepad.sThumbRX = scale_short(value, &private->rx); + + if(HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_RY, &value, + private->ppd, target_report, private->report_length) == HIDP_STATUS_SUCCESS) + device->state.Gamepad.sThumbRY = -scale_short(value, &private->ry) - 1; + + if(HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_RZ, &value, + private->ppd, target_report, private->report_length) == HIDP_STATUS_SUCCESS) + device->state.Gamepad.bRightTrigger = scale_byte(value, &private->rtrigger); + + if(HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Z, &value, + private->ppd, target_report, private->report_length) == HIDP_STATUS_SUCCESS) + device->state.Gamepad.bLeftTrigger = scale_byte(value, &private->ltrigger); } - if(HidP_GetUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_HATSWITCH, &hat_value, - private->ppd, target_report, private->report_length) == HIDP_STATUS_SUCCESS) - { - 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; - } - } - - if(HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_X, &value, - private->ppd, target_report, private->report_length) == HIDP_STATUS_SUCCESS) - device->state.Gamepad.sThumbLX = scale_short(value, &private->lx); - - if(HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Y, &value, - private->ppd, target_report, private->report_length) == HIDP_STATUS_SUCCESS) - device->state.Gamepad.sThumbLY = -scale_short(value, &private->ly) - 1; - - if(HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_RX, &value, - private->ppd, target_report, private->report_length) == HIDP_STATUS_SUCCESS) - device->state.Gamepad.sThumbRX = scale_short(value, &private->rx); - - if(HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_RY, &value, - private->ppd, target_report, private->report_length) == HIDP_STATUS_SUCCESS) - device->state.Gamepad.sThumbRY = -scale_short(value, &private->ry) - 1; - - if(HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_RZ, &value, - private->ppd, target_report, private->report_length) == HIDP_STATUS_SUCCESS) - device->state.Gamepad.bRightTrigger = scale_byte(value, &private->rtrigger); - - if(HidP_GetScaledUsageValue(HidP_Input, HID_USAGE_PAGE_GENERIC, 0, HID_USAGE_GENERIC_Z, &value, - private->ppd, target_report, private->report_length) == HIDP_STATUS_SUCCESS) - device->state.Gamepad.bLeftTrigger = scale_byte(value, &private->ltrigger); - LeaveCriticalSection(&private->crit); + memcpy(state, &device->state, sizeof(*state)); } DWORD HID_set_state(xinput_controller* device, XINPUT_VIBRATION* state) @@ -474,9 +473,7 @@ DWORD HID_set_state(xinput_controller* device, XINPUT_VIBRATION* state) report.right = (BYTE)(state->wRightMotorSpeed / 256); memset(&report.pad2, 0, sizeof(report.pad2)); - EnterCriticalSection(&private->crit); rc = HidD_SetOutputReport(private->device, &report, sizeof(report)); - LeaveCriticalSection(&private->crit); if (rc) return ERROR_SUCCESS; return GetLastError(); @@ -492,7 +489,6 @@ void HID_enable(xinput_controller* device, BOOL enable) if (device->caps.Flags & XINPUT_CAPS_FFB_SUPPORTED) { - EnterCriticalSection(&private->crit); if (private->enabled && !enable) { XINPUT_VIBRATION state; @@ -504,7 +500,6 @@ void HID_enable(xinput_controller* device, BOOL enable) { HID_set_state(device, &device->vibration); } - LeaveCriticalSection(&private->crit); } private->enabled = enable; diff --git a/dlls/xinput1_3/xinput_main.c b/dlls/xinput1_3/xinput_main.c index a417fec7ad1..5c83e87fb13 100644 --- a/dlls/xinput1_3/xinput_main.c +++ b/dlls/xinput1_3/xinput_main.c @@ -34,7 +34,66 @@ WINE_DEFAULT_DEBUG_CHANNEL(xinput); -xinput_controller controllers[XUSER_MAX_COUNT]; +/* xinput_crit guards controllers array */ +static CRITICAL_SECTION_DEBUG xinput_critsect_debug = +{ + 0, 0, &xinput_crit, + { &xinput_critsect_debug.ProcessLocksList, &xinput_critsect_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": xinput_crit") } +}; +CRITICAL_SECTION xinput_crit = { &xinput_critsect_debug, -1, 0, 0, 0, 0 }; + +static CRITICAL_SECTION_DEBUG controller_critsect_debug[XUSER_MAX_COUNT] = +{ + { + 0, 0, &controllers[0].crit, + { &controller_critsect_debug[0].ProcessLocksList, &controller_critsect_debug[0].ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": controllers[0].crit") } + }, + { + 0, 0, &controllers[1].crit, + { &controller_critsect_debug[1].ProcessLocksList, &controller_critsect_debug[1].ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": controllers[1].crit") } + }, + { + 0, 0, &controllers[2].crit, + { &controller_critsect_debug[2].ProcessLocksList, &controller_critsect_debug[2].ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": controllers[2].crit") } + }, + { + 0, 0, &controllers[3].crit, + { &controller_critsect_debug[3].ProcessLocksList, &controller_critsect_debug[3].ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": controllers[3].crit") } + }, +}; + +xinput_controller controllers[XUSER_MAX_COUNT] = { + {{ &controller_critsect_debug[0], -1, 0, 0, 0, 0 }}, + {{ &controller_critsect_debug[1], -1, 0, 0, 0, 0 }}, + {{ &controller_critsect_debug[2], -1, 0, 0, 0, 0 }}, + {{ &controller_critsect_debug[3], -1, 0, 0, 0, 0 }}, +}; + +static BOOL verify_and_lock_device(xinput_controller *device) +{ + if (!device->connected) + return FALSE; + + EnterCriticalSection(&device->crit); + + if (!device->connected) + { + LeaveCriticalSection(&device->crit); + return FALSE; + } + + return TRUE; +} + +static void unlock_device(xinput_controller *device) +{ + LeaveCriticalSection(&device->crit); +} BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, LPVOID reserved) { @@ -65,23 +124,30 @@ void WINAPI DECLSPEC_HOTPATCH XInputEnable(BOOL enable) for (index = 0; index < XUSER_MAX_COUNT; index ++) { - if (!controllers[index].connected) continue; + if (!verify_and_lock_device(&controllers[index])) continue; HID_enable(&controllers[index], enable); + unlock_device(&controllers[index]); } } DWORD WINAPI DECLSPEC_HOTPATCH XInputSetState(DWORD index, XINPUT_VIBRATION* vibration) { + DWORD ret; + TRACE("(index %u, vibration %p)\n", index, vibration); HID_find_gamepads(controllers); if (index >= XUSER_MAX_COUNT) return ERROR_BAD_ARGUMENTS; - if (!controllers[index].connected) + if (!verify_and_lock_device(&controllers[index])) return ERROR_DEVICE_NOT_CONNECTED; - return HID_set_state(&controllers[index], vibration); + ret = HID_set_state(&controllers[index], vibration); + + unlock_device(&controllers[index]); + + return ret; } /* Some versions of SteamOverlayRenderer hot-patch XInputGetStateEx() and call @@ -95,11 +161,19 @@ static DWORD xinput_get_state(DWORD index, XINPUT_STATE *state) if (index >= XUSER_MAX_COUNT) return ERROR_BAD_ARGUMENTS; - if (!controllers[index].connected) + if (!verify_and_lock_device(&controllers[index])) return ERROR_DEVICE_NOT_CONNECTED; - HID_update_state(&controllers[index]); - memcpy(state, &controllers[index].state, sizeof(XINPUT_STATE)); + HID_update_state(&controllers[index], state); + + if (!controllers[index].connected) + { + /* update_state may have disconnected the controller */ + unlock_device(&controllers[index]); + return ERROR_DEVICE_NOT_CONNECTED; + } + + unlock_device(&controllers[index]); return ERROR_SUCCESS; } @@ -151,13 +225,20 @@ DWORD WINAPI DECLSPEC_HOTPATCH XInputGetCapabilities(DWORD index, DWORD flags, X if (index >= XUSER_MAX_COUNT) return ERROR_BAD_ARGUMENTS; - if (!controllers[index].connected) - return ERROR_DEVICE_NOT_CONNECTED; - if (flags & XINPUT_FLAG_GAMEPAD && controllers[index].caps.SubType != XINPUT_DEVSUBTYPE_GAMEPAD) + + if (!verify_and_lock_device(&controllers[index])) return ERROR_DEVICE_NOT_CONNECTED; + if (flags & XINPUT_FLAG_GAMEPAD && controllers[index].caps.SubType != XINPUT_DEVSUBTYPE_GAMEPAD) + { + unlock_device(&controllers[index]); + return ERROR_DEVICE_NOT_CONNECTED; + } + memcpy(capabilities, &controllers[index].caps, sizeof(*capabilities)); + unlock_device(&controllers[index]); + return ERROR_SUCCESS; } diff --git a/dlls/xinput1_3/xinput_private.h b/dlls/xinput1_3/xinput_private.h index d6e0e9614ee..74cf318a6fb 100644 --- a/dlls/xinput1_3/xinput_private.h +++ b/dlls/xinput1_3/xinput_private.h @@ -19,16 +19,19 @@ typedef struct _xinput_controller { - BOOL connected; + CRITICAL_SECTION crit; + BOOL connected; /* only TRUE when device is valid; may be used without holding crit */ XINPUT_CAPABILITIES caps; void *platform_private; XINPUT_STATE state; XINPUT_VIBRATION vibration; } xinput_controller; +CRITICAL_SECTION xinput_crit; +xinput_controller controllers[XUSER_MAX_COUNT]; void HID_find_gamepads(xinput_controller *devices) DECLSPEC_HIDDEN; void HID_destroy_gamepads(xinput_controller *devices) DECLSPEC_HIDDEN; -void HID_update_state(xinput_controller* device) 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;