From: Rémi Bernon rbernon@codeweavers.com
--- server/process.c | 2 ++ server/process.h | 1 + server/queue.c | 24 ++++++++++++++++++++++++ server/user.h | 1 + server/winstation.c | 30 +++++++++++++++++++++++++++++- 5 files changed, 57 insertions(+), 1 deletion(-)
diff --git a/server/process.c b/server/process.c index b6c21d15752..bc6636dbe8b 100644 --- a/server/process.c +++ b/server/process.c @@ -684,6 +684,7 @@ struct process *create_process( int fd, struct process *parent, unsigned int fla process->rawinput_mouse = NULL; process->rawinput_kbd = NULL; memset( &process->image_info, 0, sizeof(process->image_info) ); + list_init( &process->rawinput_entry ); list_init( &process->kernel_object ); list_init( &process->thread_list ); list_init( &process->locks ); @@ -784,6 +785,7 @@ static void process_destroy( struct object *obj ) if (process->idle_event) release_object( process->idle_event ); if (process->id) free_ptid( process->id ); if (process->token) release_object( process->token ); + list_remove( &process->rawinput_entry ); free( process->rawinput_devices ); free( process->dir_cache ); free( process->image ); diff --git a/server/process.h b/server/process.h index 97e0d455ece..1e73e9d47dc 100644 --- a/server/process.h +++ b/server/process.h @@ -83,6 +83,7 @@ struct process unsigned int rawinput_device_count; /* number of registered rawinput devices */ const struct rawinput_device *rawinput_mouse; /* rawinput mouse device, if any */ const struct rawinput_device *rawinput_kbd; /* rawinput keyboard device, if any */ + struct list rawinput_entry; /* entry in the rawinput process list */ struct list kernel_object; /* list of kernel object pointers */ pe_image_info_t image_info; /* main exe image info */ }; diff --git a/server/queue.c b/server/queue.c index dbd83c43217..041df36331e 100644 --- a/server/queue.c +++ b/server/queue.c @@ -50,6 +50,8 @@ enum message_kind { SEND_MESSAGE, POST_MESSAGE }; #define NB_MSG_KINDS (POST_MESSAGE+1)
+/* list of processes registered for rawinput in the input desktop */ +static struct list rawinput_processes = LIST_INIT(rawinput_processes);
struct message_result { @@ -2620,6 +2622,14 @@ static struct desktop *get_hardware_input_desktop( user_handle_t win ) return desktop; }
+/* enable or disable rawinput for a given process */ +void set_rawinput_process( struct process *process, int enable ) +{ + list_remove( &process->rawinput_entry ); /* remove it first, it might already be in the list */ + if (!process->rawinput_device_count || !enable) list_init( &process->rawinput_entry ); + else list_add_tail( &rawinput_processes, &process->rawinput_entry ); +} +
/* check if the thread owning the window is hung */ DECL_HANDLER(is_window_hung) @@ -3639,12 +3649,15 @@ DECL_HANDLER(update_rawinput_devices) unsigned int device_count = get_req_data_size() / sizeof (*devices); size_t size = device_count * sizeof(*devices); struct process *process = current->process; + struct winstation *winstation; + struct desktop *desktop;
if (!size) { process->rawinput_device_count = 0; process->rawinput_mouse = NULL; process->rawinput_kbd = NULL; + set_rawinput_process( process, 0 ); return; }
@@ -3659,4 +3672,15 @@ DECL_HANDLER(update_rawinput_devices)
process->rawinput_mouse = find_rawinput_device( process, MAKELONG(HID_USAGE_GENERIC_MOUSE, HID_USAGE_PAGE_GENERIC) ); process->rawinput_kbd = find_rawinput_device( process, MAKELONG(HID_USAGE_GENERIC_KEYBOARD, HID_USAGE_PAGE_GENERIC) ); + + if ((winstation = get_visible_winstation()) && (desktop = get_input_desktop( winstation ))) + { + struct thread *thread; + + /* one of the process thread might be connected to the input desktop, update the full list */ + LIST_FOR_EACH_ENTRY( thread, &desktop->threads, struct thread, desktop_entry ) + set_rawinput_process( thread->process, 1 ); + + release_object( desktop ); + } } diff --git a/server/user.h b/server/user.h index c3ca90d5a77..b4cf618f87e 100644 --- a/server/user.h +++ b/server/user.h @@ -125,6 +125,7 @@ extern void post_win_event( struct thread *thread, unsigned int event, const WCHAR *module, data_size_t module_size, user_handle_t handle ); extern void free_hotkeys( struct desktop *desktop, user_handle_t window ); +extern void set_rawinput_process( struct process *process, int enable );
/* region functions */
diff --git a/server/winstation.c b/server/winstation.c index f6fe5fd9e57..373a1f7ba92 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -232,9 +232,27 @@ struct desktop *get_input_desktop( struct winstation *winstation ) /* changes the winstation current input desktop and update its input time */ int set_input_desktop( struct winstation *winstation, struct desktop *new_desktop ) { + struct desktop *old_desktop = winstation->input_desktop; + struct thread *thread; + if (!(winstation->flags & WSF_VISIBLE)) return 0; if (new_desktop) new_desktop->input_time = current_time; - winstation->input_desktop = new_desktop; + if (old_desktop == new_desktop) return 1; + + if (old_desktop) + { + /* disconnect every process of the old input desktop from rawinput */ + LIST_FOR_EACH_ENTRY( thread, &old_desktop->threads, struct thread, desktop_entry ) + set_rawinput_process( thread->process, 0 ); + } + + if ((winstation->input_desktop = new_desktop)) + { + /* connect every process of the new input desktop to rawinput */ + LIST_FOR_EACH_ENTRY( thread, &new_desktop->threads, struct thread, desktop_entry ) + set_rawinput_process( thread->process, 1 ); + } + return 1; }
@@ -376,6 +394,9 @@ static void add_desktop_thread( struct desktop *desktop, struct thread *thread ) desktop->close_timeout = NULL; } } + + /* if thread process is now connected to the input desktop, let it receive rawinput */ + if (desktop == desktop->winstation->input_desktop) set_rawinput_process( thread->process, 1 ); }
/* remove a user of the desktop and start the close timeout if necessary */ @@ -394,6 +415,13 @@ static void remove_desktop_thread( struct desktop *desktop, struct thread *threa if ((process = get_top_window_owner( desktop )) && desktop->users == process->running_threads && !desktop->close_timeout) desktop->close_timeout = add_timeout_user( -TICKS_PER_SEC, close_desktop_timeout, desktop ); } + + if (desktop == desktop->winstation->input_desktop) + { + /* thread process might still be connected the input desktop through another thread, update the full list */ + LIST_FOR_EACH_ENTRY( thread, &desktop->threads, struct thread, desktop_entry ) + set_rawinput_process( thread->process, 1 ); + } }
/* set the thread default desktop handle */