mirror of
git://source.winehq.org/git/wine.git
synced 2024-11-05 18:01:34 +00:00
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:
parent
a1d63d109d
commit
496eed7aaf
4 changed files with 44 additions and 18 deletions
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue