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;