Commit 496eed7a authored by Rémi Bernon's avatar Rémi Bernon Committed by Alexandre Julliard

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.
parent a1d63d10
......@@ -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);
......
......@@ -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;
......
......@@ -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 );
......
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment