[PATCH v2 0/9] MR10719: dinput: Save and load HID joystick instance GUIDs to the registry.
Supersedes https://gitlab.winehq.org/wine/wine/-/merge_requests/10364 -- v2: dinput: Create a version 1 UUID for dinput joystick devices. dinput: Save and load HID joystick instance GUIDs to the registry. dinput: Return E_FAIL when opening a joystick device that is currently disconnected. dinput: Use joystick cache in hid_joystick_enum_device(). dinput: Use joystick cache in hid_joystick_create_device(). dinput: Create a cache of currently connected HID joysticks. dinput: Handle device override directly in hid_joystick_device_try_open. dinput: Check for disabled/overriden devices in hid_joystick_try_open. dinput: Only pass instance name string to device_instance_is_disabled(). https://gitlab.winehq.org/wine/wine/-/merge_requests/10719
From: Connor McAdams <cmcadams@codeweavers.com> Signed-off-by: Connor McAdams <cmcadams@codeweavers.com> --- dlls/dinput/device.c | 16 +++++++--------- dlls/dinput/device_private.h | 2 +- dlls/dinput/joystick_hid.c | 2 +- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index 35518dd91dd..142a9908b29 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -145,11 +145,9 @@ DWORD get_config_key( HKEY defkey, HKEY appkey, const WCHAR *name, WCHAR *buffer return ERROR_FILE_NOT_FOUND; } -BOOL device_instance_is_disabled( DIDEVICEINSTANCEW *instance, BOOL *override ) +BOOL device_instance_is_disabled( const WCHAR *instance, BOOL *override ) { - static const WCHAR disabled_str[] = {'d', 'i', 's', 'a', 'b', 'l', 'e', 'd', 0}; - static const WCHAR override_str[] = {'o', 'v', 'e', 'r', 'r', 'i', 'd', 'e', 0}; - static const WCHAR joystick_key[] = {'J', 'o', 'y', 's', 't', 'i', 'c', 'k', 's', 0}; + static const WCHAR *joystick_key = L"Joysticks"; WCHAR buffer[MAX_PATH]; HKEY hkey, appkey, temp; BOOL disable = FALSE; @@ -173,16 +171,16 @@ BOOL device_instance_is_disabled( DIDEVICEINSTANCEW *instance, BOOL *override ) } /* Look for the "controllername"="disabled" key */ - if (!get_config_key( hkey, appkey, instance->tszInstanceName, buffer, sizeof(buffer) )) + if (!get_config_key( hkey, appkey, instance, buffer, sizeof(buffer) )) { - if (!wcscmp( disabled_str, buffer )) + if (!wcscmp( L"disabled", buffer )) { - TRACE( "Disabling joystick '%s' based on registry key.\n", debugstr_w(instance->tszInstanceName) ); + TRACE( "Disabling joystick '%s' based on registry key.\n", debugstr_w(instance) ); disable = TRUE; } - else if (override && !wcscmp( override_str, buffer )) + else if (override && !wcscmp( L"override", buffer )) { - TRACE( "Force enabling joystick '%s' based on registry key.\n", debugstr_w(instance->tszInstanceName) ); + TRACE( "Force enabling joystick '%s' based on registry key.\n", debugstr_w(instance) ); *override = TRUE; } } diff --git a/dlls/dinput/device_private.h b/dlls/dinput/device_private.h index fa791f08a9d..fcab99779c5 100644 --- a/dlls/dinput/device_private.h +++ b/dlls/dinput/device_private.h @@ -134,7 +134,7 @@ extern BOOL device_object_matches_semantic( const DIDEVICEINSTANCEW *instance, c extern BOOL get_app_key(HKEY*, HKEY*); extern DWORD get_config_key( HKEY, HKEY, const WCHAR *, WCHAR *, DWORD ); -extern BOOL device_instance_is_disabled( DIDEVICEINSTANCEW *instance, BOOL *override ); +extern BOOL device_instance_is_disabled( const WCHAR *instance, BOOL *override ); extern void queue_event( IDirectInputDevice8W *iface, int index, DWORD data, DWORD time, DWORD seq ); extern const GUID dinput_pidvid_guid; diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index 22709c4bfd9..c2954553805 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -1605,7 +1605,7 @@ static HRESULT hid_joystick_device_open( int index, const GUID *guid, DIDEVICEIN attrs, caps, instance, version ))) continue; - if (device_instance_is_disabled( instance, &override )) + if (device_instance_is_disabled( instance->tszInstanceName, &override )) goto next; if (override && SetupDiGetDeviceInstanceIdW( set, &devinfo, device_id, MAX_PATH, NULL ) && -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10719
From: Rémi Bernon <rbernon@codeweavers.com> Based on patches by Connor McAdams. --- dlls/dinput/joystick_hid.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index c2954553805..9a41ba19876 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -1428,6 +1428,7 @@ static HRESULT hid_joystick_device_try_open( const WCHAR *path, HANDLE *device, ULONG node_count; NTSTATUS status; UINT32 handle; + BOOL override; USHORT count; device_file = CreateFileW( path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, @@ -1450,6 +1451,8 @@ 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 (device_instance_is_disabled( instance->tszInstanceName, &override )) 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() ); @@ -1564,7 +1567,7 @@ static HRESULT hid_joystick_device_try_open( const WCHAR *path, HANDLE *device, *device = device_file; *preparsed = preparsed_data; - return DI_OK; + return override ? S_FALSE : DI_OK; failed: CloseHandle( device_file ); @@ -1582,8 +1585,8 @@ static HRESULT hid_joystick_device_open( int index, const GUID *guid, DIDEVICEIN SP_DEVINFO_DATA devinfo = {.cbSize = sizeof(devinfo)}; WCHAR device_id[MAX_PATH], *tmp; HDEVINFO set, xi_set; - BOOL override; UINT32 i = 0; + HRESULT hr; GUID hid; TRACE( "index %d, guid %s\n", index, debugstr_guid( guid ) ); @@ -1601,14 +1604,11 @@ static HRESULT hid_joystick_device_open( int index, const GUID *guid, DIDEVICEIN 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 ))) + if (FAILED(hr = 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 ) && + if (hr == S_FALSE && SetupDiGetDeviceInstanceIdW( set, &devinfo, device_id, MAX_PATH, NULL ) && (tmp = wcsstr( device_id, L"&IG_" ))) { memcpy( tmp, L"&XI_", sizeof(L"&XI_") - sizeof(WCHAR) ); @@ -2048,6 +2048,7 @@ HRESULT hid_joystick_create_device( struct dinput *dinput, const GUID *guid, IDi wcscpy( impl->device_path, *(const WCHAR **)guid ); hr = hid_joystick_device_try_open( impl->device_path, &impl->device, &impl->preparsed, &attrs, &impl->caps, &impl->base.instance, dinput->dwVersion ); + if (hr == S_FALSE) hr = S_OK; } if (hr != DI_OK) goto failed; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10719
From: Rémi Bernon <rbernon@codeweavers.com> Based on patches by Connor McAdams. --- dlls/dinput/Makefile.in | 2 +- dlls/dinput/joystick_hid.c | 79 ++++++++++++++++++++++++-------------- dlls/dinput8/Makefile.in | 2 +- 3 files changed, 53 insertions(+), 30 deletions(-) diff --git a/dlls/dinput/Makefile.in b/dlls/dinput/Makefile.in index 70aa575a837..f89ff8e8637 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 cfgmgr32 dxguid uuid comctl32 ole32 user32 advapi32 hid setupapi EXTRADEFS = -DDIRECTINPUT_VERSION=0x0700 VER_FILEDESCRIPTION_STR = "Wine DirectInput" diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index 9a41ba19876..f217e5f3e21 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -33,7 +33,7 @@ #include "ddk/hidclass.h" #include "ddk/hidsdi.h" -#include "setupapi.h" +#include "cfgmgr32.h" #include "devguid.h" #include "dinput.h" #include "setupapi.h" @@ -42,6 +42,7 @@ #include "device_private.h" #include "initguid.h" +#include "devpkey.h" #include "wine/debug.h" #include "wine/hid.h" @@ -1414,7 +1415,39 @@ static DWORD device_type_for_version( DWORD type, DWORD version ) } } -static HRESULT hid_joystick_device_try_open( const WCHAR *path, HANDLE *device, PHIDP_PREPARSED_DATA *preparsed, +static HRESULT get_device_interfaces( GUID class, DEVINSTID_W instance, WCHAR **paths ) +{ + for (;;) + { + ULONG size, flags = CM_GET_DEVICE_INTERFACE_LIST_PRESENT; + CONFIGRET ret; + + if (CM_Get_Device_Interface_List_SizeW( &size, &class, instance, flags )) return DIERR_DEVICENOTREG; + if (!(*paths = malloc( size * sizeof(**paths) ))) return E_OUTOFMEMORY; + if (!(ret = CM_Get_Device_Interface_ListW( &class, instance, *paths, size, flags ))) return DI_OK; + free( *paths ); + *paths = NULL; + if (ret != CR_BUFFER_SMALL) return DIERR_DEVICENOTREG; + } +} + +static HRESULT get_winexinput_interfaces( const WCHAR *hid_path, WCHAR **paths ) +{ + WCHAR instance_id[MAX_DEVICE_ID_LEN]; + ULONG size = sizeof(instance_id); + DEVPROPTYPE type; + WCHAR *tmp; + + if (CM_Get_Device_Interface_PropertyW( hid_path, &DEVPKEY_Device_InstanceId, &type, (BYTE *)instance_id, &size, 0 )) return DIERR_DEVICENOTREG; + CharUpperW( instance_id ); + + if (!(tmp = wcsstr( instance_id, L"&IG_" ))) return DIERR_DEVICENOTREG; + memcpy( tmp, L"&XI_", sizeof(L"&XI_") - sizeof(WCHAR) ); + + return get_device_interfaces( GUID_DEVINTERFACE_WINEXINPUT, instance_id, paths ); +} + +static HRESULT hid_joystick_device_try_open( WCHAR *path, HANDLE *device, PHIDP_PREPARSED_DATA *preparsed, HIDD_ATTRIBUTES *attrs, HIDP_CAPS *caps, DIDEVICEINSTANCEW *instance, DWORD version ) { @@ -1423,12 +1456,13 @@ static HRESULT hid_joystick_device_try_open( const WCHAR *path, HANDLE *device, HIDP_LINK_COLLECTION_NODE nodes[256]; DWORD type, size, button_count = 0; HIDP_BUTTON_CAPS buttons[10]; + WCHAR *override_paths; HIDP_VALUE_CAPS value; HANDLE device_file; ULONG node_count; NTSTATUS status; - UINT32 handle; BOOL override; + UINT32 handle; USHORT count; device_file = CreateFileW( path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, @@ -1452,6 +1486,17 @@ static HRESULT hid_joystick_device_try_open( const WCHAR *path, HANDLE *device, if (!HidD_GetProductString( device_file, instance->tszProductName, MAX_PATH * sizeof(WCHAR) )) goto failed; if (device_instance_is_disabled( instance->tszInstanceName, &override )) goto failed; + if (override && !wcsstr( path, L"&XI_" ) && SUCCEEDED(get_winexinput_interfaces( path, &override_paths ))) + { + HidD_FreePreparsedData( preparsed_data ); + CloseHandle( device_file ); + + TRACE( "Overriding %s device path with %s\n", debugstr_w(path), debugstr_w(override_paths) ); + wcscpy( path, override_paths ); + free( override_paths ); + + return hid_joystick_device_try_open( path, device, preparsed, attrs, caps, instance, version ); + } if (!DeviceIoControl( device_file, IOCTL_HID_GET_WINE_RAWINPUT_HANDLE, NULL, 0, &handle, sizeof(handle), &size, NULL )) { @@ -1567,7 +1612,7 @@ static HRESULT hid_joystick_device_try_open( const WCHAR *path, HANDLE *device, *device = device_file; *preparsed = preparsed_data; - return override ? S_FALSE : DI_OK; + return DI_OK; failed: CloseHandle( device_file ); @@ -1583,10 +1628,8 @@ static HRESULT hid_joystick_device_open( int index, const GUID *guid, DIDEVICEIN 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; UINT32 i = 0; - HRESULT hr; GUID hid; TRACE( "index %d, guid %s\n", index, debugstr_guid( guid ) ); @@ -1604,35 +1647,16 @@ static HRESULT hid_joystick_device_open( int index, const GUID *guid, DIDEVICEIN detail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W); if (!SetupDiGetDeviceInterfaceDetailW( set, &iface, detail, sizeof(buffer), NULL, &devinfo )) continue; - if (FAILED(hr = hid_joystick_device_try_open( detail->DevicePath, device, preparsed, - attrs, caps, instance, version ))) + if (FAILED(hid_joystick_device_try_open( detail->DevicePath, device, preparsed, + attrs, caps, instance, version ))) continue; - if (hr == S_FALSE && 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; @@ -2048,7 +2072,6 @@ HRESULT hid_joystick_create_device( struct dinput *dinput, const GUID *guid, IDi wcscpy( impl->device_path, *(const WCHAR **)guid ); hr = hid_joystick_device_try_open( impl->device_path, &impl->device, &impl->preparsed, &attrs, &impl->caps, &impl->base.instance, dinput->dwVersion ); - if (hr == S_FALSE) hr = S_OK; } if (hr != DI_OK) goto failed; diff --git a/dlls/dinput8/Makefile.in b/dlls/dinput8/Makefile.in index 1b288a1dce2..ebc77fa8c87 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 cfgmgr32 dxguid uuid comctl32 ole32 user32 advapi32 hid setupapi EXTRADEFS = -DDIRECTINPUT_VERSION=0x0800 PARENTSRC = ../dinput -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10719
From: Connor McAdams <cmcadams@codeweavers.com> --- dlls/dinput/dinput.c | 12 +++-- dlls/dinput/dinput_main.c | 1 + dlls/dinput/dinput_private.h | 2 + dlls/dinput/joystick_hid.c | 99 ++++++++++++++++++++++++++++++++++++ 4 files changed, 111 insertions(+), 3 deletions(-) diff --git a/dlls/dinput/dinput.c b/dlls/dinput/dinput.c index f851e17a244..f3161ca92f3 100644 --- a/dlls/dinput/dinput.c +++ b/dlls/dinput/dinput.c @@ -282,7 +282,12 @@ static HRESULT WINAPI dinput7_CreateDeviceEx( IDirectInput7W *iface, const GUID if (IsEqualGUID( &GUID_SysKeyboard, guid )) hr = keyboard_create_device( impl, guid, &device ); else if (IsEqualGUID( &GUID_SysMouse, guid )) hr = mouse_create_device( impl, guid, &device ); - else hr = hid_joystick_create_device( impl, guid, &device ); + else + { + hr = hid_joystick_create_device( impl, guid, &device ); + if (hr == DIERR_DEVICENOTREG && SUCCEEDED(hr = hid_joystick_refresh_devices())) + hr = hid_joystick_create_device( impl, guid, &device ); + } if (FAILED(hr)) return hr; @@ -372,12 +377,13 @@ static HRESULT WINAPI dinput8_EnumDevices( IDirectInput8W *iface, DWORD type, LP if (device_class == DI8DEVCLASS_ALL || device_class == DI8DEVCLASS_GAMECTRL) { - do + hr = hid_joystick_refresh_devices(); + while (SUCCEEDED(hr)) { hr = hid_joystick_enum_device( type, flags, &instance, impl->dwVersion, i++ ); if (hr == DI_OK && try_enum_device( device_type, callback, &instance, context, flags ) == DIENUM_STOP) return DI_OK; - } while (SUCCEEDED(hr)); + } } return DI_OK; diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index e4bc1f7961d..0c8bcad149c 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -522,6 +522,7 @@ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, void *reserved ) break; case DLL_PROCESS_DETACH: if (reserved) break; + hid_joystick_cleanup_devices(); unregister_di_em_win_class(); break; } diff --git a/dlls/dinput/dinput_private.h b/dlls/dinput/dinput_private.h index 0609b816b3b..0b0caebfaf1 100644 --- a/dlls/dinput/dinput_private.h +++ b/dlls/dinput/dinput_private.h @@ -56,6 +56,8 @@ extern HRESULT keyboard_enum_device( DWORD type, DWORD flags, DIDEVICEINSTANCEW extern HRESULT keyboard_create_device( struct dinput *dinput, const GUID *guid, IDirectInputDevice8W **out ); extern HRESULT hid_joystick_enum_device( DWORD type, DWORD flags, DIDEVICEINSTANCEW *instance, DWORD version, int index ); extern HRESULT hid_joystick_create_device( struct dinput *dinput, const GUID *guid, IDirectInputDevice8W **out ); +extern HRESULT hid_joystick_refresh_devices(void); +extern void hid_joystick_cleanup_devices(void); struct DevicePlayer { GUID instance_guid; diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index f217e5f3e21..19b15bf471b 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -53,6 +53,72 @@ DEFINE_GUID( GUID_DEVINTERFACE_WINEXINPUT,0x6c53d5fd,0x6480,0x440f,0xb6,0x18,0x4 DEFINE_GUID( hid_joystick_guid, 0x9e573edb, 0x7734, 0x11d2, 0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7 ); DEFINE_GUID( device_path_guid, 0x00000000, 0x0000, 0x0000, 0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf8 ); +static CRITICAL_SECTION joystick_cache_cs; +static CRITICAL_SECTION_DEBUG joystick_cache_cs_debug = +{ + 0, 0, &joystick_cache_cs, + { &joystick_cache_cs_debug.ProcessLocksList, &joystick_cache_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": joystick_cache_cs") } +}; +static CRITICAL_SECTION joystick_cache_cs = { &joystick_cache_cs_debug, -1, 0, 0, 0, 0 }; + +static struct list joystick_cache = LIST_INIT( joystick_cache ); + +struct cache_entry +{ + struct list entry; + DIDEVICEINSTANCEW instance; + WCHAR path[MAX_PATH]; +}; + +static const char *debugstr_device_instance( const DIDEVICEINSTANCEW *instance ) +{ + return wine_dbg_sprintf( "product: %04x:%04x, instance: %s", LOWORD(instance->guidProduct.Data1), + HIWORD(instance->guidProduct.Data1), debugstr_guid( &instance->guidInstance ) ); +} + +static HRESULT cache_entry_create( const DIDEVICEINSTANCEW *instance, const WCHAR *path, struct cache_entry **out ) +{ + struct cache_entry *entry; + + if (!(entry = calloc( 1, sizeof(*entry) ))) return E_OUTOFMEMORY; + entry->instance = *instance; + wcscpy( entry->path, path ); + CharLowerW( entry->path ); + + *out = entry; + return S_OK; +} + +static HRESULT insert_cache_entry( DIDEVICEINSTANCEW *instance, const WCHAR *path ) +{ + struct cache_entry *entry, *next; + HRESULT hr; + +#define SWAP(x) MAKELONG( HIWORD(x), LOWORD(x) ) + LIST_FOR_EACH_ENTRY( next, &joystick_cache, struct cache_entry, entry ) + if (SWAP( next->instance.guidProduct.Data1 ) > SWAP( instance->guidProduct.Data1 )) break; +#undef SWAP + + if (FAILED(hr = cache_entry_create( instance, path, &entry ))) return hr; + TRACE( "Created instance %s, path %s\n", debugstr_device_instance( instance ), debugstr_w( path ) ); + list_add_before( &next->entry, &entry->entry ); + + return S_OK; +} + +void hid_joystick_cleanup_devices(void) +{ + struct list *ptr; + + while ((ptr = list_head( &joystick_cache ))) + { + struct cache_entry *entry = LIST_ENTRY( ptr, struct cache_entry, entry ); + list_remove( &entry->entry ); + free( entry ); + } +} + struct pid_control_report { BYTE id; @@ -1620,6 +1686,39 @@ failed: return DIERR_DEVICENOTREG; } +HRESULT hid_joystick_refresh_devices(void) +{ + WCHAR *paths = NULL; + HANDLE device; + HRESULT hr; + GUID hid; + + TRACE( "\n" ); + + HidD_GetHidGuid( &hid ); + + EnterCriticalSection( &joystick_cache_cs ); + hid_joystick_cleanup_devices(); + + hr = get_device_interfaces( hid, NULL, &paths ); + for (WCHAR *path = paths; SUCCEEDED(hr) && *path; path = path + wcslen( path ) + 1) + { + DIDEVICEINSTANCEW instance = {.dwSize = sizeof(instance)}; + HIDD_ATTRIBUTES attrs = {.Size = sizeof(attrs)}; + PHIDP_PREPARSED_DATA preparsed; + HIDP_CAPS caps; + + if (FAILED(hid_joystick_device_try_open( path, &device, &preparsed, &attrs, &caps, &instance, 0x0800 ))) continue; + hr = insert_cache_entry( &instance, path ); + HidD_FreePreparsedData( preparsed ); + CloseHandle( device ); + } + free( paths ); + + LeaveCriticalSection( &joystick_cache_cs ); + 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 ) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10719
From: Connor McAdams <cmcadams@codeweavers.com> --- dlls/dinput/joystick_hid.c | 47 ++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index 19b15bf471b..db65404755a 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -107,6 +107,37 @@ static HRESULT insert_cache_entry( DIDEVICEINSTANCEW *instance, const WCHAR *pat return S_OK; } +static HRESULT get_instance_from_guid( const GUID *guid, DIDEVICEINSTANCEW *instance, WCHAR *path ) +{ + struct cache_entry *entry; + HRESULT hr = DI_OK; + + if (!memcmp( device_path_guid.Data4, guid->Data4, sizeof(device_path_guid.Data4) )) + { + wcscpy( path, *(const WCHAR **)guid ); + return S_OK; + } + + EnterCriticalSection( &joystick_cache_cs ); + + LIST_FOR_EACH_ENTRY( entry, &joystick_cache, struct cache_entry, entry ) + { + if (IsEqualGUID( &entry->instance.guidProduct, guid )) break; + if (IsEqualGUID( &entry->instance.guidInstance, guid )) break; + } + if (&entry->entry == &joystick_cache) hr = DIERR_DEVICENOTREG; + else + { + *instance = entry->instance; + wcscpy( path, entry->path ); + } + + LeaveCriticalSection( &joystick_cache_cs ); + + if (FAILED(hr)) WARN( "guid %s not found\n", debugstr_guid(guid) ); + return hr; +} + void hid_joystick_cleanup_devices(void) { struct list *ptr; @@ -2146,8 +2177,10 @@ HRESULT hid_joystick_create_device( struct dinput *dinput, const GUID *guid, IDi .dwHow = DIPH_DEVICE, }, }; + DIDEVICEINSTANCEW instance = {.dwSize = sizeof(instance)}; HIDD_ATTRIBUTES attrs = {.Size = sizeof(attrs)}; struct hid_joystick *impl = NULL; + WCHAR device_path[MAX_PATH]; USAGE_AND_PAGE *usages; char *buffer; HRESULT hr; @@ -2157,21 +2190,17 @@ HRESULT hid_joystick_create_device( struct dinput *dinput, const GUID *guid, IDi *out = NULL; + if (FAILED(hr = get_instance_from_guid( guid, &instance, device_path ))) return hr; + if (!(impl = calloc( 1, sizeof(*impl) ))) return E_OUTOFMEMORY; dinput_device_init( &impl->base, &hid_joystick_vtbl, guid, dinput ); impl->base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": hid_joystick.base.crit"); impl->base.dwCoopLevel = DISCL_NONEXCLUSIVE | DISCL_BACKGROUND; impl->base.read_event = CreateEventW( NULL, TRUE, FALSE, NULL ); + wcscpy( impl->device_path, device_path ); - 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 ); - else - { - wcscpy( impl->device_path, *(const WCHAR **)guid ); - hr = hid_joystick_device_try_open( impl->device_path, &impl->device, &impl->preparsed, &attrs, - &impl->caps, &impl->base.instance, dinput->dwVersion ); - } + hr = hid_joystick_device_try_open( impl->device_path, &impl->device, &impl->preparsed, &attrs, + &impl->caps, &impl->base.instance, dinput->dwVersion ); if (hr != DI_OK) goto failed; impl->base.caps.dwDevType = impl->base.instance.dwDevType; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10719
From: Connor McAdams <cmcadams@codeweavers.com> --- dlls/dinput/Makefile.in | 2 +- dlls/dinput/joystick_hid.c | 83 +++++++------------------------------- dlls/dinput8/Makefile.in | 2 +- 3 files changed, 16 insertions(+), 71 deletions(-) diff --git a/dlls/dinput/Makefile.in b/dlls/dinput/Makefile.in index f89ff8e8637..fea1a99696f 100644 --- a/dlls/dinput/Makefile.in +++ b/dlls/dinput/Makefile.in @@ -1,6 +1,6 @@ MODULE = dinput.dll IMPORTLIB = dinput -IMPORTS = dinput cfgmgr32 dxguid uuid comctl32 ole32 user32 advapi32 hid setupapi +IMPORTS = dinput cfgmgr32 dxguid uuid comctl32 ole32 user32 advapi32 hid EXTRADEFS = -DDIRECTINPUT_VERSION=0x0700 VER_FILEDESCRIPTION_STR = "Wine DirectInput" diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index db65404755a..09312f65544 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -36,7 +36,6 @@ #include "cfgmgr32.h" #include "devguid.h" #include "dinput.h" -#include "setupapi.h" #include "dinput_private.h" #include "device_private.h" @@ -1601,6 +1600,7 @@ static HRESULT hid_joystick_device_try_open( WCHAR *path, HANDLE *device, PHIDP_ goto failed; } + instance->dwSize = sizeof(DIDEVICEINSTANCEW); instance->guidInstance = hid_joystick_guid; instance->guidInstance.Data1 ^= handle; instance->guidProduct = dinput_pidvid_guid; @@ -1750,81 +1750,26 @@ HRESULT hid_joystick_refresh_devices(void) 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 ) +HRESULT hid_joystick_enum_device( DWORD type, DWORD flags, DIDEVICEINSTANCEW *instance, DWORD version, int index ) { - 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)}; - HDEVINFO set, xi_set; - UINT32 i = 0; - GUID hid; - - TRACE( "index %d, guid %s\n", index, debugstr_guid( guid ) ); - - HidD_GetHidGuid( &hid ); + struct cache_entry *entry; + HRESULT hr = DI_OK; - 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 ); + EnterCriticalSection( &joystick_cache_cs ); - *device = NULL; - *preparsed = NULL; - while (SetupDiEnumDeviceInterfaces( set, NULL, &hid, i++, &iface )) + LIST_FOR_EACH_ENTRY( entry, &joystick_cache, struct cache_entry, entry ) + if (!index--) break; + if (&entry->entry == &joystick_cache) hr = DIERR_DEVICENOTREG; + else { - 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; - - /* enumerate device by GUID */ - if (IsEqualGUID( guid, &instance->guidProduct ) || IsEqualGUID( guid, &instance->guidInstance )) break; - - /* enumerate all devices */ - if (index >= 0 && !index--) break; - - CloseHandle( *device ); - HidD_FreePreparsedData( *preparsed ); - *device = NULL; - *preparsed = NULL; + *instance = entry->instance; + instance->dwDevType = device_type_for_version( instance->dwDevType, version ) | DIDEVTYPE_HID; } - 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; -} - -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; - 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 ); - if (hr != DI_OK) return hr; - - HidD_FreePreparsedData( preparsed ); - CloseHandle( device ); - - TRACE( "found device %s, usage %04x:%04x, product %s, instance %s, name %s\n", debugstr_w(device_path), - instance->wUsagePage, instance->wUsage, debugstr_guid( &instance->guidProduct ), - debugstr_guid( &instance->guidInstance ), debugstr_w(instance->tszInstanceName) ); + LeaveCriticalSection( &joystick_cache_cs ); - return DI_OK; + if (FAILED(hr)) WARN( "index %u not found\n", index ); + return hr; } static BOOL init_object_properties( struct dinput_device *device, UINT index, struct hid_value_caps *caps, diff --git a/dlls/dinput8/Makefile.in b/dlls/dinput8/Makefile.in index ebc77fa8c87..875e9681c82 100644 --- a/dlls/dinput8/Makefile.in +++ b/dlls/dinput8/Makefile.in @@ -1,6 +1,6 @@ MODULE = dinput8.dll IMPORTLIB = dinput8 -IMPORTS = dinput8 cfgmgr32 dxguid uuid comctl32 ole32 user32 advapi32 hid setupapi +IMPORTS = dinput8 cfgmgr32 dxguid uuid comctl32 ole32 user32 advapi32 hid EXTRADEFS = -DDIRECTINPUT_VERSION=0x0800 PARENTSRC = ../dinput -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10719
From: Connor McAdams <cmcadams@codeweavers.com> --- dlls/dinput/joystick_hid.c | 2 +- dlls/dinput/tests/joystick8.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index 09312f65544..509db79086f 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -1563,7 +1563,7 @@ static HRESULT hid_joystick_device_try_open( WCHAR *path, HANDLE *device, PHIDP_ 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 ); - if (device_file == INVALID_HANDLE_VALUE) return DIERR_DEVICENOTREG; + if (device_file == INVALID_HANDLE_VALUE) return E_FAIL; if (!HidD_GetPreparsedData( device_file, &preparsed_data )) goto failed; if (!HidD_GetAttributes( device_file, attrs )) goto failed; diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index 5b2ca8fe66d..ded6b11bcff 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -6267,7 +6267,7 @@ static void test_joystick_instance_guid( DWORD version ) IDirectInputDevice8_Release( device ); hr = dinput_create_device( &di, &expect_instances[0], &device ); - todo_wine ok( hr == E_FAIL, "Unexpected hr %#lx.\n", hr ); + ok( hr == E_FAIL, "Unexpected hr %#lx.\n", hr ); if (SUCCEEDED(hr)) IDirectInputDevice8_Release( device ); hr = dinput_create_device( &di, &instances[1], &device ); @@ -6293,10 +6293,10 @@ static void test_joystick_instance_guid( DWORD version ) /* Stopped devices should return E_FAIL. */ hr = dinput_create_device( &di, &instances[0], &device ); - todo_wine ok( hr == E_FAIL, "Unexpected hr %#lx.\n", hr ); + ok( hr == E_FAIL, "Unexpected hr %#lx.\n", hr ); if (SUCCEEDED(hr)) IDirectInputDevice8_Release( device ); hr = dinput_create_device( &di, &instances[2], &device ); - todo_wine ok( hr == E_FAIL, "Unexpected hr %#lx.\n", hr ); + ok( hr == E_FAIL, "Unexpected hr %#lx.\n", hr ); if (SUCCEEDED(hr)) IDirectInputDevice8_Release( device ); /* After calling EnumDevices(), guidInstance values will be reassigned. */ -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10719
From: Rémi Bernon <rbernon@codeweavers.com> Based on patches by Connor McAdams. --- dlls/dinput/joystick_hid.c | 95 ++++++++++++++++++++++++++++++++++- dlls/dinput/tests/hotplug.c | 2 +- dlls/dinput/tests/joystick8.c | 45 ++++++----------- 3 files changed, 111 insertions(+), 31 deletions(-) diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index 509db79086f..ed484331254 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -96,7 +96,18 @@ static HRESULT insert_cache_entry( DIDEVICEINSTANCEW *instance, const WCHAR *pat #define SWAP(x) MAKELONG( HIWORD(x), LOWORD(x) ) LIST_FOR_EACH_ENTRY( next, &joystick_cache, struct cache_entry, entry ) + { if (SWAP( next->instance.guidProduct.Data1 ) > SWAP( instance->guidProduct.Data1 )) break; + if (SWAP( next->instance.guidProduct.Data1 ) < SWAP( instance->guidProduct.Data1 )) continue; + if (*path && !*next->path) + { + instance->guidInstance = next->instance.guidInstance; + TRACE( "Reusing instance %s, path %s\n", debugstr_device_instance( instance ), debugstr_w( path ) ); + next->instance = *instance; + wcscpy( next->path, path ); + return S_OK; + } + } #undef SWAP if (FAILED(hr = cache_entry_create( instance, path, &entry ))) return hr; @@ -106,6 +117,67 @@ static HRESULT insert_cache_entry( DIDEVICEINSTANCEW *instance, const WCHAR *pat return S_OK; } +static void save_registry_instances( HKEY root ) +{ + struct cache_entry *entry; + DWORD vidpid = 0, index = -1; + WCHAR buffer[MAX_PATH]; + + TRACE( "Saving cached instance GUIDs\n" ); + + LIST_FOR_EACH_ENTRY( entry, &joystick_cache, struct cache_entry, entry ) + { + index = (entry->instance.guidProduct.Data1 == vidpid) ? index + 1 : 0; + vidpid = entry->instance.guidProduct.Data1; + + swprintf( buffer, ARRAY_SIZE(buffer), L"VID_%04X&PID_%04X\\Calibration\\%u", + LOWORD(vidpid), HIWORD(vidpid), index ); + RegSetKeyValueW( root, buffer, L"GUID", REG_BINARY, (BYTE *)&entry->instance.guidInstance, + sizeof(entry->instance.guidInstance) ); + + TRACE( "Saved %04x:%04x index %lu, guid %s\n", LOWORD(vidpid), HIWORD(vidpid), index, + debugstr_guid( &entry->instance.guidInstance ) ); + } +} + +static void load_registry_product_instances( HKEY root, DWORD vidpid ) +{ + WCHAR name[MAX_PATH]; + + for (DWORD i = 0; !RegEnumKeyW( root, i, name, ARRAY_SIZE(name) ); i++) + { + DIDEVICEINSTANCEW instance = {.guidProduct = dinput_pidvid_guid }; + DWORD len = sizeof(GUID); + + instance.guidProduct.Data1 = vidpid; + if (RegGetValueW( root, name, L"GUID", RRF_RT_REG_BINARY, NULL, &instance.guidInstance, &len )) continue; + insert_cache_entry( &instance, L"" ); + + TRACE( "Loaded %04x:%04x index %s, guid %s\n", LOWORD(vidpid), HIWORD(vidpid), debugstr_w( name ), + debugstr_guid( &instance.guidInstance ) ); + } +} + +static void load_registry_instances( HKEY root ) +{ + WCHAR name[MAX_PATH], buffer[MAX_PATH]; + HKEY hkey; + + TRACE( "Loading cached instance GUIDs\n" ); + + for (DWORD i = 0; !RegEnumKeyW( root, i, name, ARRAY_SIZE(name) ); i++) + { + UINT vid, pid; + + if (swscanf( name, L"VID_%04X&PID_%04X", &vid, &pid ) != 2) continue; + swprintf( buffer, ARRAY_SIZE(buffer), L"VID_%04X&PID_%04X\\Calibration", vid, pid ); + + if (RegOpenKeyExW( root, buffer, 0, KEY_ENUMERATE_SUB_KEYS, &hkey )) continue; + load_registry_product_instances( hkey, MAKELONG(vid, pid) ); + RegCloseKey( hkey ); + } +} + static HRESULT get_instance_from_guid( const GUID *guid, DIDEVICEINSTANCEW *instance, WCHAR *path ) { struct cache_entry *entry; @@ -121,6 +193,7 @@ static HRESULT get_instance_from_guid( const GUID *guid, DIDEVICEINSTANCEW *inst LIST_FOR_EACH_ENTRY( entry, &joystick_cache, struct cache_entry, entry ) { + if (!*entry->path) continue; if (IsEqualGUID( &entry->instance.guidProduct, guid )) break; if (IsEqualGUID( &entry->instance.guidInstance, guid )) break; } @@ -1719,17 +1792,30 @@ failed: HRESULT hid_joystick_refresh_devices(void) { + static const WCHAR *dinput_path = L"System\\CurrentControlSet\\Control\\MediaProperties\\" + "PrivateProperties\\DirectInput"; + WCHAR *paths = NULL; HANDLE device; + HANDLE mutex; HRESULT hr; + HKEY root; GUID hid; TRACE( "\n" ); HidD_GetHidGuid( &hid ); + if (RegCreateKeyExW( HKEY_CURRENT_USER, dinput_path, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &root, NULL )) + return DIERR_DEVICENOTREG; + EnterCriticalSection( &joystick_cache_cs ); + + mutex = CreateMutexW( NULL, FALSE, L"__wine_dinput_reg_mutex" ); + WaitForSingleObject( mutex, INFINITE ); + hid_joystick_cleanup_devices(); + load_registry_instances( root ); hr = get_device_interfaces( hid, NULL, &paths ); for (WCHAR *path = paths; SUCCEEDED(hr) && *path; path = path + wcslen( path ) + 1) @@ -1746,7 +1832,13 @@ HRESULT hid_joystick_refresh_devices(void) } free( paths ); + save_registry_instances( root ); + ReleaseMutex( mutex ); + CloseHandle( mutex ); + LeaveCriticalSection( &joystick_cache_cs ); + RegCloseKey( root ); + return hr; } @@ -1758,7 +1850,7 @@ HRESULT hid_joystick_enum_device( DWORD type, DWORD flags, DIDEVICEINSTANCEW *in EnterCriticalSection( &joystick_cache_cs ); LIST_FOR_EACH_ENTRY( entry, &joystick_cache, struct cache_entry, entry ) - if (!index--) break; + if (*entry->path && !index--) break; if (&entry->entry == &joystick_cache) hr = DIERR_DEVICENOTREG; else { @@ -2148,6 +2240,7 @@ HRESULT hid_joystick_create_device( struct dinput *dinput, const GUID *guid, IDi &impl->caps, &impl->base.instance, dinput->dwVersion ); if (hr != DI_OK) goto failed; + impl->base.instance.guidInstance = instance.guidInstance; /* use the instance GUID from the cache */ impl->base.caps.dwDevType = impl->base.instance.dwDevType; impl->attrs = attrs; list_init( &impl->effect_list ); diff --git a/dlls/dinput/tests/hotplug.c b/dlls/dinput/tests/hotplug.c index 10a3051e8ce..e4147797652 100644 --- a/dlls/dinput/tests/hotplug.c +++ b/dlls/dinput/tests/hotplug.c @@ -222,7 +222,7 @@ static BOOL test_input_lost( DWORD version ) hr = dinput_test_create_device( version, &devinst2, &device2 ); ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr ); ok( !!device2, "device2 is NULL.\n" ); - todo_wine ok( !memcmp( &devinst.guidInstance, &devinst2.guidInstance, sizeof(GUID) ), + ok( !memcmp( &devinst.guidInstance, &devinst2.guidInstance, sizeof(GUID) ), "Unexpected guidInstance.\n" ); ref = IDirectInputDevice8_Release( device2 ); ok( ref == 0, "Release returned %ld\n", ref ); diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index ded6b11bcff..169710e0ead 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -6311,8 +6311,8 @@ static void test_joystick_instance_guid( DWORD version ) winetest_push_context( "device %d", i ); - todo_wine ok( IsEqualGUID( &expect_instances[expected_joystick - 1], &instances[i] ), - "Unexpected instance %s.\n", debugstr_guid( &instances[i] ) ); + ok( IsEqualGUID( &expect_instances[expected_joystick - 1], &instances[i] ), + "Unexpected instance %s.\n", debugstr_guid( &instances[i] ) ); hr = dinput_create_device( &di, &instances[i], &device ); ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr ); @@ -6335,8 +6335,8 @@ static void test_joystick_instance_guid( DWORD version ) winetest_push_context( "device %d", i ); - todo_wine ok( IsEqualGUID( &expect_instances[expected_joystick - 1], &instances[i] ), - "Unexpected instance %s.\n", debugstr_guid( &instances[i] ) ); + ok( IsEqualGUID( &expect_instances[expected_joystick - 1], &instances[i] ), + "Unexpected instance %s.\n", debugstr_guid( &instances[i] ) ); hr = dinput_create_device( &di, &instances[i], &device ); ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr ); @@ -6356,7 +6356,6 @@ static void test_joystick_instance_guid( DWORD version ) { winetest_push_context( "device %d", i ); - todo_wine_if( !(i & 0x1) ) ok( IsEqualGUID( &expect_instances[i], &instances[i] ), "Unexpected guidInstance %s.\n", debugstr_guid( &instances[i] ) ); @@ -6397,17 +6396,13 @@ static void test_joystick_instance_guid( DWORD version ) hid_device_start( &descs[i], 1 ); hr = dinput_create_device( &di, &expect_instances[i], &device ); - todo_wine ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr ); - if (SUCCEEDED(hr)) - { - check_device_hid_serial( device, descs[i].serial_str ); - IDirectInputDevice8_Release( device ); - } + ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr ); + check_device_hid_serial( device, descs[i].serial_str ); + IDirectInputDevice8_Release( device ); hid_device_stop( &descs[i], 1 ); hr = dinput_create_device( &di, &expect_instances[i], &device ); - todo_wine ok( hr == E_FAIL, "Unexpected hr %#lx.\n", hr ); - if (SUCCEEDED(hr)) IDirectInputDevice8_Release( device ); + ok( hr == E_FAIL, "Unexpected hr %#lx.\n", hr ); hid_device_start( &descs[i], 1 ); winetest_pop_context(); @@ -6434,17 +6429,13 @@ static void test_joystick_instance_guid( DWORD version ) hid_device_start( &descs[0], 1 ); hr = dinput_create_device( &di, &expect_instances[0], &device ); - todo_wine ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr ); - if (SUCCEEDED(hr)) - { - check_device_hid_serial( device, descs[0].serial_str ); - IDirectInputDevice8_Release( device ); - } + ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr ); + check_device_hid_serial( device, descs[0].serial_str ); + IDirectInputDevice8_Release( device ); hid_device_stop( &descs[0], 1 ); hr = dinput_create_device( &di, &expect_instances[0], &device ); - todo_wine ok( hr == E_FAIL, "Unexpected hr %#lx.\n", hr ); - if (SUCCEEDED(hr)) IDirectInputDevice8_Release( device ); + ok( hr == E_FAIL, "Unexpected hr %#lx.\n", hr ); /* Start device 1. */ @@ -6455,8 +6446,7 @@ static void test_joystick_instance_guid( DWORD version ) * with device 0. */ hr = dinput_create_device( &di, &expect_instances[0], &device ); - todo_wine ok( hr == E_FAIL, "Unexpected hr %#lx.\n", hr ); - if (SUCCEEDED(hr)) IDirectInputDevice8_Release( device ); + ok( hr == E_FAIL, "Unexpected hr %#lx.\n", hr ); /* * expect_instances[1] is not currently associated with a device, which @@ -6468,12 +6458,9 @@ static void test_joystick_instance_guid( DWORD version ) ok( hr == DIERR_DEVICENOTREG, "Unexpected hr %#lx.\n", hr ); hr = dinput_create_device( &di, &expect_instances[0], &device ); - todo_wine ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr ); - if (SUCCEEDED(hr)) - { - check_device_hid_serial( device, descs[1].serial_str ); - IDirectInputDevice8_Release( device ); - } + ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr ); + check_device_hid_serial( device, descs[1].serial_str ); + IDirectInputDevice8_Release( device ); hid_device_stop( &descs[1], 1 ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10719
From: Connor McAdams <cmcadams@codeweavers.com> --- dlls/dinput/joystick_hid.c | 47 +++++++++++++++++++++++++++-------- dlls/dinput/tests/joystick8.c | 14 +++++------ 2 files changed, 42 insertions(+), 19 deletions(-) diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index ed484331254..fa22d806437 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -49,9 +49,42 @@ WINE_DEFAULT_DEBUG_CHANNEL(dinput); DEFINE_GUID( GUID_DEVINTERFACE_WINEXINPUT,0x6c53d5fd,0x6480,0x440f,0xb6,0x18,0x47,0x67,0x50,0xc5,0xe1,0xa6 ); -DEFINE_GUID( hid_joystick_guid, 0x9e573edb, 0x7734, 0x11d2, 0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7 ); DEFINE_GUID( device_path_guid, 0x00000000, 0x0000, 0x0000, 0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf8 ); +/* + * Version 1 UUID timestamps are a count of the number of 100 nanosecond + * intervals since 00:00:00.00, 15 October 1582 (the date of Gregorian + * reform to the Christian calendar). FILETIME is a count of the number of 100 + * nanosecond intervals since 00:00:00.00, 1 January 1601. In order to convert + * a FILETIME value to a UUID timestamp, we need to add: + * - 17 days in October 1582. + * - 30 days in November 1582. + * - 31 days in December 1582. + * - 18 years between January 1583 and January 1601. + * - 5 leap days in those 18 years. + */ +#define UUID_TIME_TO_SYSTEM_TIME_DAYS ((ULONG64)((365 * 18) + 5 + 17 + 30 + 31)) +#define UUID_TIME_TO_SYSTEM_TIME_NS_DIFFERENCE ((UUID_TIME_TO_SYSTEM_TIME_DAYS) * 24 * 60 * 60 * 10000000) +DEFINE_GUID( dinput_joystick_uuid_init, 0x00000000, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x00, 'D', 'E', 'S', 'T' ); + +static GUID create_instance_uuid(void) +{ + GUID tmp = dinput_joystick_uuid_init; + static LONG clock_seq; + ULARGE_INTEGER time; + ULONG cur_seq; + + GetSystemTimeAsFileTime( (FILETIME *)&time ); + time.QuadPart += UUID_TIME_TO_SYSTEM_TIME_NS_DIFFERENCE; + tmp.Data1 = (time.QuadPart & 0xffffffff); + tmp.Data2 = ((time.QuadPart >> 32) & 0xffff); + tmp.Data3 |= ((time.QuadPart >> 48) & 0x0fff); + cur_seq = InterlockedIncrement( &clock_seq ); + tmp.Data4[1] |= (cur_seq & 0xff); + tmp.Data4[0] |= ((cur_seq & 0x3f00) >> 8); + return tmp; +} + static CRITICAL_SECTION joystick_cache_cs; static CRITICAL_SECTION_DEBUG joystick_cache_cs_debug = { @@ -1623,7 +1656,7 @@ static HRESULT hid_joystick_device_try_open( WCHAR *path, HANDLE *device, PHIDP_ 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]; WCHAR *override_paths; HIDP_VALUE_CAPS value; @@ -1631,7 +1664,6 @@ static HRESULT hid_joystick_device_try_open( WCHAR *path, HANDLE *device, PHIDP_ ULONG node_count; NTSTATUS status; BOOL override; - UINT32 handle; USHORT count; device_file = CreateFileW( path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, @@ -1667,15 +1699,8 @@ static HRESULT hid_joystick_device_try_open( WCHAR *path, HANDLE *device, PHIDP_ return hid_joystick_device_try_open( path, device, preparsed, attrs, caps, instance, version ); } - 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->dwSize = sizeof(DIDEVICEINSTANCEW); - instance->guidInstance = hid_joystick_guid; - instance->guidInstance.Data1 ^= handle; + instance->guidInstance = create_instance_uuid(); instance->guidProduct = dinput_pidvid_guid; instance->guidProduct.Data1 = MAKELONG( attrs->VendorID, attrs->ProductID ); instance->guidFFDriver = GUID_NULL; diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index 169710e0ead..562dc87e62a 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)) { @@ -6191,12 +6191,12 @@ static void test_joystick_instance_guid( DWORD version ) { winetest_push_context( "device %d", i ); - todo_wine ok( !IsEqualGUID( &expect_instances[i], &instances[i] ), - "Unexpected instance %s.\n", debugstr_guid( &instances[i] ) ); + ok( !IsEqualGUID( &expect_instances[i], &instances[i] ), + "Unexpected instance %s.\n", debugstr_guid( &instances[i] ) ); /* Old guidInstance no longer works. */ hr = dinput_create_device( &di, &expect_instances[i], &device ); - todo_wine ok( hr == DIERR_DEVICENOTREG, "Unexpected hr %#lx.\n", hr ); + ok( hr == DIERR_DEVICENOTREG, "Unexpected hr %#lx.\n", hr ); if (SUCCEEDED(hr)) IDirectInputDevice8_Release( device ); expect_instances[i] = instances[i]; @@ -6224,8 +6224,7 @@ static void test_joystick_instance_guid( DWORD version ) ok( hr == DIERR_DEVICENOTREG, "Unexpected hr %#lx.\n", hr ); hr = dinput_create_device( &di, &expect_instances[0], &device ); - todo_wine ok( hr == DIERR_DEVICENOTREG, "Unexpected hr %#lx.\n", hr ); - if (SUCCEEDED(hr)) IDirectInputDevice8_Release( device ); + ok( hr == DIERR_DEVICENOTREG, "Unexpected hr %#lx.\n", hr ); instances_end = instances; hr = dinput_enum_devices( &di, find_test_device_instances, &instances_end ); @@ -6245,8 +6244,7 @@ static void test_joystick_instance_guid( DWORD version ) ok( hr == DIERR_DEVICENOTREG, "Unexpected hr %#lx.\n", hr ); hr = dinput_create_device( &di, &expect_instances[0], &device ); - todo_wine ok( hr == DIERR_DEVICENOTREG, "Unexpected hr %#lx.\n", hr ); - if (SUCCEEDED(hr)) IDirectInputDevice8_Release( device ); + ok( hr == DIERR_DEVICENOTREG, "Unexpected hr %#lx.\n", hr ); instances_end = instances; hr = dinput_enum_devices( &di, find_test_device_instances, &instances_end ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10719
participants (3)
-
Connor McAdams -
Rémi Bernon -
Rémi Bernon (@rbernon)