This seems to be relied on by some versions of [this Unreal Engine input plugin](https://www.unrealengine.com/marketplace/en-US/product/wm-input-manager)
Note: I'm not sure how to deal with `HID_USAGE_GENERIC_KEYPAD`, which (I think) would fall under `RIM_TYPEKEYBOARD`. Do we need to store extra info to differentiate these from `HID_USAGE_GENERIC_KEYBOARD` or is there something in the device info struct that can differentiate them?
From: Evan Tang etang@codeweavers.com
Windows sends a WM_INPUT_DEVICE_CHANGE for every matching connected device on registration --- dlls/user32/tests/input.c | 38 +++++++++++++++++++++++++++----- dlls/win32u/rawinput.c | 46 +++++++++++++++++++++++++++++++-------- 2 files changed, 69 insertions(+), 15 deletions(-)
diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index f8b40099091..eb6419d7122 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -2108,7 +2108,9 @@ static void test_RegisterRawInputDevices(void) DestroyWindow(hwnd); }
-static int rawinputbuffer_wndproc_count; +static int rawinputbuffer_wndproc_wm_input_count; +static int rawinputbuffer_wndproc_wm_input_device_change_count; +static int rawinputbuffer_wndproc_other_msg_count;
typedef struct { @@ -2149,7 +2151,7 @@ static int rawinput_buffer_mouse_x(void *buffer, size_t index)
static LRESULT CALLBACK rawinputbuffer_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { - UINT i, size, count, rawinput_size, iteration = rawinputbuffer_wndproc_count++; + UINT i, size, count, rawinput_size; RAWINPUT ri; char buffer[16 * sizeof(RAWINPUT64)]; MSG message; @@ -2159,6 +2161,8 @@ static LRESULT CALLBACK rawinputbuffer_wndproc(HWND hwnd, UINT msg, WPARAM wpara
if (msg == WM_INPUT) { + UINT iteration = rawinputbuffer_wndproc_wm_input_count++; + SetLastError(0xdeadbeef); count = GetRawInputBuffer(NULL, NULL, sizeof(RAWINPUTHEADER)); ok(count == ~0U, "GetRawInputBuffer succeeded\n"); @@ -2290,19 +2294,39 @@ static LRESULT CALLBACK rawinputbuffer_wndproc(HWND hwnd, UINT msg, WPARAM wpara
return 0; } + else if (msg == WM_INPUT_DEVICE_CHANGE) + { + ok(rawinputbuffer_wndproc_wm_input_count == 0, "device change event came after input event\n"); + rawinputbuffer_wndproc_wm_input_device_change_count++; + } + else + { + rawinputbuffer_wndproc_other_msg_count++; + }
return DefWindowProcA(hwnd, msg, wparam, lparam); }
static void test_GetRawInputBuffer(void) { - unsigned int size, count, rawinput_size, header_size, scan_code; + unsigned int i, size, count, rawinput_size, header_size, scan_code, num_mice = 0; RAWINPUTDEVICE raw_devices[1]; + RAWINPUTDEVICELIST *raw_device_list; char buffer[16 * sizeof(RAWINPUT64)]; HWND hwnd; BOOL ret; POINT pt;
+ GetRawInputDeviceList(NULL, &count, sizeof(RAWINPUTDEVICELIST)); + raw_device_list = malloc(sizeof(RAWINPUTDEVICELIST) * count); + GetRawInputDeviceList(raw_device_list, &count, sizeof(RAWINPUTDEVICELIST)); + for (i = 0; i < count; i++) + { + if (raw_device_list[i].dwType == RIM_TYPEMOUSE) + num_mice++; + } + free(raw_device_list); + #define HEADER_FIELD(field) (is_wow64 ? ((RAWINPUT64 *)buffer)->header.field : ((RAWINPUT *)buffer)->header.field)
if (is_wow64) rawinput_size = sizeof(RAWINPUT64); @@ -2320,7 +2344,7 @@ static void test_GetRawInputBuffer(void)
raw_devices[0].usUsagePage = 0x01; raw_devices[0].usUsage = 0x02; - raw_devices[0].dwFlags = RIDEV_INPUTSINK; + raw_devices[0].dwFlags = RIDEV_INPUTSINK | RIDEV_DEVNOTIFY; raw_devices[0].hwndTarget = hwnd;
SetLastError(0xdeadbeef); @@ -2416,13 +2440,15 @@ static void test_GetRawInputBuffer(void) ok(count == 0U, "GetRawInputBuffer returned %u\n", count);
- rawinputbuffer_wndproc_count = 0; + rawinputbuffer_wndproc_wm_input_count = 0; + rawinputbuffer_wndproc_wm_input_device_change_count = 0; mouse_event(MOUSEEVENTF_MOVE, 1, 0, 0, 0); mouse_event(MOUSEEVENTF_MOVE, 2, 0, 0, 0); mouse_event(MOUSEEVENTF_MOVE, 3, 0, 0, 0); mouse_event(MOUSEEVENTF_MOVE, 4, 0, 0, 0); empty_message_queue(); - ok(rawinputbuffer_wndproc_count == 2, "Spurious WM_INPUT messages\n"); + ok(rawinputbuffer_wndproc_wm_input_count == 2, "Spurious WM_INPUT messages\n"); + ok(rawinputbuffer_wndproc_wm_input_device_change_count == num_mice, "Got %d WM_INPUT_DEVICE_CHANGE messages (expected %d)\n", rawinputbuffer_wndproc_wm_input_device_change_count, num_mice);
raw_devices[0].dwFlags = RIDEV_REMOVE; raw_devices[0].hwndTarget = 0; diff --git a/dlls/win32u/rawinput.c b/dlls/win32u/rawinput.c index 1ddbca0896a..2240237b378 100644 --- a/dlls/win32u/rawinput.c +++ b/dlls/win32u/rawinput.c @@ -828,7 +828,7 @@ static void register_rawinput_device( const RAWINPUTDEVICE *device ) /********************************************************************** * NtUserRegisterRawInputDevices (win32u.@) */ -BOOL WINAPI NtUserRegisterRawInputDevices( const RAWINPUTDEVICE *devices, UINT device_count, UINT device_size ) +BOOL WINAPI NtUserRegisterRawInputDevices( const RAWINPUTDEVICE *device_list, UINT device_count, UINT device_size ) { struct rawinput_device *server_devices; RAWINPUTDEVICE *new_registered_devices; @@ -836,7 +836,7 @@ BOOL WINAPI NtUserRegisterRawInputDevices( const RAWINPUTDEVICE *devices, UINT d BOOL ret; UINT i;
- TRACE( "devices %p, device_count %u, device_size %u.\n", devices, device_count, device_size ); + TRACE( "devices %p, device_count %u, device_size %u.\n", device_list, device_count, device_size );
if (device_size != sizeof(RAWINPUTDEVICE)) { @@ -846,23 +846,23 @@ BOOL WINAPI NtUserRegisterRawInputDevices( const RAWINPUTDEVICE *devices, UINT d
for (i = 0; i < device_count; ++i) { - TRACE( "device %u: page %#x, usage %#x, flags %#x, target %p.\n", i, devices[i].usUsagePage, - devices[i].usUsage, (int)devices[i].dwFlags, devices[i].hwndTarget ); + TRACE( "device %u: page %#x, usage %#x, flags %#x, target %p.\n", i, device_list[i].usUsagePage, + device_list[i].usUsage, (int)device_list[i].dwFlags, device_list[i].hwndTarget );
- if ((devices[i].dwFlags & RIDEV_INPUTSINK) && !devices[i].hwndTarget) + if ((device_list[i].dwFlags & RIDEV_INPUTSINK) && !device_list[i].hwndTarget) { RtlSetLastWin32Error( ERROR_INVALID_PARAMETER ); return FALSE; }
- if ((devices[i].dwFlags & RIDEV_REMOVE) && devices[i].hwndTarget) + if ((device_list[i].dwFlags & RIDEV_REMOVE) && device_list[i].hwndTarget) { RtlSetLastWin32Error( ERROR_INVALID_PARAMETER ); return FALSE; }
- if (devices[i].dwFlags & ~(RIDEV_REMOVE|RIDEV_NOLEGACY|RIDEV_INPUTSINK|RIDEV_DEVNOTIFY)) - FIXME( "Unhandled flags %#x for device %u.\n", (int)devices[i].dwFlags, i ); + if (device_list[i].dwFlags & ~(RIDEV_REMOVE|RIDEV_NOLEGACY|RIDEV_INPUTSINK|RIDEV_DEVNOTIFY)) + FIXME( "Unhandled flags %#x for device %u.\n", (int)device_list[i].dwFlags, i ); }
pthread_mutex_lock( &rawinput_mutex ); @@ -882,7 +882,7 @@ BOOL WINAPI NtUserRegisterRawInputDevices( const RAWINPUTDEVICE *devices, UINT d }
registered_devices = new_registered_devices; - for (i = 0; i < device_count; ++i) register_rawinput_device( devices + i ); + for (i = 0; i < device_count; ++i) register_rawinput_device( device_list + i );
if (!(device_count = registered_device_count)) server_devices = NULL; else if (!(server_devices = malloc( device_count * sizeof(*server_devices) ))) @@ -909,6 +909,34 @@ BOOL WINAPI NtUserRegisterRawInputDevices( const RAWINPUTDEVICE *devices, UINT d
free( server_devices );
+ if (ret) + { + // Send WM_INPUT_DEVICE_CHANGE for existing devices when registering for notifications + for (i = 0; i < device_count; ++i) + { + HWND hwnd = device_list[i].hwndTarget; + USHORT page = device_list[i].usUsagePage, usage = device_list[i].usUsage; + struct device *device; + if (!(device_list[i].dwFlags & RIDEV_DEVNOTIFY) || !hwnd) + continue; + + rawinput_update_device_list(); + LIST_FOR_EACH_ENTRY(device, &devices, struct device, entry) + { + BOOL matches = FALSE; + if (device->info.dwType == RIM_TYPEMOUSE) + matches = page == HID_USAGE_PAGE_GENERIC && usage == HID_USAGE_GENERIC_MOUSE; + else if (device->info.dwType == RIM_TYPEKEYBOARD) + matches = page == HID_USAGE_PAGE_GENERIC && usage == HID_USAGE_GENERIC_KEYBOARD; + else if (device->info.dwType == RIM_TYPEHID) + matches = page == device->info.hid.usUsagePage && usage == device->info.hid.usUsage; + + if (matches) + NtUserPostMessage(hwnd, WM_INPUT_DEVICE_CHANGE, GIDC_ARRIVAL, (LPARAM)device->handle); + } + } + } + pthread_mutex_unlock( &rawinput_mutex );
return ret;
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=129140
Your paranoid android.
=== w7u_2qxl (32 bit report) ===
user32: input.c:2367: Test failed: GetRawInputBuffer returned 4294967295
=== w7u_adm (32 bit report) ===
user32: input.c:2367: Test failed: GetRawInputBuffer returned 4294967295
=== w7u_el (32 bit report) ===
user32: input.c:2367: Test failed: GetRawInputBuffer returned 4294967295
=== w8 (32 bit report) ===
user32: input.c:2367: Test failed: GetRawInputBuffer returned 4294967295
=== w8adm (32 bit report) ===
user32: input.c:2367: Test failed: GetRawInputBuffer returned 4294967295
=== w864 (32 bit report) ===
user32: input.c:2367: Test failed: GetRawInputBuffer returned 4294967295
=== w1064v1507 (32 bit report) ===
user32: input.c:2367: Test failed: GetRawInputBuffer returned 4294967295
=== w1064v1809 (32 bit report) ===
user32: input.c:2367: Test failed: GetRawInputBuffer returned 4294967295
=== w1064_tsign (32 bit report) ===
user32: input.c:2367: Test failed: GetRawInputBuffer returned 4294967295
=== w10pro64 (32 bit report) ===
user32: input.c:2367: Test failed: GetRawInputBuffer returned 4294967295
=== w864 (64 bit report) ===
user32: input.c:2367: Test failed: GetRawInputBuffer returned 4294967295
=== w1064v1507 (64 bit report) ===
user32: input.c:2367: Test failed: GetRawInputBuffer returned 4294967295
=== w1064v1809 (64 bit report) ===
user32: input.c:2367: Test failed: GetRawInputBuffer returned 4294967295
=== w1064_2qxl (64 bit report) ===
user32: input.c:2367: Test failed: GetRawInputBuffer returned 4294967295
=== w1064_adm (64 bit report) ===
user32: input.c:2367: Test failed: GetRawInputBuffer returned 4294967295
=== w1064_tsign (64 bit report) ===
user32: input.c:2367: Test failed: GetRawInputBuffer returned 4294967295
=== w10pro64 (64 bit report) ===
user32: input.c:2367: Test failed: GetRawInputBuffer returned 4294967295
=== w10pro64_en_AE_u8 (64 bit report) ===
user32: input.c:2367: Test failed: GetRawInputBuffer returned 4294967295
=== w10pro64_ar (64 bit report) ===
user32: input.c:2367: Test failed: GetRawInputBuffer returned 4294967295
=== w10pro64_ja (64 bit report) ===
user32: input.c:2367: Test failed: GetRawInputBuffer returned 4294967295
=== w10pro64_zh_CN (64 bit report) ===
user32: input.c:2367: Test failed: GetRawInputBuffer returned 4294967295