diff --git a/patches/eventfd_synchronization/0020-server-Create-eventfd-file-descriptors-for-message-q.patch b/patches/eventfd_synchronization/0020-server-Create-eventfd-file-descriptors-for-message-q.patch index 922b0fd0..242e6f11 100644 --- a/patches/eventfd_synchronization/0020-server-Create-eventfd-file-descriptors-for-message-q.patch +++ b/patches/eventfd_synchronization/0020-server-Create-eventfd-file-descriptors-for-message-q.patch @@ -1,4 +1,4 @@ -From 1aac9111b536d35eec696e20141b6c5d6d92579b Mon Sep 17 00:00:00 2001 +From 2da453ad472ce69926e158bd4e933facd985d1cd Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 6 Jul 2020 16:01:56 -0500 Subject: [PATCH] server: Create eventfd file descriptors for message queues. @@ -8,7 +8,7 @@ Subject: [PATCH] server: Create eventfd file descriptors for message queues. 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/server/queue.c b/server/queue.c -index 263bb46ea00..4d416a88d88 100644 +index 1f1392387df..d34bc284d08 100644 --- a/server/queue.c +++ b/server/queue.c @@ -43,6 +43,7 @@ @@ -19,15 +19,15 @@ index 263bb46ea00..4d416a88d88 100644 #define WM_NCMOUSEFIRST WM_NCMOUSEMOVE #define WM_NCMOUSELAST (WM_NCMOUSEFIRST+(WM_MOUSELAST-WM_MOUSEFIRST)) -@@ -141,6 +142,7 @@ struct msg_queue - struct hook_table *hooks; /* hook table */ +@@ -144,6 +145,7 @@ struct msg_queue timeout_t last_get_msg; /* time of last get message call */ + int keystate_lock; /* owns an input keystate lock */ unsigned int ignore_post_msg; /* ignore post messages newer than this unique id */ + int esync_fd; /* esync file descriptor (signalled on message) */ }; struct hotkey -@@ -157,6 +159,7 @@ static void msg_queue_dump( struct object *obj, int verbose ); +@@ -160,6 +162,7 @@ static void msg_queue_dump( struct object *obj, int verbose ); static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *entry ); static void msg_queue_remove_queue( struct object *obj, struct wait_queue_entry *entry ); static int msg_queue_signaled( struct object *obj, struct wait_queue_entry *entry ); @@ -35,7 +35,7 @@ index 263bb46ea00..4d416a88d88 100644 static void msg_queue_satisfied( struct object *obj, struct wait_queue_entry *entry ); static void msg_queue_destroy( struct object *obj ); static void msg_queue_poll_event( struct fd *fd, int event ); -@@ -172,7 +175,7 @@ static const struct object_ops msg_queue_ops = +@@ -175,7 +178,7 @@ static const struct object_ops msg_queue_ops = msg_queue_add_queue, /* add_queue */ msg_queue_remove_queue, /* remove_queue */ msg_queue_signaled, /* signaled */ @@ -44,9 +44,9 @@ index 263bb46ea00..4d416a88d88 100644 msg_queue_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ -@@ -309,12 +312,16 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ - queue->hooks = NULL; +@@ -315,12 +318,16 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ queue->last_get_msg = current_time; + queue->keystate_lock = 0; queue->ignore_post_msg = 0; + queue->esync_fd = -1; list_init( &queue->send_result ); @@ -61,17 +61,17 @@ index 263bb46ea00..4d416a88d88 100644 thread->queue = queue; } if (new_input) release_object( new_input ); -@@ -491,6 +498,9 @@ static inline void clear_queue_bits( struct msg_queue *queue, unsigned int bits - { - queue->wake_bits &= ~bits; - queue->changed_bits &= ~bits; +@@ -534,6 +541,9 @@ static inline void clear_queue_bits( struct msg_queue *queue, unsigned int bits + if (queue->keystate_lock) unlock_input_keystate( queue->input ); + queue->keystate_lock = 0; + } + + if (do_esync() && !is_signaled( queue )) + esync_clear( queue->esync_fd ); } /* check whether msg is a keyboard message */ -@@ -1004,6 +1014,13 @@ static int msg_queue_signaled( struct object *obj, struct wait_queue_entry *entr +@@ -1047,6 +1057,13 @@ static int msg_queue_signaled( struct object *obj, struct wait_queue_entry *entr return ret || is_signaled( queue ); } @@ -85,7 +85,7 @@ index 263bb46ea00..4d416a88d88 100644 static void msg_queue_satisfied( struct object *obj, struct wait_queue_entry *entry ) { struct msg_queue *queue = (struct msg_queue *)obj; -@@ -2381,6 +2398,9 @@ DECL_HANDLER(get_queue_status) +@@ -2425,6 +2442,9 @@ DECL_HANDLER(get_queue_status) reply->wake_bits = queue->wake_bits; reply->changed_bits = queue->changed_bits; queue->changed_bits &= ~req->clear_bits; @@ -96,5 +96,5 @@ index 263bb46ea00..4d416a88d88 100644 else reply->wake_bits = reply->changed_bits = 0; } -- -2.28.0 +2.30.2 diff --git a/patches/eventfd_synchronization/0021-server-ntdll-Implement-message-waits.patch b/patches/eventfd_synchronization/0021-server-ntdll-Implement-message-waits.patch index f226f4d3..6459ab88 100644 --- a/patches/eventfd_synchronization/0021-server-ntdll-Implement-message-waits.patch +++ b/patches/eventfd_synchronization/0021-server-ntdll-Implement-message-waits.patch @@ -1,4 +1,4 @@ -From df50f6973c1fa60db18b408001ac50c03fb2fa07 Mon Sep 17 00:00:00 2001 +From e0a89702e35941e75ce06f795966c92b3f195ed8 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Mon, 6 Jul 2020 16:11:23 -0500 Subject: [PATCH] server, ntdll: Implement message waits. @@ -105,10 +105,10 @@ index fcbe563bb5a..88490e08ef9 100644 { struct stat st; diff --git a/server/protocol.def b/server/protocol.def -index 9062a5020c2..789bc56e7f1 100644 +index cf00ab99c63..ecbb78cc9bb 100644 --- a/server/protocol.def +++ b/server/protocol.def -@@ -3697,3 +3697,8 @@ enum esync_type +@@ -3734,3 +3734,8 @@ enum esync_type int type; unsigned int shm_idx; @END @@ -118,26 +118,26 @@ index 9062a5020c2..789bc56e7f1 100644 + int in_msgwait; /* are we in a message wait? */ +@END diff --git a/server/queue.c b/server/queue.c -index 4d416a88d88..efaf8a0f7e7 100644 +index d34bc284d08..f4edb299dc3 100644 --- a/server/queue.c +++ b/server/queue.c -@@ -143,6 +143,7 @@ struct msg_queue - timeout_t last_get_msg; /* time of last get message call */ +@@ -146,6 +146,7 @@ struct msg_queue + int keystate_lock; /* owns an input keystate lock */ unsigned int ignore_post_msg; /* ignore post messages newer than this unique id */ int esync_fd; /* esync file descriptor (signalled on message) */ + int esync_in_msgwait; /* our thread is currently waiting on us */ }; struct hotkey -@@ -313,6 +314,7 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ - queue->last_get_msg = current_time; +@@ -319,6 +320,7 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ + queue->keystate_lock = 0; queue->ignore_post_msg = 0; queue->esync_fd = -1; + queue->esync_in_msgwait = 0; list_init( &queue->send_result ); list_init( &queue->callback_result ); list_init( &queue->pending_timers ); -@@ -959,6 +961,10 @@ static int is_queue_hung( struct msg_queue *queue ) +@@ -1002,6 +1004,10 @@ static int is_queue_hung( struct msg_queue *queue ) if (get_wait_queue_thread(entry)->queue == queue) return 0; /* thread is waiting on queue -> not hung */ } @@ -148,7 +148,7 @@ index 4d416a88d88..efaf8a0f7e7 100644 return 1; } -@@ -3385,3 +3391,18 @@ DECL_HANDLER(get_rawinput_devices) +@@ -3416,3 +3422,18 @@ DECL_HANDLER(get_rawinput_devices) devices[i++] = e->device; } } @@ -168,5 +168,5 @@ index 4d416a88d88..efaf8a0f7e7 100644 + set_fd_events( queue->fd, req->in_msgwait ? POLLIN : 0 ); +} -- -2.28.0 +2.30.2 diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index d66dc910..bee4c70b 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -51,7 +51,7 @@ usage() # Get the upstream commit sha upstream_commit() { - echo "97b420224e767b24d89722ff5efeca38a8ecf1e2" + echo "2fcc1d0ecdebc55a5f515b1390ce715303f6a6ad" } # Show version information @@ -1449,6 +1449,13 @@ if test "$enable_eventfd_synchronization" -eq 1; then enable_server_Signal_Thread=1 fi +if test "$enable_server_PeekMessage" -eq 1; then + if test "$enable_server_Key_State" -gt 1; then + abort "Patchset server-Key_State disabled, but server-PeekMessage depends on that." + fi + enable_server_Key_State=1 +fi + if test "$enable_ntdll_Junction_Points" -eq 1; then if test "$enable_ntdll_DOS_Attributes" -gt 1; then abort "Patchset ntdll-DOS_Attributes disabled, but ntdll-Junction_Points depends on that." @@ -2303,8 +2310,30 @@ if test "$enable_ntdll_Junction_Points" -eq 1; then patch_apply ntdll-Junction_Points/0038-server-Rewrite-absolute-reparse-point-targets-if-the.patch fi +# Patchset server-Key_State +# | +# | This patchset fixes the following Wine bugs: +# | * [#26269] BioShock 2: Loss of keyboard input on loading screen +# | * [#31899] No keyboard input in La-Mulana remake (GetKeyState should behave similar to GetAsyncKeyState for specific +# | window messages / queue states) +# | * [#35907] Caps Lock state gets confused with multiple processes/threads +# | * [#45385] Wrong state of virtual keys after cycling windows. Usually VK_MENU, VK_SHIFT and VK_CONTROL, but every key can +# | be affected. +# | +# | Modified files: +# | * dlls/user32/tests/input.c, server/queue.c +# | +if test "$enable_server_Key_State" -eq 1; then + patch_apply server-Key_State/0001-server-Create-message-queue-and-thread-input-in-set_.patch + patch_apply server-Key_State/0002-server-Lock-thread-input-keystate-whenever-it-is-mod.patch + patch_apply server-Key_State/0003-server-Create-message-queue-and-thread-input-in-get_.patch +fi + # Patchset server-PeekMessage # | +# | This patchset has the following (direct or indirect) dependencies: +# | * server-Key_State +# | # | This patchset fixes the following Wine bugs: # | * [#28884] GetMessage should remove already seen messages with higher priority # | @@ -2336,8 +2365,8 @@ fi # Patchset eventfd_synchronization # | # | This patchset has the following (direct or indirect) dependencies: -# | * ntdll-DOS_Attributes, ntdll-NtQueryEaFile, ntdll-Junction_Points, server-PeekMessage, server-Realtime_Priority, server- -# | Signal_Thread +# | * ntdll-DOS_Attributes, ntdll-NtQueryEaFile, ntdll-Junction_Points, server-Key_State, server-PeekMessage, server- +# | Realtime_Priority, server-Signal_Thread # | # | This patchset fixes the following Wine bugs: # | * [#36692] Many multi-threaded applications have poor performance due to heavy use of synchronization primitives @@ -3324,20 +3353,6 @@ if test "$enable_server_File_Permissions" -eq 1; then patch_apply server-File_Permissions/0008-server-Improve-mapping-of-DACL-to-file-permissions.patch fi -# Patchset server-Key_State -# | -# | This patchset fixes the following Wine bugs: -# | * [#31899] Implement locking and synchronization of key states -# | * [#35907] Fix caps lock state issues with multiple processes -# | -# | Modified files: -# | * server/queue.c -# | -if test "$enable_server_Key_State" -eq 1; then - patch_apply server-Key_State/0001-server-Introduce-a-helper-function-to-update-the-thr.patch - patch_apply server-Key_State/0002-server-Implement-locking-and-synchronization-of-keys.patch -fi - # Patchset server-Stored_ACLs # | # | This patchset has the following (direct or indirect) dependencies: diff --git a/patches/server-Key_State/0001-server-Create-message-queue-and-thread-input-in-set_.patch b/patches/server-Key_State/0001-server-Create-message-queue-and-thread-input-in-set_.patch new file mode 100644 index 00000000..31b611b2 --- /dev/null +++ b/patches/server-Key_State/0001-server-Create-message-queue-and-thread-input-in-set_.patch @@ -0,0 +1,167 @@ +From 4778b1c3d59bd87b067b6266e38ddd9a5d8bae86 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Thu, 1 Apr 2021 23:19:18 +0200 +Subject: [PATCH] server: Create message queue and thread input in + set_key_state. + +This marks one test case as todo, but it was an outlier, and the 'X' key +state is now wrong in all cases. Overall this makes the tests results +more coherent. + +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 +--- + dlls/user32/tests/input.c | 52 +++++++++++++++++++-------------------- + server/queue.c | 3 ++- + 2 files changed, 28 insertions(+), 27 deletions(-) + +diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c +index 63163b7ed01..c146e4b5cd9 100644 +--- a/dlls/user32/tests/input.c ++++ b/dlls/user32/tests/input.c +@@ -3761,8 +3761,8 @@ struct get_key_state_thread_params + int index; + }; + +-#define check_get_keyboard_state(i, j, c, x, todo_c, todo_x) check_get_keyboard_state_(i, j, c, x, todo_c, todo_x, __LINE__) +-static void check_get_keyboard_state_(int i, int j, int c, int x, int todo_c, int todo_x, int line) ++#define check_get_keyboard_state(i, j, c, x, todo_x) check_get_keyboard_state_(i, j, c, x, todo_x, __LINE__) ++static void check_get_keyboard_state_(int i, int j, int c, int x, int todo_x, int line) + { + unsigned char keystate[256]; + BOOL ret; +@@ -3771,18 +3771,18 @@ static void check_get_keyboard_state_(int i, int j, int c, int x, int todo_c, in + ret = GetKeyboardState(keystate); + ok_(__FILE__, line)(ret, "GetKeyboardState failed, %u\n", GetLastError()); + todo_wine_if(todo_x) ok_(__FILE__, line)(!(keystate['X'] & 0x80) == !x, "%d:%d: expected that X keystate is %s\n", i, j, x ? "set" : "unset"); +- todo_wine_if(todo_c) ok_(__FILE__, line)(!(keystate['C'] & 0x80) == !c, "%d:%d: expected that C keystate is %s\n", i, j, c ? "set" : "unset"); ++ ok_(__FILE__, line)(!(keystate['C'] & 0x80) == !c, "%d:%d: expected that C keystate is %s\n", i, j, c ? "set" : "unset"); + + /* calling it twice shouldn't change */ + memset(keystate, 0, sizeof(keystate)); + ret = GetKeyboardState(keystate); + ok_(__FILE__, line)(ret, "GetKeyboardState failed, %u\n", GetLastError()); + todo_wine_if(todo_x) ok_(__FILE__, line)(!(keystate['X'] & 0x80) == !x, "%d:%d: expected that X keystate is %s\n", i, j, x ? "set" : "unset"); +- todo_wine_if(todo_c) ok_(__FILE__, line)(!(keystate['C'] & 0x80) == !c, "%d:%d: expected that C keystate is %s\n", i, j, c ? "set" : "unset"); ++ ok_(__FILE__, line)(!(keystate['C'] & 0x80) == !c, "%d:%d: expected that C keystate is %s\n", i, j, c ? "set" : "unset"); + } + +-#define check_get_key_state(i, j, c, x, todo_c, todo_x) check_get_key_state_(i, j, c, x, todo_c, todo_x, __LINE__) +-static void check_get_key_state_(int i, int j, int c, int x, int todo_c, int todo_x, int line) ++#define check_get_key_state(i, j, c, x, todo_x) check_get_key_state_(i, j, c, x, todo_x, __LINE__) ++static void check_get_key_state_(int i, int j, int c, int x, int todo_x, int line) + { + SHORT state; + +@@ -3791,7 +3791,7 @@ static void check_get_key_state_(int i, int j, int c, int x, int todo_c, int tod + ok_(__FILE__, line)(!(state & 0x007e), "%d:%d: expected that X undefined bits are unset, got %#x\n", i, j, state); + + state = GetKeyState('C'); +- todo_wine_if(todo_c) ok_(__FILE__, line)(!(state & 0x8000) == !c, "%d:%d: expected that C highest bit is %s, got %#x\n", i, j, c ? "set" : "unset", state); ++ ok_(__FILE__, line)(!(state & 0x8000) == !c, "%d:%d: expected that C highest bit is %s, got %#x\n", i, j, c ? "set" : "unset", state); + ok_(__FILE__, line)(!(state & 0x007e), "%d:%d: expected that C undefined bits are unset, got %#x\n", i, j, state); + } + +@@ -3808,7 +3808,7 @@ static DWORD WINAPI get_key_state_thread(void *arg) + int i = params->index, j; + + test = get_key_state_tests + i; +- has_queue = test->peek_message; ++ has_queue = test->peek_message || test->set_keyboard_state; + + if (test->peek_message) + { +@@ -3841,18 +3841,18 @@ static DWORD WINAPI get_key_state_thread(void *arg) + if (test->set_keyboard_state) expect_c = TRUE; + else expect_c = FALSE; + +- check_get_keyboard_state(i, j, expect_c, FALSE, /* todo */ i == 6, !has_queue); +- check_get_key_state(i, j, expect_c, expect_x, /* todo */ i == 6, i != 6 && (has_queue || j == 0)); +- check_get_keyboard_state(i, j, expect_c, expect_x, /* todo */ i == 6, i != 6 && (has_queue || j == 0)); ++ 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); + + /* 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 */ i == 6, has_queue || i == 6 || j > 0); +- check_get_key_state(i, j, expect_c, FALSE, /* todo */ i == 6, FALSE); +- check_get_keyboard_state(i, j, expect_c, FALSE, /* todo */ i == 6, FALSE); ++ 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); + } + + return 0; +@@ -3920,18 +3920,18 @@ static void test_GetKeyState(void) + } + else expect_c = FALSE; + +- check_get_keyboard_state(i, j, expect_c, FALSE, /* todo */ FALSE, FALSE); +- check_get_key_state(i, j, expect_c, FALSE, /* todo */ FALSE, FALSE); +- check_get_keyboard_state(i, j, expect_c, FALSE, /* todo */ FALSE, FALSE); ++ check_get_keyboard_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); + + if (test->peek_message_main) while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); + + if (test->peek_message_main) expect_x = TRUE; + else expect_x = FALSE; + +- check_get_keyboard_state(i, j, expect_c, expect_x, /* todo */ FALSE, FALSE); +- check_get_key_state(i, j, expect_c, expect_x, /* todo */ FALSE, FALSE); +- check_get_keyboard_state(i, j, expect_c, expect_x, /* todo */ FALSE, FALSE); ++ check_get_keyboard_state(i, j, expect_c, expect_x, /* todo */ FALSE); ++ check_get_key_state(i, j, expect_c, expect_x, /* todo */ FALSE); ++ check_get_keyboard_state(i, j, expect_c, expect_x, /* todo */ FALSE); + + ReleaseSemaphore(params.semaphores[1], 1, NULL); + +@@ -3947,15 +3947,15 @@ static void test_GetKeyState(void) + SetKeyboardState(keystate); + } + +- check_get_keyboard_state(i, j, FALSE, expect_x, /* todo */ FALSE, FALSE); +- check_get_key_state(i, j, FALSE, expect_x, /* todo */ FALSE, FALSE); +- check_get_keyboard_state(i, j, FALSE, expect_x, /* todo */ FALSE, FALSE); ++ check_get_keyboard_state(i, j, FALSE, expect_x, /* todo */ FALSE); ++ check_get_key_state(i, j, FALSE, expect_x, /* todo */ FALSE); ++ check_get_keyboard_state(i, j, FALSE, expect_x, /* todo */ FALSE); + + if (test->peek_message_main) while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); + +- check_get_keyboard_state(i, j, FALSE, FALSE, /* todo */ FALSE, FALSE); +- check_get_key_state(i, j, FALSE, FALSE, /* todo */ FALSE, FALSE); +- check_get_keyboard_state(i, j, FALSE, FALSE, /* todo */ FALSE, FALSE); ++ check_get_keyboard_state(i, j, FALSE, FALSE, /* todo */ FALSE); ++ check_get_key_state(i, j, FALSE, FALSE, /* todo */ FALSE); ++ check_get_keyboard_state(i, j, FALSE, FALSE, /* todo */ FALSE); + + ReleaseSemaphore(params.semaphores[1], 1, NULL); + } +diff --git a/server/queue.c b/server/queue.c +index b026c03e13d..5c9f91a13c5 100644 +--- a/server/queue.c ++++ b/server/queue.c +@@ -3007,9 +3007,10 @@ DECL_HANDLER(get_key_state) + DECL_HANDLER(set_key_state) + { + struct desktop *desktop; ++ struct msg_queue *queue = get_current_queue(); + data_size_t size = min( 256, get_req_data_size() ); + +- if (current->queue) memcpy( current->queue->input->keystate, get_req_data(), size ); ++ memcpy( queue->input->keystate, get_req_data(), size ); + if (req->async && (desktop = get_thread_desktop( current, 0 ))) + { + memcpy( desktop->keystate, get_req_data(), size ); +-- +2.30.2 + diff --git a/patches/server-Key_State/0001-server-Introduce-a-helper-function-to-update-the-thr.patch b/patches/server-Key_State/0001-server-Introduce-a-helper-function-to-update-the-thr.patch deleted file mode 100644 index e769fb34..00000000 --- a/patches/server-Key_State/0001-server-Introduce-a-helper-function-to-update-the-thr.patch +++ /dev/null @@ -1,120 +0,0 @@ -From be8f547f53a1f8d35d9680a8cb2f0cfa808568b8 Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Thu, 12 Mar 2015 00:44:25 +0100 -Subject: [PATCH] server: Introduce a helper function to update the - thread_input key state. - ---- - server/queue.c | 40 +++++++++++++++++++++++----------------- - 1 file changed, 23 insertions(+), 17 deletions(-) - -diff --git a/server/queue.c b/server/queue.c -index 7e7e6fbdf29..344e4298a56 100644 ---- a/server/queue.c -+++ b/server/queue.c -@@ -1300,9 +1300,9 @@ static void set_input_key_state( unsigned char *keystate, unsigned char key, int - else keystate[key] &= ~0x80; - } - --/* update the input key state for a keyboard message */ --static void update_input_key_state( struct desktop *desktop, unsigned char *keystate, -- unsigned int msg, lparam_t wparam ) -+/* update the key state for a keyboard message */ -+static void update_key_state( struct desktop *desktop, unsigned char *keystate, -+ unsigned int msg, lparam_t wparam ) - { - unsigned char key; - int down = 0; -@@ -1371,21 +1371,27 @@ static void update_desktop_mouse_state( struct desktop *desktop, unsigned int fl - if (flags & MOUSEEVENTF_MOVE) - update_desktop_cursor_pos( desktop, x, y ); - if (flags & MOUSEEVENTF_LEFTDOWN) -- update_input_key_state( desktop, desktop->keystate, WM_LBUTTONDOWN, wparam ); -+ update_key_state( desktop, desktop->keystate, WM_LBUTTONDOWN, wparam ); - if (flags & MOUSEEVENTF_LEFTUP) -- update_input_key_state( desktop, desktop->keystate, WM_LBUTTONUP, wparam ); -+ update_key_state( desktop, desktop->keystate, WM_LBUTTONUP, wparam ); - if (flags & MOUSEEVENTF_RIGHTDOWN) -- update_input_key_state( desktop, desktop->keystate, WM_RBUTTONDOWN, wparam ); -+ update_key_state( desktop, desktop->keystate, WM_RBUTTONDOWN, wparam ); - if (flags & MOUSEEVENTF_RIGHTUP) -- update_input_key_state( desktop, desktop->keystate, WM_RBUTTONUP, wparam ); -+ update_key_state( desktop, desktop->keystate, WM_RBUTTONUP, wparam ); - if (flags & MOUSEEVENTF_MIDDLEDOWN) -- update_input_key_state( desktop, desktop->keystate, WM_MBUTTONDOWN, wparam ); -+ update_key_state( desktop, desktop->keystate, WM_MBUTTONDOWN, wparam ); - if (flags & MOUSEEVENTF_MIDDLEUP) -- update_input_key_state( desktop, desktop->keystate, WM_MBUTTONUP, wparam ); -+ update_key_state( desktop, desktop->keystate, WM_MBUTTONUP, wparam ); - if (flags & MOUSEEVENTF_XDOWN) -- update_input_key_state( desktop, desktop->keystate, WM_XBUTTONDOWN, wparam ); -+ update_key_state( desktop, desktop->keystate, WM_XBUTTONDOWN, wparam ); - if (flags & MOUSEEVENTF_XUP) -- update_input_key_state( desktop, desktop->keystate, WM_XBUTTONUP, wparam ); -+ update_key_state( desktop, desktop->keystate, WM_XBUTTONUP, wparam ); -+} -+ -+/* update the thread input key state for a keyboard message */ -+static void update_input_key_state( struct thread_input *input, unsigned int msg, lparam_t wparam ) -+{ -+ update_key_state( input->desktop, input->keystate, msg, wparam ); - } - - /* release the hardware message currently being processed by the given thread */ -@@ -1413,7 +1419,7 @@ static void release_hardware_message( struct msg_queue *queue, unsigned int hw_i - } - if (clr_bit) clear_queue_bits( queue, clr_bit ); - -- update_input_key_state( input->desktop, input->keystate, msg->msg, msg->wparam ); -+ update_input_key_state( input, msg->msg, msg->wparam ); - list_remove( &msg->entry ); - free_message( msg ); - } -@@ -1542,7 +1548,7 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg - struct hardware_msg_data *msg_data = msg->data; - unsigned int msg_code; - -- update_input_key_state( desktop, desktop->keystate, msg->msg, msg->wparam ); -+ update_key_state( desktop, desktop->keystate, msg->msg, msg->wparam ); - last_input_time = get_tick_count(); - if (msg->msg != WM_MOUSEMOVE) always_queue = 1; - -@@ -1581,7 +1587,7 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg - win = find_hardware_message_window( desktop, input, msg, &msg_code, &thread ); - if (!win || !thread) - { -- if (input) update_input_key_state( input->desktop, input->keystate, msg->msg, msg->wparam ); -+ if (input) update_input_key_state( input, msg->msg, msg->wparam ); - free_message( msg ); - return; - } -@@ -1919,7 +1925,7 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c - - if ((device = current->process->rawinput_kbd) && (device->flags & RIDEV_NOLEGACY)) - { -- update_input_key_state( desktop, desktop->keystate, message_code, vkey ); -+ update_key_state( desktop, desktop->keystate, message_code, vkey ); - return 0; - } - -@@ -2048,7 +2054,7 @@ static int get_hardware_message( struct thread *thread, unsigned int hw_id, user - if (!win || !win_thread) - { - /* no window at all, remove it */ -- update_input_key_state( input->desktop, input->keystate, msg->msg, msg->wparam ); -+ update_input_key_state( input, msg->msg, msg->wparam ); - list_remove( &msg->entry ); - free_message( msg ); - continue; -@@ -2064,7 +2070,7 @@ static int get_hardware_message( struct thread *thread, unsigned int hw_id, user - else - { - /* for another thread input, drop it */ -- update_input_key_state( input->desktop, input->keystate, msg->msg, msg->wparam ); -+ update_input_key_state( input, msg->msg, msg->wparam ); - list_remove( &msg->entry ); - free_message( msg ); - } --- -2.28.0 - diff --git a/patches/server-Key_State/0002-server-Implement-locking-and-synchronization-of-keys.patch b/patches/server-Key_State/0002-server-Implement-locking-and-synchronization-of-keys.patch deleted file mode 100644 index 7b4286ba..00000000 --- a/patches/server-Key_State/0002-server-Implement-locking-and-synchronization-of-keys.patch +++ /dev/null @@ -1,162 +0,0 @@ -From b4259641f65faa6272c882019d773989b1f1d3d4 Mon Sep 17 00:00:00 2001 -From: Sebastian Lackner -Date: Fri, 10 Jul 2015 16:13:53 +0200 -Subject: [PATCH] server: Implement locking and synchronization of keystate - buffer. (rev 3) - ---- - server/queue.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++-- - 1 file changed, 57 insertions(+), 2 deletions(-) - -diff --git a/server/queue.c b/server/queue.c -index cd84684d4a0..77496da03ca 100644 ---- a/server/queue.c -+++ b/server/queue.c -@@ -113,7 +113,9 @@ struct thread_input - user_handle_t cursor; /* current cursor */ - int cursor_count; /* cursor show count */ - struct list msg_list; /* list of hardware messages */ -+ int lock_count; /* lock counter for keystate */ - unsigned char keystate[256]; /* state of each key */ -+ unsigned char shadow_keystate[256]; /* shadow copy of keystate */ - }; - - struct msg_queue -@@ -124,6 +126,7 @@ struct msg_queue - unsigned int wake_mask; /* wakeup mask */ - unsigned int changed_bits; /* changed wakeup bits */ - unsigned int changed_mask; /* changed wakeup mask */ -+ int keystate_locked; /* keystate is locked */ - int paint_count; /* pending paint messages count */ - int hotkey_count; /* pending hotkey messages count */ - int quit_message; /* is there a pending quit message? */ -@@ -259,9 +262,11 @@ static struct thread_input *create_thread_input( struct thread *thread ) - input->move_size = 0; - input->cursor = 0; - input->cursor_count = 0; -+ input->lock_count = 0; - list_init( &input->msg_list ); - set_caret_window( input, 0 ); - memset( input->keystate, 0, sizeof(input->keystate) ); -+ memset( input->shadow_keystate, 0, sizeof(input->shadow_keystate) ); - - if (!(input->desktop = get_thread_desktop( thread, 0 /* FIXME: access rights */ ))) - { -@@ -292,6 +297,7 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ - queue->wake_mask = 0; - queue->changed_bits = 0; - queue->changed_mask = 0; -+ queue->keystate_locked = 0; - queue->paint_count = 0; - queue->hotkey_count = 0; - queue->quit_message = 0; -@@ -335,8 +341,10 @@ static int assign_thread_input( struct thread *thread, struct thread_input *new_ - } - if (queue->input) - { -+ if (queue->keystate_locked) queue->input->lock_count--; - queue->input->cursor_count -= queue->cursor_count; - release_object( queue->input ); -+ queue->keystate_locked = 0; - } - queue->input = (struct thread_input *)grab_object( new_input ); - new_input->cursor_count += queue->cursor_count; -@@ -1027,6 +1035,7 @@ static void msg_queue_destroy( struct object *obj ) - free( timer ); - } - if (queue->timeout) remove_timeout_user( queue->timeout ); -+ if (queue->keystate_locked) queue->input->lock_count--; - queue->input->cursor_count -= queue->cursor_count; - release_object( queue->input ); - if (queue->hooks) release_object( queue->hooks ); -@@ -1127,7 +1136,11 @@ 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) -+ { -+ memset( input->keystate, 0, sizeof(input->keystate) ); -+ memset( input->shadow_keystate, 0, sizeof(input->shadow_keystate) ); -+ } - release_object( input ); - return ret; - } -@@ -1385,9 +1398,30 @@ static void update_desktop_mouse_state( struct desktop *desktop, unsigned int fl - update_key_state( desktop, desktop->keystate, WM_XBUTTONUP, wparam ); - } - -+/* synchronizes the thread input key state with the desktop */ -+static void synchronize_input_key_state( struct thread_input *input ) -+{ -+ if (!input->lock_count) -+ { -+ unsigned char *shadow_keystate = input->shadow_keystate; -+ unsigned char *keystate = input->keystate; -+ unsigned int i; -+ -+ for (i = 0; i < 256; i++) -+ { -+ if (input->desktop->keystate[i] != shadow_keystate[i]) -+ { -+ keystate[i] = input->desktop->keystate[i] & ~0x40; -+ shadow_keystate[i] = input->desktop->keystate[i]; -+ } -+ } -+ } -+} -+ - /* update the thread input key state for a keyboard message */ - static void update_input_key_state( struct thread_input *input, unsigned int msg, lparam_t wparam ) - { -+ synchronize_input_key_state( input ); - update_key_state( input->desktop, input->keystate, msg, wparam ); - } - -@@ -1588,6 +1622,15 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg - else - { - msg->unique_id = 0; /* will be set once we return it to the app */ -+ -+ /* lock the keystate on the first hardware message */ -+ if (!thread->queue->keystate_locked) -+ { -+ synchronize_input_key_state( input ); -+ input->lock_count++; -+ thread->queue->keystate_locked = 1; -+ } -+ - list_add_tail( &input->msg_list, &msg->entry ); - set_queue_bits( thread->queue, get_hardware_msg_bit(msg) ); - } -@@ -2526,6 +2569,13 @@ DECL_HANDLER(get_message) - queue->last_get_msg = current_time; - if (!filter) filter = QS_ALLINPUT; - -+ /* no longer lock the keystate if we have processed all input */ -+ if (queue->keystate_locked && !(queue->wake_bits & QS_ALLINPUT)) -+ { -+ queue->input->lock_count--; -+ queue->keystate_locked = 0; -+ } -+ - /* first check for sent messages */ - if ((ptr = list_head( &queue->msg_list[SEND_MESSAGE] ))) - { -@@ -2982,7 +3032,12 @@ DECL_HANDLER(get_key_state) - if (!(thread = get_thread_from_id( req->tid ))) return; - if (thread->queue) - { -- if (req->key >= 0) reply->state = thread->queue->input->keystate[req->key & 0xff]; -+ if (req->key >= 0) -+ { -+ /* synchronize with desktop keystate, but _only_ if req->key is given */ -+ synchronize_input_key_state( thread->queue->input ); -+ reply->state = thread->queue->input->keystate[req->key & 0xff]; -+ } - set_reply_data( thread->queue->input->keystate, size ); - release_object( thread ); - return; --- -2.27.0 - diff --git a/patches/server-Key_State/0002-server-Lock-thread-input-keystate-whenever-it-is-mod.patch b/patches/server-Key_State/0002-server-Lock-thread-input-keystate-whenever-it-is-mod.patch new file mode 100644 index 00000000..db1418af --- /dev/null +++ b/patches/server-Key_State/0002-server-Lock-thread-input-keystate-whenever-it-is-mod.patch @@ -0,0 +1,187 @@ +From a6f4d1c57d31c0a8f50afd5af9d50b7e587c84f5 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Thu, 1 Apr 2021 23:30:46 +0200 +Subject: [PATCH] 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 . + +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 +--- + 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 ); +-- +2.30.2 + diff --git a/patches/server-Key_State/0003-server-Create-message-queue-and-thread-input-in-get_.patch b/patches/server-Key_State/0003-server-Create-message-queue-and-thread-input-in-get_.patch new file mode 100644 index 00000000..49d60fe5 --- /dev/null +++ b/patches/server-Key_State/0003-server-Create-message-queue-and-thread-input-in-get_.patch @@ -0,0 +1,172 @@ +From a6a449881f6643183316ad867b49bd99f53fa4a4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Thu, 1 Apr 2021 23:41:31 +0200 +Subject: [PATCH] server: Create message queue and thread input in + get_key_state. + +This removes the fallback to desktop async keystate and uses instead the +keystate synchronization logic in all cases. + +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 +--- + dlls/user32/tests/input.c | 50 +++++++++++++++++++-------------------- + server/queue.c | 18 +++----------- + 2 files changed, 28 insertions(+), 40 deletions(-) + +diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c +index 246569961be..561f932b18b 100644 +--- a/dlls/user32/tests/input.c ++++ b/dlls/user32/tests/input.c +@@ -3761,8 +3761,8 @@ struct get_key_state_thread_params + int index; + }; + +-#define check_get_keyboard_state(i, j, c, x, todo_x) check_get_keyboard_state_(i, j, c, x, todo_x, __LINE__) +-static void check_get_keyboard_state_(int i, int j, int c, int x, int todo_x, int line) ++#define check_get_keyboard_state(i, j, c, x) check_get_keyboard_state_(i, j, c, x, __LINE__) ++static void check_get_keyboard_state_(int i, int j, int c, int x, int line) + { + unsigned char keystate[256]; + BOOL ret; +@@ -3770,24 +3770,24 @@ static void check_get_keyboard_state_(int i, int j, int c, int x, int todo_x, in + memset(keystate, 0, sizeof(keystate)); + ret = GetKeyboardState(keystate); + ok_(__FILE__, line)(ret, "GetKeyboardState failed, %u\n", GetLastError()); +- todo_wine_if(todo_x) ok_(__FILE__, line)(!(keystate['X'] & 0x80) == !x, "%d:%d: expected that X keystate is %s\n", i, j, x ? "set" : "unset"); ++ ok_(__FILE__, line)(!(keystate['X'] & 0x80) == !x, "%d:%d: expected that X keystate is %s\n", i, j, x ? "set" : "unset"); + ok_(__FILE__, line)(!(keystate['C'] & 0x80) == !c, "%d:%d: expected that C keystate is %s\n", i, j, c ? "set" : "unset"); + + /* calling it twice shouldn't change */ + memset(keystate, 0, sizeof(keystate)); + ret = GetKeyboardState(keystate); + ok_(__FILE__, line)(ret, "GetKeyboardState failed, %u\n", GetLastError()); +- todo_wine_if(todo_x) ok_(__FILE__, line)(!(keystate['X'] & 0x80) == !x, "%d:%d: expected that X keystate is %s\n", i, j, x ? "set" : "unset"); ++ ok_(__FILE__, line)(!(keystate['X'] & 0x80) == !x, "%d:%d: expected that X keystate is %s\n", i, j, x ? "set" : "unset"); + ok_(__FILE__, line)(!(keystate['C'] & 0x80) == !c, "%d:%d: expected that C keystate is %s\n", i, j, c ? "set" : "unset"); + } + +-#define check_get_key_state(i, j, c, x, todo_x) check_get_key_state_(i, j, c, x, todo_x, __LINE__) +-static void check_get_key_state_(int i, int j, int c, int x, int todo_x, int line) ++#define check_get_key_state(i, j, c, x) check_get_key_state_(i, j, c, x, __LINE__) ++static void check_get_key_state_(int i, int j, int c, int x, int line) + { + SHORT state; + + state = GetKeyState('X'); +- todo_wine_if(todo_x) ok_(__FILE__, line)(!(state & 0x8000) == !x, "%d:%d: expected that X highest bit is %s, got %#x\n", i, j, x ? "set" : "unset", state); ++ ok_(__FILE__, line)(!(state & 0x8000) == !x, "%d:%d: expected that X highest bit is %s, got %#x\n", i, j, x ? "set" : "unset", state); + ok_(__FILE__, line)(!(state & 0x007e), "%d:%d: expected that X undefined bits are unset, got %#x\n", i, j, state); + + state = GetKeyState('C'); +@@ -3841,18 +3841,18 @@ static DWORD WINAPI get_key_state_thread(void *arg) + if (test->set_keyboard_state) expect_c = TRUE; + 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_keyboard_state(i, j, expect_c, FALSE); ++ check_get_key_state(i, j, expect_c, expect_x); ++ check_get_keyboard_state(i, j, expect_c, expect_x); + + /* 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_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, expect_x); ++ check_get_key_state(i, j, expect_c, FALSE); ++ check_get_keyboard_state(i, j, expect_c, FALSE); + } + + return 0; +@@ -3920,18 +3920,18 @@ static void test_GetKeyState(void) + } + else expect_c = FALSE; + +- check_get_keyboard_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); ++ check_get_key_state(i, j, expect_c, FALSE); ++ check_get_keyboard_state(i, j, expect_c, FALSE); + + if (test->peek_message_main) while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); + + if (test->peek_message_main) expect_x = TRUE; + else expect_x = FALSE; + +- check_get_keyboard_state(i, j, expect_c, expect_x, /* todo */ FALSE); +- check_get_key_state(i, j, expect_c, expect_x, /* todo */ FALSE); +- check_get_keyboard_state(i, j, expect_c, expect_x, /* todo */ FALSE); ++ check_get_keyboard_state(i, j, expect_c, expect_x); ++ check_get_key_state(i, j, expect_c, expect_x); ++ check_get_keyboard_state(i, j, expect_c, expect_x); + + ReleaseSemaphore(params.semaphores[1], 1, NULL); + +@@ -3947,15 +3947,15 @@ static void test_GetKeyState(void) + SetKeyboardState(keystate); + } + +- check_get_keyboard_state(i, j, FALSE, expect_x, /* todo */ FALSE); +- check_get_key_state(i, j, FALSE, expect_x, /* todo */ FALSE); +- check_get_keyboard_state(i, j, FALSE, expect_x, /* todo */ FALSE); ++ check_get_keyboard_state(i, j, FALSE, expect_x); ++ check_get_key_state(i, j, FALSE, expect_x); ++ check_get_keyboard_state(i, j, FALSE, expect_x); + + if (test->peek_message_main) while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); + +- check_get_keyboard_state(i, j, FALSE, FALSE, /* todo */ FALSE); +- check_get_key_state(i, j, FALSE, FALSE, /* todo */ FALSE); +- check_get_keyboard_state(i, j, FALSE, FALSE, /* todo */ FALSE); ++ check_get_keyboard_state(i, j, FALSE, FALSE); ++ check_get_key_state(i, j, FALSE, FALSE); ++ check_get_keyboard_state(i, j, FALSE, FALSE); + + ReleaseSemaphore(params.semaphores[1], 1, NULL); + } +diff --git a/server/queue.c b/server/queue.c +index 0782c526327..fce65e360d4 100644 +--- a/server/queue.c ++++ b/server/queue.c +@@ -3025,25 +3025,13 @@ DECL_HANDLER(get_key_state) + set_reply_data( desktop->keystate, size ); + release_object( desktop ); + } +- else if (!current->queue) +- { +- unsigned char *keystate; +- /* fallback to desktop keystate */ +- if (!(desktop = get_thread_desktop( current, 0 ))) return; +- if (req->key >= 0) reply->state = desktop->keystate[req->key & 0xff] & ~0x40; +- if ((keystate = set_reply_data_size( size ))) +- { +- unsigned int i; +- for (i = 0; i < size; i++) keystate[i] = desktop->keystate[i] & ~0x40; +- } +- release_object( desktop ); +- } + else + { +- unsigned char *keystate = current->queue->input->keystate; ++ struct msg_queue *queue = get_current_queue(); ++ unsigned char *keystate = queue->input->keystate; + if (req->key >= 0) + { +- if (current->queue) sync_input_keystate( current->queue->input ); ++ sync_input_keystate( queue->input ); + reply->state = keystate[req->key & 0xff]; + } + set_reply_data( keystate, size ); +-- +2.30.2 + diff --git a/patches/server-Key_State/definition b/patches/server-Key_State/definition index a9ebdedd..a8d71deb 100644 --- a/patches/server-Key_State/definition +++ b/patches/server-Key_State/definition @@ -1,5 +1,5 @@ -# Fixes: [27238] Fallback to global key state for threads without a queue -Fixes: [31899] Implement locking and synchronization of key states -Fixes: [35907] Fix caps lock state issues with multiple processes -# Please review this for correctness; rebasing against 8cf7fe3b7c2 may have -# broken it. +Fixes: [26269] BioShock 2: Loss of keyboard input on loading screen +# Fixes: [27238] Tesla: The Weather Man demo: movement keys not working (GetKeyState should fallback to GetAsyncKeyState for threads without message queue) +Fixes: [31899] No keyboard input in La-Mulana remake (GetKeyState should behave similar to GetAsyncKeyState for specific window messages / queue states) +Fixes: [35907] Caps Lock state gets confused with multiple processes/threads +Fixes: [45385] Wrong state of virtual keys after cycling windows. Usually VK_MENU, VK_SHIFT and VK_CONTROL, but every key can be affected. diff --git a/patches/server-PeekMessage/0001-server-Fix-handling-of-GetMessage-after-previous-Pee.patch b/patches/server-PeekMessage/0001-server-Fix-handling-of-GetMessage-after-previous-Pee.patch index ce7ec607..e7d174c7 100644 --- a/patches/server-PeekMessage/0001-server-Fix-handling-of-GetMessage-after-previous-Pee.patch +++ b/patches/server-PeekMessage/0001-server-Fix-handling-of-GetMessage-after-previous-Pee.patch @@ -1,4 +1,4 @@ -From c527f32596831ae31b055cd77cb3bc848f83a8a8 Mon Sep 17 00:00:00 2001 +From 9875a6033aaa0043a7c29926a026ecafb56382e6 Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Sun, 15 Mar 2015 01:05:48 +0100 Subject: [PATCH] server: Fix handling of GetMessage after previous PeekMessage @@ -15,10 +15,10 @@ Changes in v3: 2 files changed, 62 insertions(+), 17 deletions(-) diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c -index f84525a0bf9..80cc0daa6c6 100644 +index 7eaa2c67945..8f8b1b98933 100644 --- a/dlls/user32/tests/msg.c +++ b/dlls/user32/tests/msg.c -@@ -12429,13 +12429,10 @@ static void test_PeekMessage3(void) +@@ -12648,13 +12648,10 @@ static void test_PeekMessage3(void) ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message); PostMessageA(hwnd, WM_USER, 0, 0); ret = PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE); @@ -32,7 +32,7 @@ index f84525a0bf9..80cc0daa6c6 100644 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message); ret = PeekMessageA(&msg, NULL, 0, 0, 0); ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret); -@@ -12445,10 +12442,8 @@ static void test_PeekMessage3(void) +@@ -12664,10 +12661,8 @@ static void test_PeekMessage3(void) ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message); PostMessageA(hwnd, WM_USER, 0, 0); ret = PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE); @@ -43,7 +43,7 @@ index f84525a0bf9..80cc0daa6c6 100644 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message); ret = PeekMessageA(&msg, NULL, 0, 0, 0); ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret); -@@ -12460,10 +12455,8 @@ static void test_PeekMessage3(void) +@@ -12679,10 +12674,8 @@ static void test_PeekMessage3(void) ok(msg.message == WM_TIMER, "msg.message = %u instead of WM_TIMER\n", msg.message); PostMessageA(hwnd, WM_USER, 0, 0); ret = GetMessageA(&msg, NULL, 0, 0); @@ -54,7 +54,7 @@ index f84525a0bf9..80cc0daa6c6 100644 ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message); ret = PeekMessageA(&msg, NULL, 0, 0, 0); ok(!ret, "expected PeekMessage to return FALSE, got %u\n", ret); -@@ -12491,14 +12484,32 @@ static void test_PeekMessage3(void) +@@ -12710,14 +12703,32 @@ static void test_PeekMessage3(void) ret = GetMessageA(&msg, NULL, 0, 0); ok(ret && msg.message == WM_USER, "msg.message = %u instead of WM_USER\n", msg.message); ret = GetMessageA(&msg, NULL, 0, 0); @@ -90,26 +90,26 @@ index f84525a0bf9..80cc0daa6c6 100644 * because both messages are in the same queue. */ diff --git a/server/queue.c b/server/queue.c -index a65eab38bdc..bf315f5008c 100644 +index fce65e360d4..451aaeca008 100644 --- a/server/queue.c +++ b/server/queue.c -@@ -140,6 +140,7 @@ struct msg_queue - struct thread_input *input; /* thread input descriptor */ +@@ -143,6 +143,7 @@ struct msg_queue 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 */ + unsigned int ignore_post_msg; /* ignore post messages newer than this unique id */ }; struct hotkey -@@ -300,6 +301,7 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ - queue->input = (struct thread_input *)grab_object( input ); +@@ -311,6 +312,7 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ queue->hooks = NULL; queue->last_get_msg = current_time; + queue->keystate_lock = 0; + queue->ignore_post_msg = 0; list_init( &queue->send_result ); list_init( &queue->callback_result ); list_init( &queue->pending_timers ); -@@ -529,13 +531,21 @@ static inline struct msg_queue *get_current_queue(void) +@@ -577,13 +579,21 @@ static inline struct msg_queue *get_current_queue(void) } /* get a (pseudo-)unique id to tag hardware messages */ @@ -132,7 +132,7 @@ index a65eab38bdc..bf315f5008c 100644 /* try to merge a message with the last in the list; return 1 if successful */ static int merge_message( struct thread_input *input, const struct message *msg ) { -@@ -813,7 +823,7 @@ static int match_window( user_handle_t win, user_handle_t msg_win ) +@@ -861,7 +871,7 @@ static int match_window( user_handle_t win, user_handle_t msg_win ) } /* retrieve a posted message */ @@ -141,7 +141,7 @@ index a65eab38bdc..bf315f5008c 100644 unsigned int first, unsigned int last, unsigned int flags, struct get_message_reply *reply ) { -@@ -824,6 +834,7 @@ static int get_posted_message( struct msg_queue *queue, user_handle_t win, +@@ -872,6 +882,7 @@ static int get_posted_message( struct msg_queue *queue, user_handle_t win, { if (!match_window( win, msg->win )) continue; if (!check_msg_filter( msg->msg, first, last )) continue; @@ -149,7 +149,7 @@ index a65eab38bdc..bf315f5008c 100644 goto found; /* found one */ } return 0; -@@ -1439,6 +1450,7 @@ found: +@@ -1488,6 +1499,7 @@ found: msg->msg = WM_HOTKEY; msg->wparam = hotkey->id; msg->lparam = ((hotkey->vkey & 0xffff) << 16) | modifiers; @@ -157,7 +157,7 @@ index a65eab38bdc..bf315f5008c 100644 free( msg->data ); msg->data = NULL; -@@ -2061,7 +2073,7 @@ static int get_hardware_message( struct thread *thread, unsigned int hw_id, user +@@ -2125,7 +2137,7 @@ static int get_hardware_message( struct thread *thread, unsigned int hw_id, user continue; } /* now we can return it */ @@ -166,7 +166,7 @@ index a65eab38bdc..bf315f5008c 100644 reply->type = MSG_HARDWARE; reply->win = win; reply->msg = msg_code; -@@ -2167,6 +2179,7 @@ void post_message( user_handle_t win, unsigned int message, lparam_t wparam, lpa +@@ -2231,6 +2243,7 @@ void post_message( user_handle_t win, unsigned int message, lparam_t wparam, lpa msg->result = NULL; msg->data = NULL; msg->data_size = 0; @@ -174,7 +174,7 @@ index a65eab38bdc..bf315f5008c 100644 get_message_defaults( thread->queue, &msg->x, &msg->y, &msg->time ); -@@ -2411,6 +2424,7 @@ DECL_HANDLER(send_message) +@@ -2475,6 +2488,7 @@ DECL_HANDLER(send_message) set_queue_bits( recv_queue, QS_SENDMESSAGE ); break; case MSG_POSTED: @@ -182,7 +182,7 @@ index a65eab38bdc..bf315f5008c 100644 list_add_tail( &recv_queue->msg_list[POST_MESSAGE], &msg->entry ); set_queue_bits( recv_queue, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE ); if (msg->msg == WM_HOTKEY) -@@ -2531,12 +2545,12 @@ DECL_HANDLER(get_message) +@@ -2595,12 +2609,12 @@ DECL_HANDLER(get_message) /* then check for posted messages */ if ((filter & QS_POSTMESSAGE) && @@ -197,7 +197,7 @@ index a65eab38bdc..bf315f5008c 100644 return; /* only check for quit messages if not posted messages pending */ -@@ -2547,7 +2561,7 @@ DECL_HANDLER(get_message) +@@ -2611,7 +2625,7 @@ DECL_HANDLER(get_message) if ((filter & QS_INPUT) && filter_contains_hw_range( req->get_first, req->get_last ) && get_hardware_message( current, req->hw_id, get_win, req->get_first, req->get_last, req->flags, reply )) @@ -206,7 +206,7 @@ index a65eab38bdc..bf315f5008c 100644 /* now check for WM_PAINT */ if ((filter & QS_PAINT) && -@@ -2560,7 +2574,7 @@ DECL_HANDLER(get_message) +@@ -2624,7 +2638,7 @@ DECL_HANDLER(get_message) reply->wparam = 0; reply->lparam = 0; get_message_defaults( queue, &reply->x, &reply->y, &reply->time ); @@ -215,7 +215,7 @@ index a65eab38bdc..bf315f5008c 100644 } /* now check for timer */ -@@ -2576,13 +2590,30 @@ DECL_HANDLER(get_message) +@@ -2640,13 +2654,30 @@ DECL_HANDLER(get_message) get_message_defaults( queue, &reply->x, &reply->y, &reply->time ); if (!(req->flags & PM_NOYIELD) && current->process->idle_event) set_event( current->process->idle_event ); @@ -247,7 +247,7 @@ index a65eab38bdc..bf315f5008c 100644 } -@@ -2600,7 +2631,10 @@ DECL_HANDLER(reply_message) +@@ -2664,7 +2695,10 @@ DECL_HANDLER(reply_message) DECL_HANDLER(accept_hardware_message) { if (current->queue) @@ -259,5 +259,5 @@ index a65eab38bdc..bf315f5008c 100644 set_error( STATUS_ACCESS_DENIED ); } -- -2.27.0 +2.30.2 diff --git a/patches/server-PeekMessage/definition b/patches/server-PeekMessage/definition index d66d0aab..6f30913f 100644 --- a/patches/server-PeekMessage/definition +++ b/patches/server-PeekMessage/definition @@ -1 +1,2 @@ Fixes: [28884] GetMessage should remove already seen messages with higher priority +Depends: server-Key_State