And synchronize it with desktop async keystate, on GetKeyState calls, if it is not locked yet.
Based on a patch from Sebastian Lackner sebastian@fds-team.de.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=26269 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=27238 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=31899 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=35907 Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45385 Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/user32/tests/input.c | 6 ++--- server/queue.c | 51 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 53 insertions(+), 4 deletions(-)
diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index c146e4b5cd9..246569961be 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -3842,15 +3842,15 @@ static DWORD WINAPI get_key_state_thread(void *arg) else expect_c = FALSE;
check_get_keyboard_state(i, j, expect_c, FALSE, /* todo */ !has_queue); - check_get_key_state(i, j, expect_c, expect_x, /* todo */ has_queue || j == 0); - check_get_keyboard_state(i, j, expect_c, expect_x, /* todo */ has_queue || j == 0); + check_get_key_state(i, j, expect_c, expect_x, /* todo */ !has_queue && j == 0); + check_get_keyboard_state(i, j, expect_c, expect_x, /* todo */ !has_queue && j == 0);
/* key released */ ReleaseSemaphore(semaphores[0], 1, NULL); result = WaitForSingleObject(semaphores[1], 1000); ok(result == WAIT_OBJECT_0, "%d: WaitForSingleObject returned %u\n", i, result);
- check_get_keyboard_state(i, j, expect_c, expect_x, /* todo */ has_queue || j > 0); + check_get_keyboard_state(i, j, expect_c, expect_x, /* todo */ !has_queue && j > 0); check_get_key_state(i, j, expect_c, FALSE, /* todo */ FALSE); check_get_keyboard_state(i, j, expect_c, FALSE, /* todo */ FALSE); } diff --git a/server/queue.c b/server/queue.c index 5c9f91a13c5..0782c526327 100644 --- a/server/queue.c +++ b/server/queue.c @@ -114,6 +114,8 @@ struct thread_input int cursor_count; /* cursor show count */ struct list msg_list; /* list of hardware messages */ unsigned char keystate[256]; /* state of each key */ + unsigned char desktop_keystate[256]; /* desktop keystate when keystate was synced */ + int keystate_lock; /* keystate is locked */ };
struct msg_queue @@ -140,6 +142,7 @@ struct msg_queue struct thread_input *input; /* thread input descriptor */ 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 */ };
struct hotkey @@ -265,12 +268,14 @@ static struct thread_input *create_thread_input( struct thread *thread ) list_init( &input->msg_list ); set_caret_window( input, 0 ); memset( input->keystate, 0, sizeof(input->keystate) ); + input->keystate_lock = 0;
if (!(input->desktop = get_thread_desktop( thread, 0 /* FIXME: access rights */ ))) { release_object( input ); return NULL; } + memcpy( input->desktop_keystate, input->desktop->keystate, sizeof(input->desktop_keystate) ); } return input; } @@ -305,6 +310,7 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ queue->input = (struct thread_input *)grab_object( input ); queue->hooks = NULL; queue->last_get_msg = current_time; + queue->keystate_lock = 0; list_init( &queue->send_result ); list_init( &queue->callback_result ); list_init( &queue->pending_timers ); @@ -326,6 +332,31 @@ void free_msg_queue( struct thread *thread ) thread->queue = NULL; }
+/* synchronize thread input keystate with the desktop */ +static void sync_input_keystate( struct thread_input *input ) +{ + int i; + if (!input->desktop || input->keystate_lock) return; + for (i = 0; i < sizeof(input->keystate); ++i) + { + if (input->desktop_keystate[i] == input->desktop->keystate[i]) continue; + input->keystate[i] = input->desktop_keystate[i] = input->desktop->keystate[i]; + } +} + +/* locks thread input keystate to prevent synchronization */ +static void lock_input_keystate( struct thread_input *input ) +{ + input->keystate_lock++; +} + +/* unlock the thread input keystate and synchronize it again */ +static void unlock_input_keystate( struct thread_input *input ) +{ + input->keystate_lock--; + if (!input->keystate_lock) sync_input_keystate( input ); +} + /* change the thread input data of a given thread */ static int assign_thread_input( struct thread *thread, struct thread_input *new_input ) { @@ -339,9 +370,11 @@ static int assign_thread_input( struct thread *thread, struct thread_input *new_ if (queue->input) { queue->input->cursor_count -= queue->cursor_count; + if (queue->keystate_lock) unlock_input_keystate( queue->input ); release_object( queue->input ); } queue->input = (struct thread_input *)grab_object( new_input ); + if (queue->keystate_lock) lock_input_keystate( queue->input ); new_input->cursor_count += queue->cursor_count; return 1; } @@ -477,6 +510,11 @@ static inline int is_signaled( struct msg_queue *queue ) /* set some queue bits */ static inline void set_queue_bits( struct msg_queue *queue, unsigned int bits ) { + if (bits & (QS_KEY | QS_MOUSEBUTTON)) + { + if (!queue->keystate_lock) lock_input_keystate( queue->input ); + queue->keystate_lock = 1; + } queue->wake_bits |= bits; queue->changed_bits |= bits; if (is_signaled( queue )) wake_up( &queue->obj, 0 ); @@ -487,6 +525,11 @@ static inline void clear_queue_bits( struct msg_queue *queue, unsigned int bits { queue->wake_bits &= ~bits; queue->changed_bits &= ~bits; + if (!(queue->wake_bits & (QS_KEY | QS_MOUSEBUTTON))) + { + if (queue->keystate_lock) unlock_input_keystate( queue->input ); + queue->keystate_lock = 0; + } }
/* check whether msg is a keyboard message */ @@ -1031,6 +1074,7 @@ static void msg_queue_destroy( struct object *obj ) } if (queue->timeout) remove_timeout_user( queue->timeout ); queue->input->cursor_count -= queue->cursor_count; + if (queue->keystate_lock) unlock_input_keystate( queue->input ); release_object( queue->input ); if (queue->hooks) release_object( queue->hooks ); if (queue->fd) release_object( queue->fd ); @@ -2997,7 +3041,11 @@ DECL_HANDLER(get_key_state) else { unsigned char *keystate = current->queue->input->keystate; - if (req->key >= 0) reply->state = keystate[req->key & 0xff]; + if (req->key >= 0) + { + if (current->queue) sync_input_keystate( current->queue->input ); + reply->state = keystate[req->key & 0xff]; + } set_reply_data( keystate, size ); } } @@ -3011,6 +3059,7 @@ DECL_HANDLER(set_key_state) data_size_t size = min( 256, get_req_data_size() );
memcpy( queue->input->keystate, get_req_data(), size ); + memcpy( queue->input->desktop_keystate, queue->input->desktop->keystate, 256 ); if (req->async && (desktop = get_thread_desktop( current, 0 ))) { memcpy( desktop->keystate, get_req_data(), size );