From: Connor McAdams <cmcadams@codeweavers.com> --- dlls/dinput/joystick_hid.c | 136 ++++++++++++---------------------- dlls/dinput/tests/joystick8.c | 2 +- 2 files changed, 47 insertions(+), 91 deletions(-) diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index b475eb64000..64639d3cc6a 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -71,6 +71,7 @@ struct joystick_instance struct list entry; BOOL override; WORD vid, pid; + GUID guid; WCHAR dev_path[MAX_PATH]; }; @@ -101,6 +102,20 @@ static struct joystick_instance *joystick_cache_get_instance_from_index( unsigne return inst; } +static struct joystick_instance *joystick_cache_get_instance_from_guid( const GUID *guid ) +{ + GUID guid_product = dinput_pidvid_guid; + struct joystick_instance *inst = NULL; + + LIST_FOR_EACH_ENTRY( inst, &joystick_cache, struct joystick_instance, entry ) + { + guid_product.Data1 = MAKELONG( inst->vid, inst->pid); + if (IsEqualGUID( &inst->guid, guid ) || IsEqualGUID( &guid_product, guid )) return inst; + } + + return NULL; +} + void hid_joystick_cleanup( void ) { joystick_cache_free(); @@ -1475,13 +1490,12 @@ static HRESULT hid_joystick_device_try_open( const WCHAR *path, HANDLE *device, BOOL has_accelerator, has_brake, has_clutch, has_z, has_pov; PHIDP_PREPARSED_DATA preparsed_data = NULL; HIDP_LINK_COLLECTION_NODE nodes[256]; - DWORD type, size, button_count = 0; + DWORD type, button_count = 0; HIDP_BUTTON_CAPS buttons[10]; HIDP_VALUE_CAPS value; HANDLE device_file; ULONG node_count; NTSTATUS status; - UINT32 handle; USHORT count; device_file = CreateFileW( path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, @@ -1504,14 +1518,7 @@ static HRESULT hid_joystick_device_try_open( const WCHAR *path, HANDLE *device, if (!HidD_GetProductString( device_file, instance->tszInstanceName, MAX_PATH * sizeof(WCHAR) )) goto failed; if (!HidD_GetProductString( device_file, instance->tszProductName, MAX_PATH * sizeof(WCHAR) )) goto failed; - if (!DeviceIoControl( device_file, IOCTL_HID_GET_WINE_RAWINPUT_HANDLE, NULL, 0, &handle, sizeof(handle), &size, NULL )) - { - ERR( "failed to get raw input handle, error %lu\n", GetLastError() ); - goto failed; - } - - instance->guidInstance = hid_joystick_guid; - instance->guidInstance.Data1 ^= handle; + instance->guidInstance = GUID_NULL; instance->guidProduct = dinput_pidvid_guid; instance->guidProduct.Data1 = MAKELONG( attrs->VendorID, attrs->ProductID ); instance->guidFFDriver = GUID_NULL; @@ -1651,7 +1658,7 @@ static HRESULT hid_joystick_get_class_dev_iface_list( const GUID *class, const D return DI_OK; } -static BOOL hid_device_is_valid_joystick( const WCHAR *path, WORD *vid, WORD *pid, BOOL *override ) +static BOOL hid_device_is_valid_joystick( const WCHAR *path, WORD *vid, WORD *pid, BOOL *override, GUID *guid_instance ) { PHIDP_PREPARSED_DATA preparsed = NULL; HIDD_ATTRIBUTES attrs = { 0 }; @@ -1659,6 +1666,8 @@ static BOOL hid_device_is_valid_joystick( const WCHAR *path, WORD *vid, WORD *pi WCHAR product[MAX_PATH]; BOOL ret_val = FALSE; HIDP_CAPS caps; + UINT32 handle; + DWORD size; device_file = CreateFileW( path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, 0 ); @@ -1679,6 +1688,13 @@ static BOOL hid_device_is_valid_joystick( const WCHAR *path, WORD *vid, WORD *pi if (!HidD_GetProductString( device_file, product, sizeof(product) )) goto exit; if (device_instance_is_disabled( product, override )) goto exit; + if (!DeviceIoControl( device_file, IOCTL_HID_GET_WINE_RAWINPUT_HANDLE, NULL, 0, &handle, sizeof(handle), &size, NULL )) + { + ERR( "failed to get raw input handle, error %lu\n", GetLastError() ); + goto exit; + } + *guid_instance = hid_joystick_guid; + guid_instance->Data1 ^= handle; *vid = attrs.VendorID; *pid = attrs.ProductID; ret_val = TRUE; @@ -1713,8 +1729,9 @@ HRESULT hid_joystick_refresh_devices( void ) struct joystick_instance *instance = NULL; BOOL override; WORD vid, pid; + GUID guid; - if (!hid_device_is_valid_joystick( tmp, &vid, &pid, &override )) continue; + if (!hid_device_is_valid_joystick( tmp, &vid, &pid, &override, &guid )) continue; if (!(instance = malloc( sizeof(*instance) ))) { hr = E_OUTOFMEMORY; @@ -1723,6 +1740,7 @@ HRESULT hid_joystick_refresh_devices( void ) instance->vid = vid; instance->pid = pid; instance->override = override; + instance->guid = guid; wcscpy( instance->dev_path, tmp ); /* * SetupAPI returns paths in lowercase, cfgmgr32 does not. joy.cpl @@ -1739,81 +1757,6 @@ exit: return hr; } -static HRESULT hid_joystick_device_open( int index, const GUID *guid, DIDEVICEINSTANCEW *instance, - WCHAR *device_path, HANDLE *device, PHIDP_PREPARSED_DATA *preparsed, - HIDD_ATTRIBUTES *attrs, HIDP_CAPS *caps, DWORD version ) -{ - char buffer[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + MAX_PATH * sizeof(WCHAR)]; - SP_DEVICE_INTERFACE_DETAIL_DATA_W *detail = (void *)buffer; - SP_DEVICE_INTERFACE_DATA iface = {.cbSize = sizeof(iface)}; - SP_DEVINFO_DATA devinfo = {.cbSize = sizeof(devinfo)}; - WCHAR device_id[MAX_PATH], *tmp; - HDEVINFO set, xi_set; - BOOL override; - UINT32 i = 0; - GUID hid; - - TRACE( "index %d, guid %s\n", index, debugstr_guid( guid ) ); - - HidD_GetHidGuid( &hid ); - - set = SetupDiGetClassDevsW( &hid, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT ); - if (set == INVALID_HANDLE_VALUE) return DIERR_DEVICENOTREG; - xi_set = SetupDiGetClassDevsW( &GUID_DEVINTERFACE_WINEXINPUT, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT ); - - *device = NULL; - *preparsed = NULL; - while (SetupDiEnumDeviceInterfaces( set, NULL, &hid, i++, &iface )) - { - detail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W); - if (!SetupDiGetDeviceInterfaceDetailW( set, &iface, detail, sizeof(buffer), NULL, &devinfo )) - continue; - if (FAILED(hid_joystick_device_try_open( detail->DevicePath, device, preparsed, - attrs, caps, instance, version ))) - continue; - - if (device_instance_is_disabled( instance->tszInstanceName, &override )) - goto next; - - if (override && SetupDiGetDeviceInstanceIdW( set, &devinfo, device_id, MAX_PATH, NULL ) && - (tmp = wcsstr( device_id, L"&IG_" ))) - { - memcpy( tmp, L"&XI_", sizeof(L"&XI_") - sizeof(WCHAR) ); - if (!SetupDiOpenDeviceInfoW( xi_set, device_id, NULL, 0, &devinfo )) - goto next; - if (!SetupDiEnumDeviceInterfaces( xi_set, &devinfo, &GUID_DEVINTERFACE_WINEXINPUT, 0, &iface )) - goto next; - if (!SetupDiGetDeviceInterfaceDetailW( xi_set, &iface, detail, sizeof(buffer), NULL, &devinfo )) - goto next; - - CloseHandle( *device ); - HidD_FreePreparsedData( *preparsed ); - if (FAILED(hid_joystick_device_try_open( detail->DevicePath, device, preparsed, - attrs, caps, instance, version ))) - continue; - } - - /* enumerate device by GUID */ - if (IsEqualGUID( guid, &instance->guidProduct ) || IsEqualGUID( guid, &instance->guidInstance )) break; - - /* enumerate all devices */ - if (index >= 0 && !index--) break; - - next: - CloseHandle( *device ); - HidD_FreePreparsedData( *preparsed ); - *device = NULL; - *preparsed = NULL; - } - - if (xi_set != INVALID_HANDLE_VALUE) SetupDiDestroyDeviceInfoList( xi_set ); - SetupDiDestroyDeviceInfoList( set ); - if (!*device || !*preparsed) return DIERR_DEVICENOTREG; - - lstrcpynW( device_path, detail->DevicePath, MAX_PATH ); - return DI_OK; -} - static HRESULT hid_joystick_instance_try_open( struct joystick_instance *instance, HANDLE *device, PHIDP_PREPARSED_DATA *preparsed, HIDD_ATTRIBUTES *attrs, HIDP_CAPS *caps, DIDEVICEINSTANCEW *di_instance, WCHAR *device_path, DWORD version ) @@ -1844,7 +1787,11 @@ static HRESULT hid_joystick_instance_try_open( struct joystick_instance *instanc } hr = hid_joystick_device_try_open( path, device, preparsed, attrs, caps, di_instance, version ); - if (SUCCEEDED(hr)) wcscpy( device_path, path ); + if (SUCCEEDED(hr)) + { + wcscpy( device_path, path ); + di_instance->guidInstance = instance->guid; + } if (path != instance->dev_path) free( path ); return hr; } @@ -2248,8 +2195,17 @@ HRESULT hid_joystick_create_device( struct dinput *dinput, const GUID *guid, IDi impl->base.read_event = CreateEventW( NULL, TRUE, FALSE, NULL ); if (memcmp( device_path_guid.Data4, guid->Data4, sizeof(device_path_guid.Data4) )) - hr = hid_joystick_device_open( -1, guid, &impl->base.instance, impl->device_path, &impl->device, &impl->preparsed, - &attrs, &impl->caps, dinput->dwVersion ); + { + struct joystick_instance *inst; + + EnterCriticalSection( &joystick_cache_cs ); + if ((inst = joystick_cache_get_instance_from_guid( guid ))) + hr = hid_joystick_instance_try_open( inst, &impl->device, &impl->preparsed, &attrs, &impl->caps, + &impl->base.instance, impl->device_path, dinput->dwVersion ); + else + hr = DIERR_DEVICENOTREG; + LeaveCriticalSection( &joystick_cache_cs ); + } else { wcscpy( impl->device_path, *(const WCHAR **)guid ); diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index 5b2ca8fe66d..cafc43d8b72 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -6161,7 +6161,7 @@ static void test_joystick_instance_guid( DWORD version ) ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr ); hr = dinput_create_device( &di2, &expect_instances[0], &device ); - if (version == 0x800) todo_wine ok( hr == DIERR_DEVICENOTREG, "Unexpected hr %#lx.\n", hr ); + if (version == 0x800) ok( hr == DIERR_DEVICENOTREG, "Unexpected hr %#lx.\n", hr ); else ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr ); if (SUCCEEDED(hr)) { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10364