From: Connor McAdams <cmcadams@codeweavers.com> Signed-off-by: Connor McAdams <cmcadams@codeweavers.com> --- dlls/dinput/joystick_hid.c | 74 +++++++++++++++++++++++++++-------- dlls/dinput/tests/joystick8.c | 27 ++++++------- 2 files changed, 71 insertions(+), 30 deletions(-) diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index fa22d806437..14547245af1 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -96,10 +96,13 @@ static CRITICAL_SECTION joystick_cache_cs = { &joystick_cache_cs_debug, -1, 0, 0 static struct list joystick_cache = LIST_INIT( joystick_cache ); +#define MAX_JOY_ID 16 + struct cache_entry { struct list entry; DIDEVICEINSTANCEW instance; + DWORD joy_id; WCHAR path[MAX_PATH]; }; @@ -109,12 +112,14 @@ static const char *debugstr_device_instance( const DIDEVICEINSTANCEW *instance ) HIWORD(instance->guidProduct.Data1), debugstr_guid( &instance->guidInstance ) ); } -static HRESULT cache_entry_create( const DIDEVICEINSTANCEW *instance, const WCHAR *path, struct cache_entry **out ) +static HRESULT cache_entry_create( const DIDEVICEINSTANCEW *instance, DWORD joy_id, + const WCHAR *path, struct cache_entry **out ) { struct cache_entry *entry; if (!(entry = calloc( 1, sizeof(*entry) ))) return E_OUTOFMEMORY; entry->instance = *instance; + entry->joy_id = joy_id; wcscpy( entry->path, path ); CharLowerW( entry->path ); @@ -122,7 +127,7 @@ static HRESULT cache_entry_create( const DIDEVICEINSTANCEW *instance, const WCHA return S_OK; } -static HRESULT insert_cache_entry( DIDEVICEINSTANCEW *instance, const WCHAR *path ) +static HRESULT insert_cache_entry( DIDEVICEINSTANCEW *instance, DWORD joy_id, const WCHAR *path ) { struct cache_entry *entry, *next; HRESULT hr; @@ -135,7 +140,8 @@ static HRESULT insert_cache_entry( DIDEVICEINSTANCEW *instance, const WCHAR *pat if (*path && !*next->path) { instance->guidInstance = next->instance.guidInstance; - TRACE( "Reusing instance %s, path %s\n", debugstr_device_instance( instance ), debugstr_w( path ) ); + TRACE( "Reusing instance %s, path %s, joy_id %#lx\n", debugstr_device_instance( instance ), + debugstr_w( path ), next->joy_id ); next->instance = *instance; wcscpy( next->path, path ); return S_OK; @@ -143,8 +149,9 @@ static HRESULT insert_cache_entry( DIDEVICEINSTANCEW *instance, const WCHAR *pat } #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 ) ); + if (FAILED(hr = cache_entry_create( instance, joy_id, path, &entry ))) return hr; + TRACE( "Created instance %s, path %s, joy_id %#lx\n", debugstr_device_instance( instance ), + debugstr_w( path ), joy_id ); list_add_before( &next->entry, &entry->entry ); return S_OK; @@ -167,9 +174,12 @@ static void save_registry_instances( HKEY root ) LOWORD(vidpid), HIWORD(vidpid), index ); RegSetKeyValueW( root, buffer, L"GUID", REG_BINARY, (BYTE *)&entry->instance.guidInstance, sizeof(entry->instance.guidInstance) ); + if (entry->joy_id >= MAX_JOY_ID) RegDeleteKeyValueW( root, buffer, L"Joystick Id" ); + else RegSetKeyValueW( root, buffer, L"Joystick Id", REG_BINARY, (BYTE *)&entry->joy_id, + sizeof(entry->joy_id) ); - TRACE( "Saved %04x:%04x index %lu, guid %s\n", LOWORD(vidpid), HIWORD(vidpid), index, - debugstr_guid( &entry->instance.guidInstance ) ); + TRACE( "Saved %04x:%04x index %lu, guid %s, joy_id %#lx\n", LOWORD(vidpid), HIWORD(vidpid), index, + debugstr_guid( &entry->instance.guidInstance ), entry->joy_id ); } } @@ -180,14 +190,16 @@ static void load_registry_product_instances( HKEY root, DWORD vidpid ) for (DWORD i = 0; !RegEnumKeyW( root, i, name, ARRAY_SIZE(name) ); i++) { DIDEVICEINSTANCEW instance = {.guidProduct = dinput_pidvid_guid }; - DWORD len = sizeof(GUID); + DWORD len = sizeof(GUID), joy_id, len_id = sizeof(joy_id); instance.guidProduct.Data1 = vidpid; if (RegGetValueW( root, name, L"GUID", RRF_RT_REG_BINARY, NULL, &instance.guidInstance, &len )) continue; - insert_cache_entry( &instance, L"" ); + if (RegGetValueW( root, name, L"Joystick Id", RRF_RT_REG_BINARY, NULL, &joy_id, &len_id )) joy_id = MAX_JOY_ID + 1; + + TRACE( "Loaded %04x:%04x index %s, guid %s, joy_id %#lx\n", LOWORD(vidpid), HIWORD(vidpid), debugstr_w( name ), + debugstr_guid( &instance.guidInstance ), joy_id ); - TRACE( "Loaded %04x:%04x index %s, guid %s\n", LOWORD(vidpid), HIWORD(vidpid), debugstr_w( name ), - debugstr_guid( &instance.guidInstance ) ); + insert_cache_entry( &instance, joy_id, L"" ); } } @@ -211,7 +223,33 @@ static void load_registry_instances( HKEY root ) } } -static HRESULT get_instance_from_guid( const GUID *guid, DIDEVICEINSTANCEW *instance, WCHAR *path ) +static void assign_joystick_ids(void) +{ + DWORD ids = ((1 << MAX_JOY_ID) - 1) | (1 << (MAX_JOY_ID + 1)); + struct cache_entry *entry; + + LIST_FOR_EACH_ENTRY( entry, &joystick_cache, struct cache_entry, entry ) + { + if (!*entry->path || entry->joy_id >= MAX_JOY_ID) continue; + if (!(ids & (1 << entry->joy_id))) entry->joy_id = MAX_JOY_ID + 1; + else ids &= ~(1 << entry->joy_id); + + TRACE( "Reusing joy_id %#lx for instance %s, path %s\n", entry->joy_id, + debugstr_device_instance( &entry->instance ), debugstr_w( entry->path ) ); + } + + LIST_FOR_EACH_ENTRY( entry, &joystick_cache, struct cache_entry, entry ) + { + if (!*entry->path || entry->joy_id < MAX_JOY_ID) continue; + BitScanForward( &entry->joy_id, ids ); + if (entry->joy_id < MAX_JOY_ID) ids &= ~(1 << entry->joy_id); + + TRACE( "Assigned joy_id %#lx to instance %s, path %s\n", entry->joy_id, + debugstr_device_instance( &entry->instance ), debugstr_w( entry->path ) ); + } +} + +static HRESULT get_instance_from_guid( const GUID *guid, DIDEVICEINSTANCEW *instance, DWORD *joy_id, WCHAR *path ) { struct cache_entry *entry; HRESULT hr = DI_OK; @@ -234,6 +272,7 @@ static HRESULT get_instance_from_guid( const GUID *guid, DIDEVICEINSTANCEW *inst else { *instance = entry->instance; + *joy_id = entry->joy_id; wcscpy( path, entry->path ); } @@ -382,6 +421,7 @@ struct hid_joystick WCHAR device_path[MAX_PATH]; HIDD_ATTRIBUTES attrs; HIDP_CAPS caps; + DWORD joy_id; char *input_report_buf; char *output_report_buf; @@ -1007,7 +1047,7 @@ static HRESULT hid_joystick_get_property( IDirectInputDevice8W *iface, DWORD pro case (DWORD_PTR)DIPROP_JOYSTICKID: { DIPROPDWORD *value = (DIPROPDWORD *)header; - value->dwData = impl->base.instance.guidInstance.Data3; + value->dwData = impl->joy_id; return DI_OK; } case (DWORD_PTR)DIPROP_GUIDANDPATH: @@ -1851,12 +1891,13 @@ HRESULT hid_joystick_refresh_devices(void) HIDP_CAPS caps; if (FAILED(hid_joystick_device_try_open( path, &device, &preparsed, &attrs, &caps, &instance, 0x0800 ))) continue; - hr = insert_cache_entry( &instance, path ); + hr = insert_cache_entry( &instance, MAX_JOY_ID + 1, path ); HidD_FreePreparsedData( preparsed ); CloseHandle( device ); } free( paths ); + assign_joystick_ids(); save_registry_instances( root ); ReleaseMutex( mutex ); CloseHandle( mutex ); @@ -2244,18 +2285,19 @@ HRESULT hid_joystick_create_device( struct dinput *dinput, const GUID *guid, IDi struct hid_joystick *impl = NULL; WCHAR device_path[MAX_PATH]; USAGE_AND_PAGE *usages; + DWORD size, joy_id = 0; char *buffer; HRESULT hr; - DWORD size; TRACE( "dinput %p, guid %s, out %p\n", dinput, debugstr_guid( guid ), out ); *out = NULL; - if (FAILED(hr = get_instance_from_guid( guid, &instance, device_path ))) return hr; + if (FAILED(hr = get_instance_from_guid( guid, &instance, &joy_id, device_path ))) return hr; if (!(impl = calloc( 1, sizeof(*impl) ))) return E_OUTOFMEMORY; dinput_device_init( &impl->base, &hid_joystick_vtbl, guid, dinput ); + impl->joy_id = joy_id; 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 ); diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index f6d3d0e2f5a..de9841a2d22 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -2107,7 +2107,6 @@ static void test_simple_joystick( DWORD version ) prop_dword.dwData = 0xdeadbeef; hr = IDirectInputDevice8_GetProperty( device, DIPROP_JOYSTICKID, &prop_dword.diph ); ok( hr == DI_OK, "GetProperty DIPROP_JOYSTICKID returned %#lx\n", hr ); - todo_wine ok( prop_dword.dwData == 0, "got %#lx expected 0\n", prop_dword.dwData ); prop_dword.dwData = 0xdeadbeef; @@ -6622,7 +6621,7 @@ static void test_joystick_id( DWORD version ) ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr ); check_device_hid_serial( device, descs[i].serial_str ); - check_device_joystick_id( device, i, TRUE ); + check_device_joystick_id( device, i, FALSE ); IDirectInputDevice8_Release( device ); winetest_pop_context(); @@ -6648,7 +6647,7 @@ static void test_joystick_id( DWORD version ) ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr ); check_device_hid_serial( device, descs[expected_dev_idx].serial_str ); - check_device_joystick_id( device, expected_dev_idx, TRUE ); + check_device_joystick_id( device, expected_dev_idx, FALSE ); IDirectInputDevice8_Release( device ); winetest_pop_context(); } @@ -6674,7 +6673,7 @@ static void test_joystick_id( DWORD version ) ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr ); check_device_hid_serial( device, descs[expected_dev_idx].serial_str ); - check_device_joystick_id( device, i, TRUE ); + check_device_joystick_id( device, i, FALSE ); IDirectInputDevice8_Release( device ); winetest_pop_context(); @@ -6698,8 +6697,8 @@ static void test_joystick_id( DWORD version ) ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr ); check_device_hid_serial( device, descs[i].serial_str ); - if (i < 2) check_device_joystick_id( device, i, TRUE ); - else check_device_joystick_id( device, (i == 2) ? 3 : 2, TRUE ); + if (i < 2) check_device_joystick_id( device, i, FALSE ); + else check_device_joystick_id( device, (i == 2) ? 3 : 2, FALSE ); IDirectInputDevice8_Release( device ); winetest_pop_context(); @@ -6719,7 +6718,7 @@ static void test_joystick_id( DWORD version ) ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr ); check_device_hid_serial( device, descs[i].serial_str ); - check_device_joystick_id( device, i, TRUE ); + check_device_joystick_id( device, i, FALSE ); IDirectInputDevice8_Release( device ); winetest_pop_context(); @@ -6738,7 +6737,7 @@ static void test_joystick_id( DWORD version ) ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr ); check_device_hid_serial( device, descs[0].serial_str ); - check_device_joystick_id( device, 0, TRUE ); + check_device_joystick_id( device, 0, FALSE ); IDirectInputDevice8_Release( device ); @@ -6755,7 +6754,7 @@ static void test_joystick_id( DWORD version ) ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr ); check_device_hid_serial( device, descs[i].serial_str ); - check_device_joystick_id( device, !i ? 15 : i, TRUE ); + check_device_joystick_id( device, !i ? 15 : i, FALSE ); IDirectInputDevice8_Release( device ); winetest_pop_context(); @@ -6780,7 +6779,7 @@ static void test_joystick_id( DWORD version ) ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr ); check_device_hid_serial( device, descs[i].serial_str ); - check_device_joystick_id( device, i, TRUE ); + check_device_joystick_id( device, i, FALSE ); IDirectInputDevice8_Release( device ); winetest_pop_context(); @@ -6806,8 +6805,8 @@ static void test_joystick_id( DWORD version ) ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr ); check_device_hid_serial( device, descs[i].serial_str ); - if (i < 2) check_device_joystick_id( device, !i ? 1 : 0, TRUE ); - else check_device_joystick_id( device, i, TRUE ); + if (i < 2) check_device_joystick_id( device, !i ? 1 : 0, FALSE ); + else check_device_joystick_id( device, i, FALSE ); IDirectInputDevice8_Release( device ); winetest_pop_context(); } @@ -6836,8 +6835,8 @@ static void test_joystick_id( DWORD version ) /* * Devices 16 and above all get a fixed joystick ID of 17. */ - if (i >= 16) check_device_joystick_id( device, 17, TRUE ); - else check_device_joystick_id( device, i, TRUE ); + if (i >= 16) check_device_joystick_id( device, 17, FALSE ); + else check_device_joystick_id( device, i, FALSE ); IDirectInputDevice8_Release( device ); winetest_pop_context(); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10776