Another thread is created to execute the tests, for SetThreadDesktop to succeed consistently. It seems to fail spuriously if it is called from a thread that already created some windows before.
This shows that rawinput messages may be dispatched across desktops, but only if the subscribing process has a window in the input desktop, and it is the foreground process (even if the target window may be in another desktop).
Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
v4: What v3 should have been, queue_rawinput_message really simplified now, the only logic kept is here to implement RIDEV_INPUTSINK, although it will also be useful in the future, to dispatch HID rawinput from the winedevice processes.
dlls/user32/tests/input.c | 119 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 113 insertions(+), 6 deletions(-)
diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index 9ec829860af..01733317b2b 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -50,6 +50,7 @@
#include "windef.h" #include "winbase.h" +#include "wingdi.h" #include "winuser.h" #include "winnls.h" #include "ddk/hidsdi.h" @@ -60,6 +61,8 @@ static HWND hWndTest; static LONG timetag = 0x10000000;
+#define DESKTOP_ALL_ACCESS 0x01ff + static struct { LONG last_key_down; LONG last_key_up; @@ -1891,6 +1894,11 @@ struct rawinput_test rawinput_tests[] =
{ TRUE, TRUE, RIDEV_EXINPUTSINK, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, { TRUE, TRUE, RIDEV_EXINPUTSINK, FALSE, TRUE, FALSE, /* todos: */ FALSE, TRUE, FALSE }, + + /* cross-desktop foreground tests */ + { TRUE, FALSE, 0, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, + { TRUE, TRUE, 0, FALSE, TRUE, TRUE, /* todos: */ FALSE, FALSE, FALSE }, + { TRUE, TRUE, RIDEV_INPUTSINK, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, };
static void rawinput_test_process(void) @@ -1927,6 +1935,7 @@ static void rawinput_test_process(void) case 11: case 12: case 13: + case 16: GetCursorPos(&pt);
hwnd = CreateWindowA("static", "static", WS_VISIBLE | WS_POPUP, @@ -1960,6 +1969,9 @@ static void rawinput_test_process(void) rawinput_test_received_raw = FALSE; rawinput_test_received_rawfg = FALSE;
+ /* fallthrough */ + case 14: + case 15: if (i != 8) mouse_event(MOUSEEVENTF_MOVE, 5, 0, 0, 0); empty_message_queue(); break; @@ -1998,19 +2010,87 @@ static void rawinput_test_process(void)
struct rawinput_test_thread_params { + HDESK desk; HANDLE ready; HANDLE start; HANDLE done; };
+static DWORD WINAPI rawinput_test_desk_thread(void *arg) +{ + struct rawinput_test_thread_params *params = arg; + RAWINPUTDEVICE raw_devices[1]; + DWORD ret; + POINT pt; + HWND hwnd = NULL; + MSG msg; + int i; + + ok( SetThreadDesktop( params->desk ), "SetThreadDesktop failed\n" ); + + for (i = 14; i < ARRAY_SIZE(rawinput_tests); ++i) + { + WaitForSingleObject(params->ready, INFINITE); + ResetEvent(params->ready); + + switch (i) + { + case 14: + case 15: + case 16: + GetCursorPos(&pt); + + hwnd = CreateWindowA("static", "static", WS_VISIBLE | WS_POPUP, + pt.x - 50, pt.y - 50, 100, 100, 0, NULL, NULL, NULL); + ok(hwnd != 0, "CreateWindow failed\n"); + SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)rawinput_wndproc); + empty_message_queue(); + + /* FIXME: Try to workaround X11/Win32 focus inconsistencies and + * make the window visible and foreground as hard as possible. */ + ShowWindow(hwnd, SW_SHOW); + SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE); + SetForegroundWindow(hwnd); + UpdateWindow(hwnd); + empty_message_queue(); + + raw_devices[0].usUsagePage = 0x01; + raw_devices[0].usUsage = 0x02; + raw_devices[0].dwFlags = rawinput_tests[i].register_flags; + raw_devices[0].hwndTarget = rawinput_tests[i].register_window ? hwnd : 0; + + rawinput_test_received_legacy = FALSE; + rawinput_test_received_raw = FALSE; + rawinput_test_received_rawfg = FALSE; + + SetLastError(0xdeadbeef); + ret = RegisterRawInputDevices(raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE)); + ok(ret, "%d: RegisterRawInputDevices failed\n", i); + ok(GetLastError() == 0xdeadbeef, "%d: RegisterRawInputDevices returned %08x\n", i, GetLastError()); + break; + } + + SetEvent(params->start); + + while (MsgWaitForMultipleObjects(1, ¶ms->done, FALSE, INFINITE, QS_ALLINPUT) != WAIT_OBJECT_0) + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); + + ResetEvent(params->done); + if (hwnd) DestroyWindow(hwnd); + } + + return 0; +} + static DWORD WINAPI rawinput_test_thread(void *arg) { struct rawinput_test_thread_params *params = arg; + HANDLE thread; POINT pt; HWND hwnd = NULL; int i;
- for (i = 0; i < ARRAY_SIZE(rawinput_tests); ++i) + for (i = 0; i < 14; ++i) { WaitForSingleObject(params->ready, INFINITE); ResetEvent(params->ready); @@ -2046,6 +2126,11 @@ static DWORD WINAPI rawinput_test_thread(void *arg) if (hwnd) DestroyWindow(hwnd); }
+ thread = CreateThread(NULL, 0, rawinput_test_desk_thread, params, 0, NULL); + ok(thread != NULL, "CreateThread failed\n"); + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); + return 0; }
@@ -2063,6 +2148,9 @@ static void test_rawinput(const char* argv0) char path[MAX_PATH]; int i;
+ params.desk = CreateDesktopA( "rawinput_test_desktop", NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL ); + ok( params.desk != NULL, "CreateDesktopA failed, last error: %u\n", GetLastError() ); + params.ready = CreateEventA(NULL, FALSE, FALSE, NULL); ok(params.ready != NULL, "CreateEvent failed\n");
@@ -2103,7 +2191,8 @@ static void test_rawinput(const char* argv0) hwnd = CreateWindowA("static", "static", WS_VISIBLE | WS_POPUP, pt.x - 50, pt.y - 50, 100, 100, 0, NULL, NULL, NULL); ok(hwnd != 0, "CreateWindow failed\n"); - SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)rawinput_wndproc); + if (i != 14 && i != 15 && i != 16) + SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)rawinput_wndproc); empty_message_queue();
/* FIXME: Try to workaround X11/Win32 focus inconsistencies and @@ -2135,14 +2224,30 @@ static void test_rawinput(const char* argv0) ok(!skipped, "%d: RegisterRawInputDevices failed: %u\n", i, GetLastError()); }
- SetEvent(process_ready); - WaitForSingleObject(process_start, INFINITE); - ResetEvent(process_start); - SetEvent(params.ready); WaitForSingleObject(params.start, INFINITE); ResetEvent(params.start);
+ /* we need the main window to be over the other thread window, as although + * it is in another desktop, it will receive the messages directly otherwise */ + switch (i) + { + case 14: + case 15: + SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE); + SetForegroundWindow(hwnd); + empty_message_queue(); + + rawinput_test_received_legacy = FALSE; + rawinput_test_received_raw = FALSE; + rawinput_test_received_rawfg = FALSE; + break; + } + + SetEvent(process_ready); + WaitForSingleObject(process_start, INFINITE); + ResetEvent(process_start); + if (i <= 3 || i == 8) mouse_event(MOUSEEVENTF_MOVE, 5, 0, 0, 0); empty_message_queue();
@@ -2192,6 +2297,8 @@ static void test_rawinput(const char* argv0) CloseHandle(params.start); CloseHandle(params.ready); CloseHandle(thread); + + CloseDesktop(params.desk); }
static void test_key_map(void)
This delivers the rawinput messages to the correct process, regardless of where the input was received.
As for now RIDEV_INPUTSINK is still not implemented, this only fixes the case where input is injected in a background process and where it should not receive rawinput -as in the test- or when cursor moves over a background window and the foreground process should have received rawinput messages.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/user32/tests/input.c | 2 +- server/queue.c | 85 ++++++++++++++++++++++++++++++--------- 2 files changed, 67 insertions(+), 20 deletions(-)
diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index 01733317b2b..6f1fa9b3e9c 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -1885,7 +1885,7 @@ struct rawinput_test rawinput_tests[] = /* cross-process foreground tests */ { TRUE, TRUE, 0, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, { TRUE, TRUE, RIDEV_INPUTSINK, FALSE, TRUE, FALSE, /* todos: */ FALSE, TRUE, FALSE }, - { TRUE, TRUE, 0, FALSE, FALSE, FALSE, /* todos: */ FALSE, TRUE, TRUE }, + { TRUE, TRUE, 0, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE },
/* multi-process rawinput tests */ { TRUE, TRUE, 0, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, diff --git a/server/queue.c b/server/queue.c index 84ee0f9a4ea..d7840cd7150 100644 --- a/server/queue.c +++ b/server/queue.c @@ -1596,13 +1596,58 @@ static int send_hook_ll_message( struct desktop *desktop, struct message *hardwa return 1; }
+/* get the foreground thread for a desktop and a window receiving input */ +static struct thread *get_foreground_thread( struct desktop *desktop, user_handle_t window ) +{ + /* if desktop has no foreground process, assume the receiving window is */ + if (desktop->foreground_input) return get_window_thread( desktop->foreground_input->focus ); + if (window) return get_window_thread( get_user_full_handle( window ) ); + return NULL; +} + +struct rawinput_message +{ + struct thread *foreground; + struct desktop *desktop; + struct hw_msg_source source; + unsigned int time; + struct hardware_msg_data data; +}; + +/* check if process is supposed to receive a WM_INPUT message and eventually queue it */ +static int queue_rawinput_message( struct process* process, void *arg ) +{ + const struct rawinput_message* raw_msg = arg; + const struct rawinput_device *device = NULL; + struct message *msg; + + if (raw_msg->data.rawinput.type == RIM_TYPEMOUSE) + device = process->rawinput_mouse; + else if (raw_msg->data.rawinput.type == RIM_TYPEKEYBOARD) + device = process->rawinput_kbd; + if (!device) return 0; + + if (!(msg = alloc_hardware_message( raw_msg->data.info, raw_msg->source, raw_msg->time ))) + return 0; + + msg->win = device->target; + msg->msg = WM_INPUT; + msg->wparam = RIM_INPUT; + msg->lparam = 0; + memcpy( msg->data, &raw_msg->data, sizeof(raw_msg->data) ); + + queue_hardware_message( raw_msg->desktop, msg, 1 ); + return 0; +} + /* queue a hardware message for a mouse event */ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input, unsigned int origin, struct msg_queue *sender ) { - const struct rawinput_device *device; struct hardware_msg_data *msg_data; + struct rawinput_message raw_msg; struct message *msg; + struct thread *foreground; unsigned int i, time, flags; struct hw_msg_source source = { IMDT_MOUSE, origin }; int wait = 0, x, y; @@ -1651,23 +1696,23 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons y = desktop->cursor.y; }
- if ((device = current->process->rawinput_mouse)) + if ((foreground = get_foreground_thread( desktop, win ))) { - if (!(msg = alloc_hardware_message( input->mouse.info, source, time ))) return 0; - msg_data = msg->data; - - msg->win = device->target; - msg->msg = WM_INPUT; - msg->wparam = RIM_INPUT; - msg->lparam = 0; + raw_msg.foreground = foreground; + raw_msg.desktop = desktop; + raw_msg.source = source; + raw_msg.time = time;
+ msg_data = &raw_msg.data; + msg_data->info = input->mouse.info; msg_data->flags = flags; msg_data->rawinput.type = RIM_TYPEMOUSE; msg_data->rawinput.mouse.x = x - desktop->cursor.x; msg_data->rawinput.mouse.y = y - desktop->cursor.y; msg_data->rawinput.mouse.data = input->mouse.data;
- queue_hardware_message( desktop, msg, 0 ); + queue_rawinput_message( foreground->process, &raw_msg ); + release_object( foreground ); }
for (i = 0; i < ARRAY_SIZE( messages ); i++) @@ -1704,9 +1749,10 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c unsigned int origin, struct msg_queue *sender ) { struct hw_msg_source source = { IMDT_KEYBOARD, origin }; - const struct rawinput_device *device; struct hardware_msg_data *msg_data; + struct rawinput_message raw_msg; struct message *msg; + struct thread *foreground; unsigned char vkey = input->kbd.vkey; unsigned int message_code, time; int wait; @@ -1777,22 +1823,23 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c break; }
- if ((device = current->process->rawinput_kbd)) + if ((foreground = get_foreground_thread( desktop, win ))) { - if (!(msg = alloc_hardware_message( input->kbd.info, source, time ))) return 0; - msg_data = msg->data; - - msg->win = device->target; - msg->msg = WM_INPUT; - msg->wparam = RIM_INPUT; + raw_msg.foreground = foreground; + raw_msg.desktop = desktop; + raw_msg.source = source; + raw_msg.time = time;
+ msg_data = &raw_msg.data; + msg_data->info = input->kbd.info; msg_data->flags = input->kbd.flags; msg_data->rawinput.type = RIM_TYPEKEYBOARD; msg_data->rawinput.kbd.message = message_code; msg_data->rawinput.kbd.vkey = vkey; msg_data->rawinput.kbd.scan = input->kbd.scan;
- queue_hardware_message( desktop, msg, 0 ); + queue_rawinput_message( foreground->process, &raw_msg ); + release_object( foreground ); }
if (!(msg = alloc_hardware_message( input->kbd.info, source, time ))) return 0;
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- server/queue.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-)
diff --git a/server/queue.c b/server/queue.c index d7840cd7150..01896aa41ee 100644 --- a/server/queue.c +++ b/server/queue.c @@ -366,6 +366,20 @@ static struct message *alloc_hardware_message( lparam_t info, struct hw_msg_sour return msg; }
+static int update_desktop_cursor_pos( struct desktop *desktop, int x, int y ) +{ + int updated; + + x = max( min( x, desktop->cursor.clip.right - 1 ), desktop->cursor.clip.left ); + y = max( min( y, desktop->cursor.clip.bottom - 1 ), desktop->cursor.clip.top ); + updated = (desktop->cursor.x != x || desktop->cursor.y != y); + desktop->cursor.x = x; + desktop->cursor.y = y; + desktop->cursor.last_change = get_tick_count(); + + return updated; +} + /* set the cursor position and queue the corresponding mouse message */ static void set_cursor_pos( struct desktop *desktop, int x, int y ) { @@ -1500,15 +1514,7 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg } else if (msg->msg != WM_INPUT) { - if (msg->msg == WM_MOUSEMOVE) - { - int x = max( min( msg->x, desktop->cursor.clip.right - 1 ), desktop->cursor.clip.left ); - int y = max( min( msg->y, desktop->cursor.clip.bottom - 1 ), desktop->cursor.clip.top ); - if (desktop->cursor.x != x || desktop->cursor.y != y) always_queue = 1; - desktop->cursor.x = x; - desktop->cursor.y = y; - desktop->cursor.last_change = get_tick_count(); - } + if (msg->msg == WM_MOUSEMOVE && update_desktop_cursor_pos( desktop, msg->x, msg->y )) always_queue = 1; if (desktop->keystate[VK_LBUTTON] & 0x80) msg->wparam |= MK_LBUTTON; if (desktop->keystate[VK_MBUTTON] & 0x80) msg->wparam |= MK_MBUTTON; if (desktop->keystate[VK_RBUTTON] & 0x80) msg->wparam |= MK_RBUTTON;
So that we can update individual states in next patch.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- server/queue.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/server/queue.c b/server/queue.c index 01896aa41ee..126ca76f986 100644 --- a/server/queue.c +++ b/server/queue.c @@ -1290,12 +1290,12 @@ static void set_input_key_state( unsigned char *keystate, unsigned char key, int
/* update the input key state for a keyboard message */ static void update_input_key_state( struct desktop *desktop, unsigned char *keystate, - const struct message *msg ) + unsigned int msg, lparam_t wparam ) { unsigned char key; int down = 0;
- switch (msg->msg) + switch (msg) { case WM_LBUTTONDOWN: down = (keystate == desktop->keystate) ? 0xc0 : 0x80; @@ -1319,8 +1319,8 @@ static void update_input_key_state( struct desktop *desktop, unsigned char *keys down = (keystate == desktop->keystate) ? 0xc0 : 0x80; /* fall through */ case WM_XBUTTONUP: - if (msg->wparam >> 16 == XBUTTON1) set_input_key_state( keystate, VK_XBUTTON1, down ); - else if (msg->wparam >> 16 == XBUTTON2) set_input_key_state( keystate, VK_XBUTTON2, down ); + if (wparam >> 16 == XBUTTON1) set_input_key_state( keystate, VK_XBUTTON1, down ); + else if (wparam >> 16 == XBUTTON2) set_input_key_state( keystate, VK_XBUTTON2, down ); break; case WM_KEYDOWN: case WM_SYSKEYDOWN: @@ -1328,7 +1328,7 @@ static void update_input_key_state( struct desktop *desktop, unsigned char *keys /* fall through */ case WM_KEYUP: case WM_SYSKEYUP: - key = (unsigned char)msg->wparam; + key = (unsigned char)wparam; set_input_key_state( keystate, key, down ); switch(key) { @@ -1382,7 +1382,7 @@ static void release_hardware_message( struct msg_queue *queue, unsigned int hw_i } if (clr_bit) clear_queue_bits( queue, clr_bit );
- update_input_key_state( input->desktop, input->keystate, msg ); + update_input_key_state( input->desktop, input->keystate, msg->msg, msg->wparam ); list_remove( &msg->entry ); free_message( msg ); } @@ -1501,7 +1501,7 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg struct thread_input *input; unsigned int msg_code;
- update_input_key_state( desktop, desktop->keystate, msg ); + update_input_key_state( desktop, desktop->keystate, msg->msg, msg->wparam ); last_input_time = get_tick_count(); if (msg->msg != WM_MOUSEMOVE) always_queue = 1;
@@ -1536,7 +1536,7 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg win = find_hardware_message_window( desktop, input, msg, &msg_code, &thread ); if (!win || !thread) { - if (input) update_input_key_state( input->desktop, input->keystate, msg ); + if (input) update_input_key_state( input->desktop, input->keystate, msg->msg, msg->wparam ); free_message( msg ); return; } @@ -1973,7 +1973,7 @@ static int get_hardware_message( struct thread *thread, unsigned int hw_id, user if (!win || !win_thread) { /* no window at all, remove it */ - update_input_key_state( input->desktop, input->keystate, msg ); + update_input_key_state( input->desktop, input->keystate, msg->msg, msg->wparam ); list_remove( &msg->entry ); free_message( msg ); continue; @@ -1989,7 +1989,7 @@ static int get_hardware_message( struct thread *thread, unsigned int hw_id, user else { /* for another thread input, drop it */ - update_input_key_state( input->desktop, input->keystate, msg ); + update_input_key_state( input->desktop, input->keystate, msg->msg, msg->wparam ); list_remove( &msg->entry ); free_message( msg ); }
This makes legacy mouse window messages such as WM_MOUSEMOVE and others, to stop being sent, including to low-level hooks. The desktop mouse state should still be udpated.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/user32/rawinput.c | 2 +- dlls/user32/tests/input.c | 2 +- server/queue.c | 45 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 2 deletions(-)
diff --git a/dlls/user32/rawinput.c b/dlls/user32/rawinput.c index dd2ac2e208b..7a9eb6ced17 100644 --- a/dlls/user32/rawinput.c +++ b/dlls/user32/rawinput.c @@ -306,7 +306,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH RegisterRawInputDevices(RAWINPUTDEVICE *devices, U TRACE("device %u: page %#x, usage %#x, flags %#x, target %p.\n", i, devices[i].usUsagePage, devices[i].usUsage, devices[i].dwFlags, devices[i].hwndTarget); - if (devices[i].dwFlags & ~RIDEV_REMOVE) + if (devices[i].dwFlags & ~(RIDEV_REMOVE|RIDEV_NOLEGACY)) FIXME("Unhandled flags %#x for device %u.\n", devices[i].dwFlags, i);
d[i].usage_page = devices[i].usUsagePage; diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index 6f1fa9b3e9c..8ae44e4ab92 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -1876,7 +1876,7 @@ struct rawinput_test rawinput_tests[] = { FALSE, FALSE, 0, TRUE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, { TRUE, FALSE, 0, TRUE, TRUE, TRUE, /* todos: */ FALSE, FALSE, FALSE }, { TRUE, TRUE, 0, TRUE, TRUE, TRUE, /* todos: */ FALSE, FALSE, FALSE }, - { TRUE, TRUE, RIDEV_NOLEGACY, FALSE, TRUE, TRUE, /* todos: */ TRUE, FALSE, FALSE }, + { TRUE, TRUE, RIDEV_NOLEGACY, FALSE, TRUE, TRUE, /* todos: */ FALSE, FALSE, FALSE },
/* same-process foreground tests */ { TRUE, FALSE, 0, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, diff --git a/server/queue.c b/server/queue.c index 126ca76f986..0318e234bd3 100644 --- a/server/queue.c +++ b/server/queue.c @@ -384,8 +384,15 @@ static int update_desktop_cursor_pos( struct desktop *desktop, int x, int y ) static void set_cursor_pos( struct desktop *desktop, int x, int y ) { static const struct hw_msg_source source = { IMDT_UNAVAILABLE, IMO_SYSTEM }; + const struct rawinput_device *device; struct message *msg;
+ if ((device = current->process->rawinput_mouse) && (device->flags & RIDEV_NOLEGACY)) + { + update_desktop_cursor_pos( desktop, x, y ); + return; + } + if (!(msg = alloc_hardware_message( 0, source, get_tick_count() ))) return;
msg->msg = WM_MOUSEMOVE; @@ -1352,6 +1359,30 @@ static void update_input_key_state( struct desktop *desktop, unsigned char *keys } }
+/* update the desktop key state according to a mouse message flags */ +static void update_desktop_mouse_state( struct desktop *desktop, unsigned int flags, + int x, int y, lparam_t wparam ) +{ + if (flags & MOUSEEVENTF_MOVE) + update_desktop_cursor_pos( desktop, x, y ); + if (flags & MOUSEEVENTF_LEFTDOWN) + update_input_key_state( desktop, desktop->keystate, WM_LBUTTONDOWN, wparam ); + if (flags & MOUSEEVENTF_LEFTUP) + update_input_key_state( desktop, desktop->keystate, WM_LBUTTONUP, wparam ); + if (flags & MOUSEEVENTF_RIGHTDOWN) + update_input_key_state( desktop, desktop->keystate, WM_RBUTTONDOWN, wparam ); + if (flags & MOUSEEVENTF_RIGHTUP) + update_input_key_state( desktop, desktop->keystate, WM_RBUTTONUP, wparam ); + if (flags & MOUSEEVENTF_MIDDLEDOWN) + update_input_key_state( desktop, desktop->keystate, WM_MBUTTONDOWN, wparam ); + if (flags & MOUSEEVENTF_MIDDLEUP) + update_input_key_state( desktop, desktop->keystate, WM_MBUTTONUP, wparam ); + if (flags & MOUSEEVENTF_XDOWN) + update_input_key_state( desktop, desktop->keystate, WM_XBUTTONDOWN, wparam ); + if (flags & MOUSEEVENTF_XUP) + update_input_key_state( desktop, desktop->keystate, WM_XBUTTONUP, wparam ); +} + /* release the hardware message currently being processed by the given thread */ static void release_hardware_message( struct msg_queue *queue, unsigned int hw_id, int remove ) @@ -1650,6 +1681,7 @@ static int queue_rawinput_message( struct process* process, void *arg ) static int queue_mouse_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input, unsigned int origin, struct msg_queue *sender ) { + const struct rawinput_device *device; struct hardware_msg_data *msg_data; struct rawinput_message raw_msg; struct message *msg; @@ -1721,6 +1753,12 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons release_object( foreground ); }
+ if ((device = current->process->rawinput_mouse) && (device->flags & RIDEV_NOLEGACY)) + { + update_desktop_mouse_state( desktop, flags, x, y, input->mouse.data << 16 ); + return 0; + } + for (i = 0; i < ARRAY_SIZE( messages ); i++) { if (!messages[i]) continue; @@ -1755,6 +1793,7 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c unsigned int origin, struct msg_queue *sender ) { struct hw_msg_source source = { IMDT_KEYBOARD, origin }; + const struct rawinput_device *device; struct hardware_msg_data *msg_data; struct rawinput_message raw_msg; struct message *msg; @@ -1848,6 +1887,12 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c release_object( foreground ); }
+ if ((device = current->process->rawinput_kbd) && (device->flags & RIDEV_NOLEGACY)) + { + update_input_key_state( desktop, desktop->keystate, message_code, vkey ); + return 0; + } + if (!(msg = alloc_hardware_message( input->kbd.info, source, time ))) return 0; msg_data = msg->data;
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=74117
Your paranoid android.
=== debiant (32 bit Chinese:China report) ===
user32: clipboard.c:833: Test failed: 0: gle 5 clipboard.c:838: Test failed: 0.0: got 0000 instead of 0001 clipboard.c:868: Test failed: 0: gle 1418 clipboard.c:717: Test failed: 1: gle 5 clipboard.c:719: Test failed: 1: gle 1418 clipboard.c:746: Test failed: 1: count 4 clipboard.c:749: Test failed: 1: gle 1418 clipboard.c:760: Test failed: 1: gle 5 clipboard.c:765: Test failed: 1.0: got 0000 instead of 0007 clipboard.c:805: Test failed: 1: gle 1418 clipboard.c:815: Test failed: 1: count 4 clipboard.c:818: Test failed: 1: gle 1418 clipboard.c:833: Test failed: 1: gle 5 clipboard.c:838: Test failed: 1.0: got 0000 instead of 0007 clipboard.c:868: Test failed: 1: gle 1418 clipboard.c:717: Test failed: 2: gle 5 clipboard.c:719: Test failed: 2: gle 1418 clipboard.c:746: Test failed: 2: count 4 clipboard.c:749: Test failed: 2: gle 1418 clipboard.c:760: Test failed: 2: gle 5 clipboard.c:765: Test failed: 2.0: got 0000 instead of 000d clipboard.c:805: Test failed: 2: gle 1418 clipboard.c:815: Test failed: 2: count 4 clipboard.c:818: Test failed: 2: gle 1418 clipboard.c:833: Test failed: 2: gle 5 clipboard.c:838: Test failed: 2.0: got 0000 instead of 000d clipboard.c:868: Test failed: 2: gle 1418 clipboard.c:717: Test failed: 3: gle 5 clipboard.c:719: Test failed: 3: gle 1418 clipboard.c:746: Test failed: 3: count 5 clipboard.c:749: Test failed: 3: gle 1418 clipboard.c:755: Test failed: 3: 0003 not available clipboard.c:757: Test failed: 3: count 5 instead of 2 clipboard.c:760: Test failed: 3: gle 5 clipboard.c:765: Test failed: 3.0: got 0000 instead of 000e clipboard.c:805: Test failed: 3: gle 1418 clipboard.c:815: Test failed: 3: count 5 clipboard.c:818: Test failed: 3: gle 1418 clipboard.c:826: Test failed: 3: 0003 not available clipboard.c:828: Test failed: 3: count 5 instead of 2 clipboard.c:833: Test failed: 3: gle 5 clipboard.c:838: Test failed: 3.0: got 0000 instead of 000e clipboard.c:868: Test failed: 3: gle 1418 clipboard.c:717: Test failed: 4: gle 5 clipboard.c:719: Test failed: 4: gle 1418 clipboard.c:746: Test failed: 4: count 6 clipboard.c:749: Test failed: 4: gle 1418 clipboard.c:757: Test failed: 4: count 6 instead of 2 clipboard.c:760: Test failed: 4: gle 5 clipboard.c:765: Test failed: 4.0: got 0000 instead of 0003 clipboard.c:805: Test failed: 4: gle 1418 clipboard.c:815: Test failed: 4: count 6 clipboard.c:818: Test failed: 4: gle 1418 clipboard.c:828: Test failed: 4: count 6 instead of 2 clipboard.c:833: Test failed: 4: gle 5 clipboard.c:838: Test failed: 4.0: got 0000 instead of 0003 clipboard.c:868: Test failed: 4: gle 1418 clipboard.c:717: Test failed: 5: gle 5 clipboard.c:719: Test failed: 5: gle 1418 clipboard.c:746: Test failed: 5: count 7 clipboard.c:749: Test failed: 5: gle 1418 clipboard.c:755: Test failed: 5: 0008 not available clipboard.c:755: Test failed: 5: 0011 not available clipboard.c:757: Test failed: 5: count 7 instead of 3 clipboard.c:760: Test failed: 5: gle 5 clipboard.c:765: Test failed: 5.0: got 0000 instead of 0002 clipboard.c:805: Test failed: 5: gle 1418 clipboard.c:815: Test failed: 5: count 7 clipboard.c:818: Test failed: 5: gle 1418 clipboard.c:826: Test failed: 5: 0008 not available clipboard.c:826: Test failed: 5: 0011 not available clipboard.c:828: Test failed: 5: count 7 instead of 3 clipboard.c:833: Test failed: 5: gle 5 clipboard.c:838: Test failed: 5.0: got 0000 instead of 0002 clipboard.c:868: Test failed: 5: gle 1418 clipboard.c:717: Test failed: 6: gle 5 clipboard.c:719: Test failed: 6: gle 1418 clipboard.c:746: Test failed: 6: count 8 clipboard.c:749: Test failed: 6: gle 1418 clipboard.c:755: Test failed: 6: 0011 not available clipboard.c:757: Test failed: 6: count 8 instead of 3 clipboard.c:760: Test failed: 6: gle 5 clipboard.c:765: Test failed: 6.0: got 0000 instead of 0008 clipboard.c:805: Test failed: 6: gle 1418 clipboard.c:815: Test failed: 6: count 8 clipboard.c:818: Test failed: 6: gle 1418 clipboard.c:826: Test failed: 6: 0011 not available clipboard.c:828: Test failed: 6: count 8 instead of 3 clipboard.c:833: Test failed: 6: gle 5 clipboard.c:838: Test failed: 6.0: got 0000 instead of 0008 clipboard.c:868: Test failed: 6: gle 1418 clipboard.c:717: Test failed: 7: gle 5 clipboard.c:719: Test failed: 7: gle 1418 clipboard.c:746: Test failed: 7: count 9 clipboard.c:749: Test failed: 7: gle 1418 clipboard.c:757: Test failed: 7: count 9 instead of 3 clipboard.c:760: Test failed: 7: gle 5 clipboard.c:765: Test failed: 7.0: got 0000 instead of 0011 clipboard.c:805: Test failed: 7: gle 1418 clipboard.c:815: Test failed: 7: count 9 clipboard.c:818: Test failed: 7: gle 1418 clipboard.c:828: Test failed: 7: count 9 instead of 3 clipboard.c:833: Test failed: 7: gle 5 clipboard.c:838: Test failed: 7.0: got 0000 instead of 0011 clipboard.c:868: Test failed: 7: gle 1418 clipboard.c:874: Test failed: gle 5 clipboard.c:876: Test failed: gle 1418 clipboard.c:878: Test failed: gle 1418
This flag allows applications to receive rawinput messages while in background. They have to specify a target hwnd, which will receive them, and the messages will carry a RIM_INPUTSINK wparam if the process wasn't foreground.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/user32/rawinput.c | 9 ++++++++- dlls/user32/tests/input.c | 8 +++----- server/queue.c | 24 ++++++++++++++++++++---- 3 files changed, 31 insertions(+), 10 deletions(-)
diff --git a/dlls/user32/rawinput.c b/dlls/user32/rawinput.c index 7a9eb6ced17..103835e0e33 100644 --- a/dlls/user32/rawinput.c +++ b/dlls/user32/rawinput.c @@ -291,6 +291,13 @@ BOOL WINAPI DECLSPEC_HOTPATCH RegisterRawInputDevices(RAWINPUTDEVICE *devices, U
for (i = 0; i < device_count; ++i) { + if ((devices[i].dwFlags & RIDEV_INPUTSINK) && + (devices[i].hwndTarget == NULL)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + if ((devices[i].dwFlags & RIDEV_REMOVE) && (devices[i].hwndTarget != NULL)) { @@ -306,7 +313,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH RegisterRawInputDevices(RAWINPUTDEVICE *devices, U TRACE("device %u: page %#x, usage %#x, flags %#x, target %p.\n", i, devices[i].usUsagePage, devices[i].usUsage, devices[i].dwFlags, devices[i].hwndTarget); - if (devices[i].dwFlags & ~(RIDEV_REMOVE|RIDEV_NOLEGACY)) + if (devices[i].dwFlags & ~(RIDEV_REMOVE|RIDEV_NOLEGACY|RIDEV_INPUTSINK)) FIXME("Unhandled flags %#x for device %u.\n", devices[i].dwFlags, i);
d[i].usage_page = devices[i].usUsagePage; diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index 8ae44e4ab92..51b18242444 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -1807,9 +1807,7 @@ static void test_RegisterRawInputDevices(void)
SetLastError(0xdeadbeef); res = RegisterRawInputDevices(raw_devices, ARRAY_SIZE(raw_devices), sizeof(RAWINPUTDEVICE)); - todo_wine ok(res == FALSE, "RegisterRawInputDevices failed\n"); - todo_wine ok(GetLastError() == ERROR_INVALID_PARAMETER, "RegisterRawInputDevices returned %08x\n", GetLastError());
raw_devices[0].hwndTarget = hwnd; @@ -1884,13 +1882,13 @@ struct rawinput_test rawinput_tests[] =
/* cross-process foreground tests */ { TRUE, TRUE, 0, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, - { TRUE, TRUE, RIDEV_INPUTSINK, FALSE, TRUE, FALSE, /* todos: */ FALSE, TRUE, FALSE }, + { TRUE, TRUE, RIDEV_INPUTSINK, FALSE, TRUE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, { TRUE, TRUE, 0, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE },
/* multi-process rawinput tests */ { TRUE, TRUE, 0, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, - { TRUE, TRUE, RIDEV_INPUTSINK, FALSE, TRUE, FALSE, /* todos: */ FALSE, TRUE, FALSE }, - { TRUE, TRUE, RIDEV_INPUTSINK, FALSE, TRUE, FALSE, /* todos: */ FALSE, TRUE, FALSE }, + { TRUE, TRUE, RIDEV_INPUTSINK, FALSE, TRUE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, + { TRUE, TRUE, RIDEV_INPUTSINK, FALSE, TRUE, FALSE, /* todos: */ FALSE, FALSE, FALSE },
{ TRUE, TRUE, RIDEV_EXINPUTSINK, FALSE, FALSE, FALSE, /* todos: */ FALSE, FALSE, FALSE }, { TRUE, TRUE, RIDEV_EXINPUTSINK, FALSE, TRUE, FALSE, /* todos: */ FALSE, TRUE, FALSE }, diff --git a/server/queue.c b/server/queue.c index 0318e234bd3..0de3f3bf99e 100644 --- a/server/queue.c +++ b/server/queue.c @@ -1656,7 +1656,10 @@ static int queue_rawinput_message( struct process* process, void *arg ) { const struct rawinput_message* raw_msg = arg; const struct rawinput_device *device = NULL; + struct desktop *target_desktop = NULL; + struct thread *target_thread = NULL; struct message *msg; + int wparam = RIM_INPUT;
if (raw_msg->data.rawinput.type == RIM_TYPEMOUSE) device = process->rawinput_mouse; @@ -1664,16 +1667,29 @@ static int queue_rawinput_message( struct process* process, void *arg ) device = process->rawinput_kbd; if (!device) return 0;
+ if (process != raw_msg->foreground->process) + { + if (!(device->flags & RIDEV_INPUTSINK)) goto done; + if (!(target_thread = get_window_thread( device->target ))) goto done; + if (!(target_desktop = get_thread_desktop( target_thread, 0 ))) goto done; + if (target_desktop != raw_msg->desktop) goto done; + wparam = RIM_INPUTSINK; + } + if (!(msg = alloc_hardware_message( raw_msg->data.info, raw_msg->source, raw_msg->time ))) - return 0; + goto done;
msg->win = device->target; msg->msg = WM_INPUT; - msg->wparam = RIM_INPUT; + msg->wparam = wparam; msg->lparam = 0; memcpy( msg->data, &raw_msg->data, sizeof(raw_msg->data) );
queue_hardware_message( raw_msg->desktop, msg, 1 ); + +done: + if (target_thread) release_object( target_thread ); + if (target_desktop) release_object( target_desktop ); return 0; }
@@ -1749,7 +1765,7 @@ static int queue_mouse_message( struct desktop *desktop, user_handle_t win, cons msg_data->rawinput.mouse.y = y - desktop->cursor.y; msg_data->rawinput.mouse.data = input->mouse.data;
- queue_rawinput_message( foreground->process, &raw_msg ); + enum_processes( queue_rawinput_message, &raw_msg ); release_object( foreground ); }
@@ -1883,7 +1899,7 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c msg_data->rawinput.kbd.vkey = vkey; msg_data->rawinput.kbd.scan = input->kbd.scan;
- queue_rawinput_message( foreground->process, &raw_msg ); + enum_processes( queue_rawinput_message, &raw_msg ); release_object( foreground ); }
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=74118
Your paranoid android.
=== debiant (32 bit Chinese:China report) ===
user32: clipboard.c:1383: Test failed: gle 5 clipboard.c:1385: Test failed: gle 1418 clipboard.c:1388: Test failed: got 00000000 clipboard.c:1389: Test failed: expected moveable mem 00000000 clipboard.c:1391: Test failed: got 00000000 clipboard.c:1392: Test failed: expected moveable mem 00000000 clipboard.c:1395: Test failed: got 00000000 clipboard.c:1396: Test failed: expected bitmap 00000000 clipboard.c:1398: Test failed: got 00000000 clipboard.c:1399: Test failed: expected bitmap 00000000 clipboard.c:1401: Test failed: got 00000000 clipboard.c:1402: Test failed: expected bitmap 00000000 clipboard.c:1404: Test failed: got 00000000 clipboard.c:1405: Test failed: expected palette 00000000 clipboard.c:1407: Test failed: got 00000000 clipboard.c:1408: Test failed: expected moveable mem 00000000 clipboard.c:1410: Test failed: got 00000000 clipboard.c:1411: Test failed: expected moveable mem 00000000 clipboard.c:1425: Test failed: got 00000000 clipboard.c:1426: Test failed: expected fixed mem 00000000 clipboard.c:1428: Test failed: got 00000000 clipboard.c:1429: Test failed: expected fixed mem 00000000 clipboard.c:1431: Test failed: got 00000000 clipboard.c:1432: Test failed: expected moveable mem 00000000 clipboard.c:1444: Test failed: wrong data 00000000 clipboard.c:1445: Test failed: expected moveable mem 00000000 clipboard.c:1448: Test failed: wrong data 00000000, cf 0000c040 clipboard.c:1449: Test failed: expected moveable mem 00000000 clipboard.c:1452: Test failed: wrong data 00000000 clipboard.c:1453: Test failed: expected moveable mem 00000000 clipboard.c:1456: Test failed: wrong data 00000000 clipboard.c:1457: Test failed: expected moveable mem 00000000 clipboard.c:1460: Test failed: wrong data 00000000 clipboard.c:1461: Test failed: expected fixed mem 00000000 clipboard.c:1464: Test failed: wrong data 00000000 clipboard.c:1465: Test failed: expected fixed mem 00000000 clipboard.c:1468: Test failed: wrong data 00000000 clipboard.c:1469: Test failed: expected moveable mem 00000000 clipboard.c:1475: Test failed: got 00000000 clipboard.c:1476: Test failed: expected moveable mem 00000000 clipboard.c:1477: Test failed: expected freed mem 00C0B3EA clipboard.c:1480: Test failed: got 00000000 clipboard.c:1481: Test failed: expected fixed mem 00000000 clipboard.c:1486: Test failed: gle 1418 clipboard.c:1549: Test failed: wrong data 00000000 clipboard.c:1552: Test failed: wrong data 00000000, cf 0000c040 clipboard.c:1555: Test failed: wrong data 00000000 clipboard.c:1558: Test failed: wrong data 00000000 clipboard.c:1561: Test failed: wrong data 00000000 clipboard.c:1564: Test failed: wrong data 00000000 clipboard.c:1567: Test failed: wrong data 00000000 clipboard.c:1574: Test failed: expected fixed mem 00000000 clipboard.c:1576: Test failed: expected fixed mem 00000000 clipboard.c:1578: Test failed: expected fixed mem 00000000 clipboard.c:1580: Test failed: expected bitmap 00000000 clipboard.c:1582: Test failed: expected bitmap 00000000 clipboard.c:1584: Test failed: expected palette 00000000 clipboard.c:1586: Test failed: expected fixed mem 00000000 clipboard.c:1588: Test failed: expected fixed mem 00000000 clipboard.c:1600: Test failed: expected freed mem 00C0C7A2 clipboard.c:1601: Test failed: expected freed mem 00C0EB8A clipboard.c:1602: Test failed: expected freed mem 00C0EBC2 clipboard.c:1603: Test failed: expected freed mem 00C0D31A clipboard.c:1604: Test failed: expected freed mem 00C0B53A win.c:10232: Test failed: Expected foreground window 008300FA, got 00E10102 win.c:10234: Test failed: GetActiveWindow() = 00000000 win.c:10234: Test failed: GetFocus() = 00000000 win.c:10235: Test failed: Received WM_ACTIVATEAPP(1), did not expect it. win.c:10236: Test failed: Received WM_ACTIVATEAPP(0), did not expect it.
=== debiant (64 bit WoW report) ===
user32: win.c:10147: Test failed: GetActiveWindow() = 00000000 win.c:10147: Test failed: GetFocus() = 00000000 win.c:10149: Test failed: Expected foreground window 000D013E, got 00E10102 win.c:10152: Test failed: Received WM_ACTIVATEAPP(0), did not expect it. win.c:10159: Test failed: Expected foreground window 000D013E, got 00000000 win.c:10161: Test failed: GetActiveWindow() = 00000000 win.c:10161: Test failed: GetFocus() = 00000000 win.c:10169: Test failed: Received WM_ACTIVATEAPP(1), did not expect it.