From: Zhiyi Zhang zzhang@codeweavers.com
Fix an application failing to receive keyboard input after changing focus. --- dlls/user32/tests/input.c | 3 +-- server/queue.c | 24 +++++++++++++++++++++--- server/user.h | 2 +- server/winstation.c | 2 +- 4 files changed, 24 insertions(+), 7 deletions(-)
diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index 47c26293dec..ede787f1096 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -4678,10 +4678,9 @@ static void test_attach_input(void)
ret = AttachThreadInput(GetCurrentThreadId(), tid, FALSE); ok(ret, "AttachThreadInput error %ld\n", GetLastError()); - SendMessageA(wnd_event.hwnd, WM_USER+1, TRUE, (LPARAM)ourWnd); + SendMessageA(wnd_event.hwnd, WM_USER+1, 0, (LPARAM)ourWnd);
ret = AttachThreadInput(GetCurrentThreadId(), tid, FALSE); - todo_wine ok(ret, "AttachThreadInput error %ld\n", GetLastError()); SendMessageA(wnd_event.hwnd, WM_USER+1, 0, 0);
diff --git a/server/queue.c b/server/queue.c index ee03ceb55c8..d00b6a2e0c9 100644 --- a/server/queue.c +++ b/server/queue.c @@ -131,6 +131,7 @@ struct msg_queue lparam_t next_timer_id; /* id for the next timer with a 0 window */ struct timeout_user *timeout; /* timeout for next timer to expire */ struct thread_input *input; /* thread input descriptor */ + int attach_input_count; /* how many times the thread input has attached to the other thread */ struct hook_table *hooks; /* hook table */ timeout_t last_get_msg; /* time of last get message call */ int keystate_lock; /* owns an input keystate lock */ @@ -311,6 +312,7 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ queue->next_timer_id = 0x7fff; queue->timeout = NULL; queue->input = (struct thread_input *)grab_object( input ); + queue->attach_input_count = 0; queue->hooks = NULL; queue->last_get_msg = current_time; queue->keystate_lock = 0; @@ -423,6 +425,7 @@ static int assign_thread_input( struct thread *thread, struct thread_input *new_ } SHARED_WRITE_END;
+ queue->attach_input_count = 0; return 1; }
@@ -1408,6 +1411,13 @@ int attach_thread_input( struct thread *thread_from, struct thread *thread_to ) struct thread_input *input, *old_input; int ret;
+ if (thread_from->queue && thread_to->queue + && thread_from->queue->input == thread_to->queue->input) + { + thread_from->queue->attach_input_count++; + return 1; + } + if (!thread_to->queue && !(thread_to->queue = create_msg_queue( thread_to, NULL ))) return 0; if (!(desktop = get_thread_desktop( thread_from, 0 ))) return 0; input = (struct thread_input *)grab_object( thread_to->queue->input ); @@ -1436,17 +1446,25 @@ int attach_thread_input( struct thread *thread_from, struct thread *thread_to ) }
ret = assign_thread_input( thread_from, input ); - if (ret) memset( input->keystate, 0, sizeof(input->keystate) ); + if (ret) + { + if (thread_from->queue) + thread_from->queue->attach_input_count = 1; + memset( input->keystate, 0, sizeof(input->keystate) ); + } release_object( input ); return ret; }
/* detach two thread input data structures */ -void detach_thread_input( struct thread *thread_from ) +void detach_thread_input( struct thread *thread_from, int force ) { struct thread *thread; struct thread_input *input, *old_input = thread_from->queue->input;
+ if (!force && --thread_from->queue->attach_input_count > 0) + return; + if ((input = create_thread_input( thread_from ))) { const input_shm_t *old_input_shm, *input_shm; @@ -3660,7 +3678,7 @@ DECL_HANDLER(attach_thread_input) { if (thread_from->queue && thread_to->queue && thread_from->queue->input == thread_to->queue->input) - detach_thread_input( thread_from ); + detach_thread_input( thread_from, 0 ); else set_error( STATUS_ACCESS_DENIED ); } diff --git a/server/user.h b/server/user.h index 6f10f296200..2d572d20e9b 100644 --- a/server/user.h +++ b/server/user.h @@ -120,7 +120,7 @@ extern void queue_cleanup_window( struct thread *thread, user_handle_t win ); extern int init_thread_queue( struct thread *thread ); extern void check_thread_queue_idle( struct thread *thread ); extern int attach_thread_input( struct thread *thread_from, struct thread *thread_to ); -extern void detach_thread_input( struct thread *thread_from ); +extern void detach_thread_input( struct thread *thread_from, int force ); extern void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, unsigned int flags, int reset ); extern void post_message( user_handle_t win, unsigned int message, diff --git a/server/winstation.c b/server/winstation.c index 76a23b197a4..f0a1158d164 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -823,7 +823,7 @@ DECL_HANDLER(set_thread_desktop) if (!current->process->desktop) set_process_default_desktop( current->process, new_desktop, req->handle );
- if (old_desktop != new_desktop && current->queue) detach_thread_input( current ); + if (old_desktop != new_desktop && current->queue) detach_thread_input( current, 1 );
if (old_desktop) release_object( old_desktop ); release_object( new_desktop );