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.
This commit is contained in:
Rémi Bernon 2024-02-25 09:33:06 +01:00 committed by Alexandre Julliard
parent a1d63d109d
commit 496eed7aaf
4 changed files with 44 additions and 18 deletions

View file

@ -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);

View file

@ -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;

View file

@ -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 );

View file

@ -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;