server: Lock thread input keystate whenever it is modified.
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> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
ff74d5c244
commit
f076e5f854
|
@ -4042,15 +4042,15 @@ static DWORD WINAPI get_key_state_thread(void *arg)
|
||||||
else expect_c = FALSE;
|
else expect_c = FALSE;
|
||||||
|
|
||||||
check_get_keyboard_state(i, j, expect_c, FALSE, /* todo */ !has_queue);
|
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_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_keyboard_state(i, j, expect_c, expect_x, /* todo */ !has_queue && j == 0);
|
||||||
|
|
||||||
/* key released */
|
/* key released */
|
||||||
ReleaseSemaphore(semaphores[0], 1, NULL);
|
ReleaseSemaphore(semaphores[0], 1, NULL);
|
||||||
result = WaitForSingleObject(semaphores[1], 1000);
|
result = WaitForSingleObject(semaphores[1], 1000);
|
||||||
ok(result == WAIT_OBJECT_0, "%d: WaitForSingleObject returned %lu\n", i, result);
|
ok(result == WAIT_OBJECT_0, "%d: WaitForSingleObject returned %lu\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_key_state(i, j, expect_c, FALSE, /* todo */ FALSE);
|
||||||
check_get_keyboard_state(i, j, expect_c, FALSE, /* todo */ FALSE);
|
check_get_keyboard_state(i, j, expect_c, FALSE, /* todo */ FALSE);
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,6 +112,8 @@ struct thread_input
|
||||||
int cursor_count; /* cursor show count */
|
int cursor_count; /* cursor show count */
|
||||||
struct list msg_list; /* list of hardware messages */
|
struct list msg_list; /* list of hardware messages */
|
||||||
unsigned char keystate[256]; /* state of each key */
|
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
|
struct msg_queue
|
||||||
|
@ -138,6 +140,7 @@ struct msg_queue
|
||||||
struct thread_input *input; /* thread input descriptor */
|
struct thread_input *input; /* thread input descriptor */
|
||||||
struct hook_table *hooks; /* hook table */
|
struct hook_table *hooks; /* hook table */
|
||||||
timeout_t last_get_msg; /* time of last get message call */
|
timeout_t last_get_msg; /* time of last get message call */
|
||||||
|
int keystate_lock; /* owns an input keystate lock */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct hotkey
|
struct hotkey
|
||||||
|
@ -263,12 +266,14 @@ static struct thread_input *create_thread_input( struct thread *thread )
|
||||||
list_init( &input->msg_list );
|
list_init( &input->msg_list );
|
||||||
set_caret_window( input, 0 );
|
set_caret_window( input, 0 );
|
||||||
memset( input->keystate, 0, sizeof(input->keystate) );
|
memset( input->keystate, 0, sizeof(input->keystate) );
|
||||||
|
input->keystate_lock = 0;
|
||||||
|
|
||||||
if (!(input->desktop = get_thread_desktop( thread, 0 /* FIXME: access rights */ )))
|
if (!(input->desktop = get_thread_desktop( thread, 0 /* FIXME: access rights */ )))
|
||||||
{
|
{
|
||||||
release_object( input );
|
release_object( input );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
memcpy( input->desktop_keystate, input->desktop->keystate, sizeof(input->desktop_keystate) );
|
||||||
}
|
}
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
@ -303,6 +308,7 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_
|
||||||
queue->input = (struct thread_input *)grab_object( input );
|
queue->input = (struct thread_input *)grab_object( input );
|
||||||
queue->hooks = NULL;
|
queue->hooks = NULL;
|
||||||
queue->last_get_msg = current_time;
|
queue->last_get_msg = current_time;
|
||||||
|
queue->keystate_lock = 0;
|
||||||
list_init( &queue->send_result );
|
list_init( &queue->send_result );
|
||||||
list_init( &queue->callback_result );
|
list_init( &queue->callback_result );
|
||||||
list_init( &queue->pending_timers );
|
list_init( &queue->pending_timers );
|
||||||
|
@ -324,6 +330,31 @@ void free_msg_queue( struct thread *thread )
|
||||||
thread->queue = NULL;
|
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 */
|
/* change the thread input data of a given thread */
|
||||||
static int assign_thread_input( struct thread *thread, struct thread_input *new_input )
|
static int assign_thread_input( struct thread *thread, struct thread_input *new_input )
|
||||||
{
|
{
|
||||||
|
@ -337,9 +368,11 @@ static int assign_thread_input( struct thread *thread, struct thread_input *new_
|
||||||
if (queue->input)
|
if (queue->input)
|
||||||
{
|
{
|
||||||
queue->input->cursor_count -= queue->cursor_count;
|
queue->input->cursor_count -= queue->cursor_count;
|
||||||
|
if (queue->keystate_lock) unlock_input_keystate( queue->input );
|
||||||
release_object( queue->input );
|
release_object( queue->input );
|
||||||
}
|
}
|
||||||
queue->input = (struct thread_input *)grab_object( new_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;
|
new_input->cursor_count += queue->cursor_count;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -476,6 +509,11 @@ static inline int is_signaled( struct msg_queue *queue )
|
||||||
/* set some queue bits */
|
/* set some queue bits */
|
||||||
static inline void set_queue_bits( struct msg_queue *queue, unsigned int 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->wake_bits |= bits;
|
||||||
queue->changed_bits |= bits;
|
queue->changed_bits |= bits;
|
||||||
if (is_signaled( queue )) wake_up( &queue->obj, 0 );
|
if (is_signaled( queue )) wake_up( &queue->obj, 0 );
|
||||||
|
@ -486,6 +524,11 @@ static inline void clear_queue_bits( struct msg_queue *queue, unsigned int bits
|
||||||
{
|
{
|
||||||
queue->wake_bits &= ~bits;
|
queue->wake_bits &= ~bits;
|
||||||
queue->changed_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 */
|
/* check whether msg is a keyboard message */
|
||||||
|
@ -1030,6 +1073,7 @@ static void msg_queue_destroy( struct object *obj )
|
||||||
}
|
}
|
||||||
if (queue->timeout) remove_timeout_user( queue->timeout );
|
if (queue->timeout) remove_timeout_user( queue->timeout );
|
||||||
queue->input->cursor_count -= queue->cursor_count;
|
queue->input->cursor_count -= queue->cursor_count;
|
||||||
|
if (queue->keystate_lock) unlock_input_keystate( queue->input );
|
||||||
release_object( queue->input );
|
release_object( queue->input );
|
||||||
if (queue->hooks) release_object( queue->hooks );
|
if (queue->hooks) release_object( queue->hooks );
|
||||||
if (queue->fd) release_object( queue->fd );
|
if (queue->fd) release_object( queue->fd );
|
||||||
|
@ -3070,7 +3114,11 @@ DECL_HANDLER(get_key_state)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
unsigned char *keystate = current->queue->input->keystate;
|
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 );
|
set_reply_data( keystate, size );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3084,6 +3132,7 @@ DECL_HANDLER(set_key_state)
|
||||||
data_size_t size = min( 256, get_req_data_size() );
|
data_size_t size = min( 256, get_req_data_size() );
|
||||||
|
|
||||||
memcpy( queue->input->keystate, 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 )))
|
if (req->async && (desktop = get_thread_desktop( current, 0 )))
|
||||||
{
|
{
|
||||||
memcpy( desktop->keystate, get_req_data(), size );
|
memcpy( desktop->keystate, get_req_data(), size );
|
||||||
|
|
Loading…
Reference in New Issue