From: Connor McAdams <cmcadams@codeweavers.com> --- dlls/dinput/Makefile.in | 2 +- dlls/dinput/joystick_hid.c | 80 +++++++++++++++++++++++++++++++++----- dlls/dinput8/Makefile.in | 2 +- 3 files changed, 72 insertions(+), 12 deletions(-) diff --git a/dlls/dinput/Makefile.in b/dlls/dinput/Makefile.in index 70aa575a837..883639195ba 100644 --- a/dlls/dinput/Makefile.in +++ b/dlls/dinput/Makefile.in @@ -1,6 +1,6 @@ MODULE = dinput.dll IMPORTLIB = dinput -IMPORTS = dinput dxguid uuid comctl32 ole32 user32 advapi32 hid setupapi +IMPORTS = dinput dxguid uuid comctl32 ole32 user32 advapi32 hid setupapi cfgmgr32 EXTRADEFS = -DDIRECTINPUT_VERSION=0x0700 VER_FILEDESCRIPTION_STR = "Wine DirectInput" diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index 8c6a752c020..b475eb64000 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -42,6 +42,8 @@ #include "device_private.h" #include "initguid.h" +#include "devpkey.h" +#include "propkey.h" #include "wine/debug.h" #include "wine/hid.h" @@ -67,6 +69,7 @@ static struct list joystick_cache = LIST_INIT(joystick_cache); struct joystick_instance { struct list entry; + BOOL override; WORD vid, pid; WCHAR dev_path[MAX_PATH]; @@ -83,6 +86,21 @@ static void joystick_cache_free( void ) } } +static struct joystick_instance *joystick_cache_get_instance_from_index( unsigned int index ) +{ + struct joystick_instance *inst = NULL; + unsigned int i = 0; + + if (index >= list_count( &joystick_cache )) return NULL; + + LIST_FOR_EACH_ENTRY( inst, &joystick_cache, struct joystick_instance, entry ) + { + if (index == i++) break; + } + + return inst; +} + void hid_joystick_cleanup( void ) { joystick_cache_free(); @@ -1608,7 +1626,7 @@ failed: return DIERR_DEVICENOTREG; } -static HRESULT hid_joystick_get_class_dev_iface_list( const GUID *class, WCHAR **list ) +static HRESULT hid_joystick_get_class_dev_iface_list( const GUID *class, const DEVINSTID_W instance_id, WCHAR **list ) { WCHAR *ifaces = NULL; GUID guid = *class; @@ -1618,12 +1636,12 @@ static HRESULT hid_joystick_get_class_dev_iface_list( const GUID *class, WCHAR * *list = NULL; while (1) { - if ((ret = CM_Get_Device_Interface_List_SizeW( &size, &guid, NULL, CM_GET_DEVICE_INTERFACE_LIST_PRESENT ))) + if ((ret = CM_Get_Device_Interface_List_SizeW( &size, &guid, instance_id, CM_GET_DEVICE_INTERFACE_LIST_PRESENT ))) WARN( "Got unexpected return value %lu.\n", ret ); if (ret || size == 1) return DIERR_DEVICENOTREG; if (!(ifaces = calloc( size, sizeof(*ifaces) ))) return E_OUTOFMEMORY; - if (!(ret = CM_Get_Device_Interface_ListW( &guid, NULL, ifaces, size, CM_GET_DEVICE_INTERFACE_LIST_PRESENT ))) + if (!(ret = CM_Get_Device_Interface_ListW( &guid, instance_id, ifaces, size, CM_GET_DEVICE_INTERFACE_LIST_PRESENT ))) break; free( ifaces ); if (ret != CR_BUFFER_SMALL) return E_FAIL; @@ -1633,7 +1651,7 @@ static HRESULT hid_joystick_get_class_dev_iface_list( const GUID *class, WCHAR * return DI_OK; } -static BOOL hid_device_is_valid_joystick( const WCHAR *path, WORD *vid, WORD *pid ) +static BOOL hid_device_is_valid_joystick( const WCHAR *path, WORD *vid, WORD *pid, BOOL *override ) { PHIDP_PREPARSED_DATA preparsed = NULL; HIDD_ATTRIBUTES attrs = { 0 }; @@ -1660,7 +1678,7 @@ 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, NULL )) goto exit; + if (device_instance_is_disabled( product, override )) goto exit; *vid = attrs.VendorID; *pid = attrs.ProductID; ret_val = TRUE; @@ -1681,7 +1699,7 @@ HRESULT hid_joystick_refresh_devices( void ) hid_list = NULL; HidD_GetHidGuid( &hid ); - hr = hid_joystick_get_class_dev_iface_list( &hid, &hid_list ); + hr = hid_joystick_get_class_dev_iface_list( &hid, NULL, &hid_list ); if (FAILED(hr)) return hr; /* @@ -1693,9 +1711,10 @@ HRESULT hid_joystick_refresh_devices( void ) for (tmp = hid_list; *tmp; tmp = tmp + wcslen( tmp ) + 1) { struct joystick_instance *instance = NULL; + BOOL override; WORD vid, pid; - if (!hid_device_is_valid_joystick( tmp, &vid, &pid )) continue; + if (!hid_device_is_valid_joystick( tmp, &vid, &pid, &override )) continue; if (!(instance = malloc( sizeof(*instance) ))) { hr = E_OUTOFMEMORY; @@ -1703,6 +1722,7 @@ HRESULT hid_joystick_refresh_devices( void ) } instance->vid = vid; instance->pid = pid; + instance->override = override; wcscpy( instance->dev_path, tmp ); /* * SetupAPI returns paths in lowercase, cfgmgr32 does not. joy.cpl @@ -1794,20 +1814,60 @@ static HRESULT hid_joystick_device_open( int index, const GUID *guid, DIDEVICEIN 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 ) +{ + WCHAR *path = instance->dev_path; + HRESULT hr; + + if (instance->override) + { + WCHAR instance_id[MAX_DEVICE_ID_LEN] = { 0 }; + DEVPROPTYPE type; + CONFIGRET ret; + WCHAR *tmp; + ULONG size; + + size = sizeof(instance_id); + ret = CM_Get_Device_Interface_PropertyW( instance->dev_path, &DEVPKEY_Device_InstanceId, &type, + (BYTE *)instance_id, &size, 0 ); + if (ret || !(tmp = wcsstr( instance_id, L"&IG_" ))) + { + WARN( "Failed to get valid instance id for overridden device.\n" ); + return E_FAIL; + } + + memcpy( tmp, L"&XI_", sizeof(L"&XI_") - sizeof(WCHAR) ); + if (FAILED(hid_joystick_get_class_dev_iface_list( &GUID_DEVINTERFACE_WINEXINPUT, instance_id, &path ))) + return E_FAIL; + } + + hr = hid_joystick_device_try_open( path, device, preparsed, attrs, caps, di_instance, version ); + if (SUCCEEDED(hr)) wcscpy( device_path, path ); + if (path != instance->dev_path) free( path ); + return hr; +} + + HRESULT hid_joystick_enum_device( DWORD type, DWORD flags, DIDEVICEINSTANCEW *instance, DWORD version, int index ) { HIDD_ATTRIBUTES attrs = {.Size = sizeof(attrs)}; PHIDP_PREPARSED_DATA preparsed; + struct joystick_instance *inst; WCHAR device_path[MAX_PATH]; - GUID guid = GUID_NULL; HIDP_CAPS caps; HANDLE device; HRESULT hr; TRACE( "type %#lx, flags %#lx, instance %p, version %#lx, index %d\n", type, flags, instance, version, index ); - hr = hid_joystick_device_open( index, &guid, instance, device_path, &device, &preparsed, - &attrs, &caps, version ); + EnterCriticalSection( &joystick_cache_cs ); + if ((inst = joystick_cache_get_instance_from_index( index ))) + hr = hid_joystick_instance_try_open( inst, &device, &preparsed, &attrs, &caps, instance, device_path, version ); + else + hr = DIERR_DEVICENOTREG; + LeaveCriticalSection( &joystick_cache_cs ); if (hr != DI_OK) return hr; HidD_FreePreparsedData( preparsed ); diff --git a/dlls/dinput8/Makefile.in b/dlls/dinput8/Makefile.in index 1b288a1dce2..bdb50f9fa05 100644 --- a/dlls/dinput8/Makefile.in +++ b/dlls/dinput8/Makefile.in @@ -1,6 +1,6 @@ MODULE = dinput8.dll IMPORTLIB = dinput8 -IMPORTS = dinput8 dxguid uuid comctl32 ole32 user32 advapi32 hid setupapi +IMPORTS = dinput8 dxguid uuid comctl32 ole32 user32 advapi32 hid setupapi cfgmgr32 EXTRADEFS = -DDIRECTINPUT_VERSION=0x0800 PARENTSRC = ../dinput -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10364