Module: wine Branch: master Commit: 496eed7aafdb4bce0963bd4258b9a8096e8b4696 URL: https://gitlab.winehq.org/wine/wine/-/commit/496eed7aafdb4bce0963bd4258b9a80...
Author: Rémi Bernon rbernon@codeweavers.com Date: Sun Feb 25 09:33:06 2024 +0100
server: Send hardware input to the visible input desktop.
When hwnd is specified, it is because it received a direct host input, so switch the input desktop to match the one that is receiving it.
We don't validate that the sending thread uses the same desktop as the target window: it may not even be the case for drivers with a separate thread that listens on input events.
---
dlls/user32/tests/winstation.c | 6 ++---- server/queue.c | 40 ++++++++++++++++++++++++++++------------ server/user.h | 3 +++ server/winstation.c | 13 +++++++++++-- 4 files changed, 44 insertions(+), 18 deletions(-)
diff --git a/dlls/user32/tests/winstation.c b/dlls/user32/tests/winstation.c index 11ad7685e97..bcbb55ee918 100644 --- a/dlls/user32/tests/winstation.c +++ b/dlls/user32/tests/winstation.c @@ -652,9 +652,8 @@ static void test_inputdesktop(void) win_skip("Skip tests on NT4\n"); return; } - todo_wine ok(GetLastError() == ERROR_ACCESS_DENIED, "unexpected last error %08lx\n", GetLastError()); - ok(ret == 1 || broken(ret == 0) /* Win64 */, "unexpected return count %ld\n", ret); + ok(ret == 0 || broken(ret == 1) /* Win32 */, "unexpected return count %ld\n", ret);
/* Set thread desktop back to the old thread desktop, SendInput should success. */ ret = SetThreadDesktop(old_thread_desk); @@ -699,9 +698,8 @@ static void test_inputdesktop(void)
SetLastError(0xdeadbeef); ret = SendInput(1, inputs, sizeof(INPUT)); - todo_wine ok(GetLastError() == ERROR_ACCESS_DENIED, "unexpected last error %08lx\n", GetLastError()); - ok(ret == 1 || broken(ret == 0) /* Win64 */, "unexpected return count %ld\n", ret); + ok(ret == 0 || broken(ret == 1) /* Win32 */, "unexpected return count %ld\n", ret);
/* Set thread desktop to the new desktop, SendInput should success. */ ret = SetThreadDesktop(new_desk); diff --git a/server/queue.c b/server/queue.c index 6f38227aa84..dbd83c43217 100644 --- a/server/queue.c +++ b/server/queue.c @@ -2598,6 +2598,28 @@ void free_hotkeys( struct desktop *desktop, user_handle_t window ) } }
+/* retrieve the desktop which should receive some hardware input event */ +static struct desktop *get_hardware_input_desktop( user_handle_t win ) +{ + struct winstation *winstation; + struct desktop *desktop; + struct thread *thread; + + if (!win || !(thread = get_window_thread( win ))) + { + if (!(winstation = get_visible_winstation())) return NULL; + return get_input_desktop( winstation ); + } + else + { + /* if window is specified, use its desktop to make it the input desktop */ + desktop = (struct desktop *)grab_object( thread->queue->input->desktop ); + release_object( thread ); + } + + return desktop; +} +
/* check if the thread owning the window is hung */ DECL_HANDLER(is_window_hung) @@ -2767,22 +2789,17 @@ DECL_HANDLER(send_message) /* send a hardware message to a thread queue */ DECL_HANDLER(send_hardware_message) { - struct thread *thread = NULL; struct desktop *desktop; unsigned int origin = (req->flags & SEND_HWMSG_INJECTED ? IMO_INJECTED : IMO_HARDWARE); struct msg_queue *sender = get_current_queue();
- if (!(desktop = get_thread_desktop( current, 0 ))) return; - - if (req->win) + if (!(desktop = get_hardware_input_desktop( req->win ))) return; + if ((origin == IMO_INJECTED && desktop != current->queue->input->desktop) || + !set_input_desktop( desktop->winstation, desktop )) { - if (!(thread = get_window_thread( req->win ))) return; - if (desktop != thread->queue->input->desktop) - { - /* don't allow queuing events to a different desktop */ - release_object( desktop ); - return; - } + release_object( desktop ); + set_error( STATUS_ACCESS_DENIED ); + return; }
reply->prev_x = desktop->cursor.x; @@ -2802,7 +2819,6 @@ DECL_HANDLER(send_hardware_message) default: set_error( STATUS_INVALID_PARAMETER ); } - if (thread) release_object( thread );
reply->new_x = desktop->cursor.x; reply->new_y = desktop->cursor.y; diff --git a/server/user.h b/server/user.h index 56b0eb685f0..1acd0638520 100644 --- a/server/user.h +++ b/server/user.h @@ -186,6 +186,9 @@ extern client_ptr_t get_class_client_ptr( struct window_class *class );
/* windows station functions */
+extern struct winstation *get_visible_winstation(void); +extern struct desktop *get_input_desktop( struct winstation *winstation ); +extern int set_input_desktop( struct winstation *winstation, struct desktop *new_desktop ); extern struct desktop *get_desktop_obj( struct process *process, obj_handle_t handle, unsigned int access ); extern struct winstation *get_process_winstation( struct process *process, unsigned int access ); extern struct desktop *get_thread_desktop( struct thread *thread, unsigned int access ); diff --git a/server/winstation.c b/server/winstation.c index a23cd24261a..00afe0119ff 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -212,8 +212,17 @@ struct winstation *get_process_winstation( struct process *process, unsigned int access, &winstation_ops ); }
+/* retrieve the visible winstation */ +struct winstation *get_visible_winstation(void) +{ + struct winstation *winstation; + LIST_FOR_EACH_ENTRY( winstation, &winstation_list, struct winstation, entry ) + if (winstation->flags & WSF_VISIBLE) return winstation; + return NULL; +} + /* retrieve the winstation current input desktop */ -static struct desktop *get_input_desktop( struct winstation *winstation ) +struct desktop *get_input_desktop( struct winstation *winstation ) { struct desktop *desktop; if (!(desktop = winstation->input_desktop)) return NULL; @@ -221,7 +230,7 @@ static struct desktop *get_input_desktop( struct winstation *winstation ) }
/* changes the winstation current input desktop and update its input time */ -static int set_input_desktop( struct winstation *winstation, struct desktop *new_desktop ) +int set_input_desktop( struct winstation *winstation, struct desktop *new_desktop ) { if (!(winstation->flags & WSF_VISIBLE)) return 0; if (new_desktop) new_desktop->input_time = current_time;