-- v2: win32u: Fix thread safety when accessing rawinput device data. win32u: Read rawinput device preparsed data using virtual memory. win32u: Enumerate mouse and keyboard devices first and skip duplicates. dinput/tests: Add some rawinput joystick tests. dinput/tests: Wait for Acquire to complete when injecting input.
From: R��mi Bernon rbernon@codeweavers.com
--- dlls/dinput/tests/joystick8.c | 43 +++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 10 deletions(-)
diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index 1c6496790e6..29d979e6da7 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -1327,6 +1327,11 @@ static void test_simple_joystick( DWORD version )
send_hid_input( file, &injected_input[0], sizeof(*injected_input) ); res = WaitForSingleObject( event, 100 ); + if (res == WAIT_TIMEOUT) /* Acquire is asynchronous */ + { + send_hid_input( file, &injected_input[0], sizeof(*injected_input) ); + res = WaitForSingleObject( event, 100 ); + } ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); ResetEvent( event );
@@ -1353,6 +1358,11 @@ static void test_simple_joystick( DWORD version )
send_hid_input( file, &injected_input[1], sizeof(*injected_input) ); res = WaitForSingleObject( event, 100 ); + if (res == WAIT_TIMEOUT) /* Acquire is asynchronous */ + { + send_hid_input( file, &injected_input[1], sizeof(*injected_input) ); + res = WaitForSingleObject( event, 100 ); + } ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); ResetEvent( event );
@@ -1550,9 +1560,15 @@ static void test_simple_joystick( DWORD version )
send_hid_input( file, &injected_input[4], sizeof(*injected_input) ); res = WaitForSingleObject( event, 100 ); + if (res == WAIT_TIMEOUT) /* Acquire is asynchronous */ + { + send_hid_input( file, &injected_input[4], sizeof(*injected_input) ); + res = WaitForSingleObject( event, 100 ); + } todo_wine ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); ResetEvent( event ); + send_hid_input( file, &injected_input[3], sizeof(*injected_input) ); res = WaitForSingleObject( event, 100 ); ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); @@ -1565,6 +1581,10 @@ static void test_simple_joystick( DWORD version ) ok( ((ULONG *)buffer)[2] == 0x7fff, "got %#lx, expected %#x\n", ((ULONG *)buffer)[2], 0x7fff ); hr = IDirectInputDevice8_Unacquire( device ); ok( hr == DI_OK, "Unacquire returned: %#lx\n", hr ); + hr = IDirectInputDevice8_SetProperty( device, DIPROP_LOGICALRANGE, &prop_range.diph ); + ok( hr == DIERR_UNSUPPORTED, "SetProperty DIPROP_LOGICALRANGE returned %#lx\n", hr ); + hr = IDirectInputDevice8_SetProperty( device, DIPROP_PHYSICALRANGE, &prop_range.diph ); + ok( hr == DIERR_UNSUPPORTED, "SetProperty DIPROP_PHYSICALRANGE returned %#lx\n", hr );
hr = IDirectInputDevice8_SetDataFormat( device, &c_dfDIJoystick2 ); ok( hr == DI_OK, "SetDataFormat returned: %#lx\n", hr ); @@ -1573,8 +1593,14 @@ static void test_simple_joystick( DWORD version )
send_hid_input( file, &injected_input[4], sizeof(*injected_input) ); res = WaitForSingleObject( event, 100 ); + if (res == WAIT_TIMEOUT) /* Acquire is asynchronous */ + { + send_hid_input( file, &injected_input[4], sizeof(*injected_input) ); + res = WaitForSingleObject( event, 100 ); + } ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); ResetEvent( event ); + send_hid_input( file, &injected_input[3], sizeof(*injected_input) ); res = WaitForSingleObject( event, 100 ); ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); @@ -1615,15 +1641,6 @@ static void test_simple_joystick( DWORD version ) ok( hr == (version < 0x0800 ? DIERR_UNSUPPORTED : DIERR_ACQUIRED), "SetProperty DIPROP_PHYSICALRANGE returned %#lx\n", hr );
- hr = IDirectInputDevice8_Unacquire( device ); - ok( hr == DI_OK, "Unacquire returned: %#lx\n", hr ); - hr = IDirectInputDevice8_SetProperty( device, DIPROP_LOGICALRANGE, &prop_range.diph ); - ok( hr == DIERR_UNSUPPORTED, "SetProperty DIPROP_LOGICALRANGE returned %#lx\n", hr ); - hr = IDirectInputDevice8_SetProperty( device, DIPROP_PHYSICALRANGE, &prop_range.diph ); - ok( hr == DIERR_UNSUPPORTED, "SetProperty DIPROP_PHYSICALRANGE returned %#lx\n", hr ); - hr = IDirectInputDevice8_Acquire( device ); - ok( hr == DI_OK, "Unacquire returned: %#lx\n", hr ); - prop_range.diph.dwHow = DIPH_DEVICE; prop_range.diph.dwObj = 0; prop_range.lMin = 0xdeadbeef; @@ -1800,7 +1817,8 @@ static void test_simple_joystick( DWORD version ) send_hid_input( file, &injected_input[i], sizeof(*injected_input) );
res = WaitForSingleObject( event, 100 ); - if (i == 0 || i == 3) ok( res == WAIT_TIMEOUT, "WaitForSingleObject succeeded\n" ); + if (i == 0) ok( res == WAIT_TIMEOUT || broken( res == WAIT_OBJECT_0 ) /* w8 */, "WaitForSingleObject succeeded\n" ); + else if (i == 3) ok( res == WAIT_TIMEOUT, "WaitForSingleObject succeeded\n" ); else ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); ResetEvent( event ); winetest_pop_context(); @@ -1945,6 +1963,11 @@ static void test_simple_joystick( DWORD version ) send_hid_input( file, &injected_input[i], sizeof(*injected_input) );
res = WaitForSingleObject( event, 100 ); + if (i == 0 && res == WAIT_TIMEOUT) /* Acquire is asynchronous */ + { + send_hid_input( file, &injected_input[i], sizeof(*injected_input) ); + res = WaitForSingleObject( event, 100 ); + } if (i == 3) ok( res == WAIT_TIMEOUT, "WaitForSingleObject succeeded\n" ); else ok( res == WAIT_OBJECT_0, "WaitForSingleObject failed\n" ); ResetEvent( event );
From: R��mi Bernon rbernon@codeweavers.com
--- dlls/dinput/tests/joystick8.c | 269 ++++++++++++++++++++++++++++++++++ 1 file changed, 269 insertions(+)
diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index 29d979e6da7..3193ee12ddc 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -4101,6 +4101,274 @@ done: cleanup_registry_keys(); }
+static BOOL wm_input_device_change_count; +static BOOL wm_input_count; +static char wm_input_buf[1024]; +static UINT wm_input_len; + +static LRESULT CALLBACK rawinput_wndproc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) +{ + UINT size = sizeof(wm_input_buf); + + if (msg == WM_INPUT_DEVICE_CHANGE) wm_input_device_change_count++; + if (msg == WM_INPUT) + { + wm_input_count++; + wm_input_len = GetRawInputData( (HRAWINPUT)lparam, RID_INPUT, (RAWINPUT *)wm_input_buf, + &size, sizeof(RAWINPUTHEADER) ); + } + + return DefWindowProcW( hwnd, msg, wparam, lparam ); +} + +static void test_rawinput(void) +{ +#include "psh_hid_macros.h" + static const unsigned char report_desc[] = + { + USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC), + USAGE(1, HID_USAGE_GENERIC_JOYSTICK), + COLLECTION(1, Application), + USAGE(1, HID_USAGE_GENERIC_JOYSTICK), + COLLECTION(1, Report), + REPORT_ID(1, 1), + + USAGE(1, HID_USAGE_GENERIC_WHEEL), + USAGE(4, (0xff01u<<16)|(0x1234)), + USAGE(1, HID_USAGE_GENERIC_X), + USAGE(1, HID_USAGE_GENERIC_Y), + USAGE(4, (HID_USAGE_PAGE_SIMULATION<<16)|HID_USAGE_SIMULATION_RUDDER), + USAGE(4, (HID_USAGE_PAGE_DIGITIZER<<16)|HID_USAGE_DIGITIZER_TIP_PRESSURE), + USAGE(4, (HID_USAGE_PAGE_CONSUMER<<16)|HID_USAGE_CONSUMER_VOLUME), + LOGICAL_MINIMUM(1, 0xe7), + LOGICAL_MAXIMUM(1, 0x38), + PHYSICAL_MINIMUM(1, 0xe7), + PHYSICAL_MAXIMUM(1, 0x38), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 7), + INPUT(1, Data|Var|Abs), + + USAGE(1, HID_USAGE_GENERIC_HATSWITCH), + LOGICAL_MINIMUM(1, 1), + LOGICAL_MAXIMUM(1, 8), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 8), + REPORT_SIZE(1, 4), + REPORT_COUNT(1, 1), + INPUT(1, Data|Var|Abs|Null), + + USAGE_PAGE(1, HID_USAGE_PAGE_BUTTON), + USAGE_MINIMUM(1, 1), + USAGE_MAXIMUM(1, 2), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 1), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 1), + REPORT_SIZE(1, 1), + REPORT_COUNT(1, 4), + INPUT(1, Data|Var|Abs), + END_COLLECTION, + END_COLLECTION, + }; + C_ASSERT(sizeof(report_desc) < MAX_HID_DESCRIPTOR_LEN); +#include "pop_hid_macros.h" + + struct hid_device_desc desc = + { + .use_report_id = TRUE, + .caps = { .InputReportByteLength = 9 }, + .attributes = default_attributes, + }; + struct hid_expect injected_input[] = + { + { + .code = IOCTL_HID_READ_REPORT, + .report_buf = {1,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0}, + }, + { + .code = IOCTL_HID_READ_REPORT, + .report_buf = {1,0x10,0x10,0x38,0x38,0x10,0x10,0x10,0xf8}, + }, + { + .code = IOCTL_HID_READ_REPORT, + .report_buf = {1,0x10,0x10,0x01,0x01,0x10,0x10,0x10,0x00}, + }, + { + .code = IOCTL_HID_READ_REPORT, + .report_buf = {1,0x10,0x10,0x01,0x01,0x10,0x10,0x10,0x00}, + }, + { + .code = IOCTL_HID_READ_REPORT, + .report_buf = {1,0x10,0x10,0x80,0x80,0x10,0x10,0x10,0xff}, + }, + { + .code = IOCTL_HID_READ_REPORT, + .report_buf = {1,0x10,0x10,0x10,0xee,0x10,0x10,0x10,0x54}, + }, + }; + WNDCLASSEXW class = + { + .cbSize = sizeof(WNDCLASSEXW), + .hInstance = GetModuleHandleW( NULL ), + .lpszClassName = L"rawinput", + .lpfnWndProc = rawinput_wndproc, + }; + RAWINPUT *rawinput = (RAWINPUT *)wm_input_buf; + RAWINPUTDEVICELIST raw_device_list[16]; + RAWINPUTDEVICE raw_devices[16]; + ULONG i, res, device_count; + WCHAR path[MAX_PATH] = {0}; + HANDLE file; + UINT count; + HWND hwnd; + BOOL ret; + MSG msg; + + RegisterClassExW( &class ); + + cleanup_registry_keys(); + + desc.report_descriptor_len = sizeof(report_desc); + memcpy( desc.report_descriptor_buf, report_desc, sizeof(report_desc) ); + fill_context( desc.context, ARRAY_SIZE(desc.context) ); + + hwnd = CreateWindowW( class.lpszClassName, L"dinput", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 10, 10, 200, 200, + NULL, NULL, NULL, NULL ); + ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() ); + + count = ARRAY_SIZE(raw_devices); + res = GetRegisteredRawInputDevices( raw_devices, &count, sizeof(RAWINPUTDEVICE) ); + ok( res == 0, "GetRegisteredRawInputDevices returned %lu\n", res ); + todo_wine + ok( count == ARRAY_SIZE(raw_devices), "got count %u\n", count ); + + count = ARRAY_SIZE(raw_device_list); + res = GetRawInputDeviceList( raw_device_list, &count, sizeof(RAWINPUTDEVICELIST) ); + ok( res >= 2, "GetRawInputDeviceList returned %lu\n", res ); + ok( count == ARRAY_SIZE(raw_device_list), "got count %u\n", count ); + device_count = res; + + if (!hid_device_start( &desc )) goto done; + + count = ARRAY_SIZE(raw_devices); + res = GetRegisteredRawInputDevices( raw_devices, &count, sizeof(RAWINPUTDEVICE) ); + ok( res == 0, "GetRegisteredRawInputDevices returned %lu\n", res ); + todo_wine + ok( count == ARRAY_SIZE(raw_devices), "got count %u\n", count ); + + + while (PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + ok( !wm_input_device_change_count, "got %u WM_INPUT_DEVICE_CHANGE\n", wm_input_device_change_count ); + ok( !wm_input_count, "got %u WM_INPUT\n", wm_input_count ); + + raw_devices[0].usUsagePage = HID_USAGE_PAGE_GENERIC; + raw_devices[0].usUsage = HID_USAGE_GENERIC_GAMEPAD; + raw_devices[0].dwFlags = RIDEV_DEVNOTIFY; + raw_devices[0].hwndTarget = hwnd; + count = ARRAY_SIZE(raw_devices); + ret = RegisterRawInputDevices( raw_devices, 1, sizeof(RAWINPUTDEVICE) ); + ok( ret, "RegisterRawInputDevices failed, error %lu\n", GetLastError() ); + + hid_device_stop( &desc ); + + while (PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + ok( !wm_input_device_change_count, "got %u WM_INPUT_DEVICE_CHANGE\n", wm_input_device_change_count ); + ok( !wm_input_count, "got %u WM_INPUT\n", wm_input_count ); + + raw_devices[0].usUsagePage = HID_USAGE_PAGE_GENERIC; + raw_devices[0].usUsage = HID_USAGE_GENERIC_JOYSTICK; + raw_devices[0].dwFlags = RIDEV_DEVNOTIFY; + raw_devices[0].hwndTarget = hwnd; + count = ARRAY_SIZE(raw_devices); + ret = RegisterRawInputDevices( raw_devices, 1, sizeof(RAWINPUTDEVICE) ); + ok( ret, "RegisterRawInputDevices failed, error %lu\n", GetLastError() ); + + hid_device_start( &desc ); + + while (PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + ok( wm_input_device_change_count == 1, "got %u WM_INPUT_DEVICE_CHANGE\n", wm_input_device_change_count ); + ok( !wm_input_count, "got %u WM_INPUT\n", wm_input_count ); + wm_input_device_change_count = 0; + + raw_devices[0].usUsagePage = HID_USAGE_PAGE_GENERIC; + raw_devices[0].usUsage = HID_USAGE_GENERIC_JOYSTICK; + raw_devices[0].dwFlags = RIDEV_INPUTSINK; + raw_devices[0].hwndTarget = hwnd; + count = ARRAY_SIZE(raw_devices); + ret = RegisterRawInputDevices( raw_devices, 1, sizeof(RAWINPUTDEVICE) ); + ok( ret, "RegisterRawInputDevices failed, error %lu\n", GetLastError() ); + + hid_device_stop( &desc ); + hid_device_start( &desc ); + + while (PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + ok( !wm_input_device_change_count, "got %u WM_INPUT_DEVICE_CHANGE\n", wm_input_device_change_count ); + ok( !wm_input_count, "got %u WM_INPUT\n", wm_input_count ); + + + count = ARRAY_SIZE(raw_device_list); + res = GetRawInputDeviceList( raw_device_list, &count, sizeof(RAWINPUTDEVICELIST) ); + todo_wine + ok( res == device_count + 1, "GetRawInputDeviceList returned %lu\n", res ); + ok( count == ARRAY_SIZE(raw_device_list), "got count %u\n", count ); + device_count = res; + + while (device_count--) + { + if (raw_device_list[device_count].dwType != RIM_TYPEHID) continue; + + count = ARRAY_SIZE(path); + res = GetRawInputDeviceInfoW( raw_device_list[device_count].hDevice, RIDI_DEVICENAME, path, &count ); + ok( res == wcslen( path ) + 1, "GetRawInputDeviceInfoW returned %lu\n", res ); + todo_wine + ok( count == ARRAY_SIZE(path), "got count %u\n", count ); + + if (wcsstr( path, expect_vidpid_str )) break; + } + + todo_wine + ok( !!wcsstr( path, expect_vidpid_str ), "got path %s\n", debugstr_w(path) ); + if (!wcsstr( path, expect_vidpid_str )) goto done; + + + file = CreateFileW( path, FILE_READ_ACCESS | FILE_WRITE_ACCESS, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, + FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, NULL ); + ok( file != INVALID_HANDLE_VALUE, "got error %lu\n", GetLastError() ); + + for (i = 0; i < ARRAY_SIZE(injected_input); ++i) + { + winetest_push_context( "state[%ld]", i ); + + send_hid_input( file, &injected_input[i], sizeof(*injected_input) ); + + MsgWaitForMultipleObjects( 0, NULL, FALSE, INFINITE, QS_ALLINPUT ); + while (PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE )) DispatchMessageW( &msg ); + + ok( !wm_input_device_change_count, "got %u WM_INPUT_DEVICE_CHANGE\n", wm_input_device_change_count ); + todo_wine + ok( wm_input_count == 1, "got %u WM_INPUT\n", wm_input_count ); + todo_wine + ok( wm_input_len == offsetof(RAWINPUT, data.hid.bRawData[desc.caps.InputReportByteLength]), + "got wm_input_len %u\n", wm_input_len ); + todo_wine + ok( !memcmp( rawinput->data.hid.bRawData, injected_input[i].report_buf, desc.caps.InputReportByteLength ), + "got unexpected report data\n" ); + wm_input_count = 0; + + winetest_pop_context(); + } + + CloseHandle( file ); + +done: + hid_device_stop( &desc ); + cleanup_registry_keys(); + + DestroyWindow( hwnd ); + UnregisterClassW( class.lpszClassName, class.hInstance ); +} + START_TEST( joystick8 ) { dinput_test_init(); @@ -4121,6 +4389,7 @@ START_TEST( joystick8 )
test_many_axes_joystick(); test_driving_wheel_axes(); + test_rawinput(); test_windows_gaming_input(); }
From: R��mi Bernon rbernon@codeweavers.com
--- dlls/win32u/rawinput.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-)
diff --git a/dlls/win32u/rawinput.c b/dlls/win32u/rawinput.c index 81403771c4a..6a018e15bb7 100644 --- a/dlls/win32u/rawinput.c +++ b/dlls/win32u/rawinput.c @@ -244,9 +244,9 @@ static struct device *add_device( HKEY key, DWORD type ) static const RID_DEVICE_INFO_MOUSE mouse_info = {1, 5, 0, FALSE}; struct hid_preparsed_data *preparsed = NULL; HID_COLLECTION_INFORMATION hid_info; - struct device *device = NULL; OBJECT_ATTRIBUTES attr; UNICODE_STRING string; + struct device *device; RID_DEVICE_INFO info; IO_STATUS_BLOCK io; WCHAR *path, *pos; @@ -292,6 +292,15 @@ static struct device *add_device( HKEY key, DWORD type ) goto fail; }
+ for (i = 0; i < rawinput_devices_count; ++i) + { + if (rawinput_devices[i].handle == UlongToHandle(handle)) + { + TRACE( "Ignoring already added device %#x / %s.\n", handle, debugstr_w(path) ); + goto fail; + } + } + memset( &info, 0, sizeof(info) ); info.cbSize = sizeof(info); info.dwType = type; @@ -340,20 +349,7 @@ static struct device *add_device( HKEY key, DWORD type ) break; }
- for (i = 0; i < rawinput_devices_count && !device; ++i) - { - if (rawinput_devices[i].handle == UlongToHandle(handle)) - device = rawinput_devices + i; - } - - if (device) - { - TRACE( "Updating device %#x / %s.\n", handle, debugstr_w(path) ); - free( device->data ); - NtClose( device->file ); - free( device->path ); - } - else if (array_reserve( (void **)&rawinput_devices, &rawinput_devices_max, + if (array_reserve( (void **)&rawinput_devices, &rawinput_devices_max, rawinput_devices_count + 1, sizeof(*rawinput_devices) )) { device = &rawinput_devices[rawinput_devices_count++]; @@ -461,9 +457,9 @@ static void rawinput_update_device_list(void) } rawinput_devices_count = 0;
- enumerate_devices( RIM_TYPEHID, guid_devinterface_hidW ); enumerate_devices( RIM_TYPEMOUSE, guid_devinterface_mouseW ); enumerate_devices( RIM_TYPEKEYBOARD, guid_devinterface_keyboardW ); + enumerate_devices( RIM_TYPEHID, guid_devinterface_hidW );
pthread_mutex_unlock( &rawinput_devices_mutex ); }
From: R��mi Bernon rbernon@codeweavers.com
--- dlls/dinput/tests/joystick8.c | 11 +++++------ dlls/win32u/rawinput.c | 20 +++++++++++++++++--- 2 files changed, 22 insertions(+), 9 deletions(-)
diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index 3193ee12ddc..8f6d386c952 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -4308,7 +4308,11 @@ static void test_rawinput(void)
count = ARRAY_SIZE(raw_device_list); res = GetRawInputDeviceList( raw_device_list, &count, sizeof(RAWINPUTDEVICELIST) ); - todo_wine + if (!strcmp( winetest_platform, "wine" ) && res == device_count) + { + Sleep( 2500 ); /* Wine only refreshes device list every 2s */ + res = GetRawInputDeviceList( raw_device_list, &count, sizeof(RAWINPUTDEVICELIST) ); + } ok( res == device_count + 1, "GetRawInputDeviceList returned %lu\n", res ); ok( count == ARRAY_SIZE(raw_device_list), "got count %u\n", count ); device_count = res; @@ -4326,9 +4330,7 @@ static void test_rawinput(void) if (wcsstr( path, expect_vidpid_str )) break; }
- todo_wine ok( !!wcsstr( path, expect_vidpid_str ), "got path %s\n", debugstr_w(path) ); - if (!wcsstr( path, expect_vidpid_str )) goto done;
file = CreateFileW( path, FILE_READ_ACCESS | FILE_WRITE_ACCESS, @@ -4346,12 +4348,9 @@ static void test_rawinput(void) while (PeekMessageW( &msg, hwnd, 0, 0, PM_REMOVE )) DispatchMessageW( &msg );
ok( !wm_input_device_change_count, "got %u WM_INPUT_DEVICE_CHANGE\n", wm_input_device_change_count ); - todo_wine ok( wm_input_count == 1, "got %u WM_INPUT\n", wm_input_count ); - todo_wine ok( wm_input_len == offsetof(RAWINPUT, data.hid.bRawData[desc.caps.InputReportByteLength]), "got wm_input_len %u\n", wm_input_len ); - todo_wine ok( !memcmp( rawinput->data.hid.bRawData, injected_input[i].report_buf, desc.caps.InputReportByteLength ), "got unexpected report data\n" ); wm_input_count = 0; diff --git a/dlls/win32u/rawinput.c b/dlls/win32u/rawinput.c index 6a018e15bb7..e59c93898c2 100644 --- a/dlls/win32u/rawinput.c +++ b/dlls/win32u/rawinput.c @@ -253,6 +253,8 @@ static struct device *add_device( HKEY key, DWORD type ) NTSTATUS status; unsigned int i; UINT32 handle; + void *buffer; + SIZE_T size; HANDLE file;
if (!query_reg_value( key, symbolic_linkW, value, sizeof(value_buffer) )) @@ -327,9 +329,21 @@ static struct device *add_device( HKEY key, DWORD type ) goto fail; }
- status = NtDeviceIoControlFile( file, NULL, NULL, NULL, &io, - IOCTL_HID_GET_COLLECTION_DESCRIPTOR, - NULL, 0, preparsed, hid_info.DescriptorSize ); + /* NtDeviceIoControlFile checks that the output buffer is writable using ntdll virtual + * memory protection information, we need an NtAllocateVirtualMemory allocated buffer. + */ + size = hid_info.DescriptorSize; + if (!(status = NtAllocateVirtualMemory( GetCurrentProcess(), (void **)&buffer, 0, &size, + MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE ))) + { + size = 0; + status = NtDeviceIoControlFile( file, NULL, NULL, NULL, &io, + IOCTL_HID_GET_COLLECTION_DESCRIPTOR, + NULL, 0, buffer, hid_info.DescriptorSize ); + if (!status) memcpy( preparsed, buffer, hid_info.DescriptorSize ); + NtFreeVirtualMemory( GetCurrentProcess(), (void **)&buffer, &size, MEM_RELEASE ); + } + if (status) { ERR( "Failed to get collection descriptor, status %#x.\n", status );
From: R��mi Bernon rbernon@codeweavers.com
--- dlls/win32u/rawinput.c | 48 +++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 17 deletions(-)
diff --git a/dlls/win32u/rawinput.c b/dlls/win32u/rawinput.c index e59c93898c2..cbf91a9facb 100644 --- a/dlls/win32u/rawinput.c +++ b/dlls/win32u/rawinput.c @@ -206,7 +206,7 @@ struct device static struct device *rawinput_devices; static unsigned int rawinput_devices_count, rawinput_devices_max;
-static pthread_mutex_t rawinput_devices_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t rawinput_mutex = PTHREAD_MUTEX_INITIALIZER;
static bool array_reserve( void **elements, unsigned int *capacity, unsigned int count, unsigned int size ) { @@ -460,8 +460,6 @@ static void rawinput_update_device_list(void)
TRACE( "\n" );
- pthread_mutex_lock( &rawinput_devices_mutex ); - /* destroy previous list */ for (i = 0; i < rawinput_devices_count; ++i) { @@ -474,8 +472,6 @@ static void rawinput_update_device_list(void) enumerate_devices( RIM_TYPEMOUSE, guid_devinterface_mouseW ); enumerate_devices( RIM_TYPEKEYBOARD, guid_devinterface_keyboardW ); enumerate_devices( RIM_TYPEHID, guid_devinterface_hidW ); - - pthread_mutex_unlock( &rawinput_devices_mutex ); }
static struct device *find_device_from_handle( HANDLE handle ) @@ -502,14 +498,19 @@ BOOL rawinput_device_get_usages( HANDLE handle, USAGE *usage_page, USAGE *usage { struct device *device;
- *usage_page = *usage = 0; + pthread_mutex_lock( &rawinput_mutex ); + + if (!(device = find_device_from_handle( handle )) || device->info.dwType != RIM_TYPEHID) + *usage_page = *usage = 0; + else + { + *usage_page = device->info.hid.usUsagePage; + *usage = device->info.hid.usUsage; + }
- if (!(device = find_device_from_handle( handle ))) return FALSE; - if (device->info.dwType != RIM_TYPEHID) return FALSE; + pthread_mutex_unlock( &rawinput_mutex );
- *usage_page = device->info.hid.usUsagePage; - *usage = device->info.hid.usUsage; - return TRUE; + return *usage_page || *usage; }
/********************************************************************** @@ -534,12 +535,16 @@ UINT WINAPI NtUserGetRawInputDeviceList( RAWINPUTDEVICELIST *devices, UINT *devi return ~0u; }
+ pthread_mutex_lock( &rawinput_mutex ); + if (ticks - last_check > 2000) { last_check = ticks; rawinput_update_device_list(); }
+ pthread_mutex_unlock( &rawinput_mutex ); + if (!devices) { *device_count = rawinput_devices_count; @@ -579,13 +584,23 @@ UINT WINAPI NtUserGetRawInputDeviceInfo( HANDLE handle, UINT command, void *data SetLastError( ERROR_NOACCESS ); return ~0u; } + if (command != RIDI_DEVICENAME && command != RIDI_DEVICEINFO && command != RIDI_PREPARSEDDATA) + { + FIXME( "Command %#x not implemented!\n", command ); + SetLastError( ERROR_INVALID_PARAMETER ); + return ~0u; + } + + pthread_mutex_lock( &rawinput_mutex ); + if (!(device = find_device_from_handle( handle ))) { + pthread_mutex_unlock( &rawinput_mutex ); SetLastError( ERROR_INVALID_HANDLE ); return ~0u; }
- data_len = *data_size; + len = data_len = *data_size; switch (command) { case RIDI_DEVICENAME: @@ -611,13 +626,10 @@ UINT WINAPI NtUserGetRawInputDeviceInfo( HANDLE handle, UINT command, void *data memcpy( data, preparsed, len ); *data_size = len; break; - - default: - FIXME( "command %#x not supported\n", command ); - SetLastError( ERROR_INVALID_PARAMETER ); - return ~0u; }
+ pthread_mutex_unlock( &rawinput_mutex ); + if (!data) return 0;
@@ -795,7 +807,9 @@ BOOL process_rawinput_message( MSG *msg, UINT hw_id, const struct hardware_msg_d
if (msg->message == WM_INPUT_DEVICE_CHANGE) { + pthread_mutex_lock( &rawinput_mutex ); rawinput_update_device_list(); + pthread_mutex_unlock( &rawinput_mutex ); } else {
v2: Use a temporary virtual memory buffer instead of keeping entire pages allocated, add a comment.