From: Rémi Bernon rbernon@codeweavers.com
--- server/protocol.def | 1 + server/queue.c | 45 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 36 insertions(+), 10 deletions(-)
diff --git a/server/protocol.def b/server/protocol.def index 91257fce3a1..97a22599475 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -935,6 +935,7 @@ typedef volatile struct rectangle_t caret_rect; /* caret rectangle */ user_handle_t cursor; /* handle to the cursor */ int cursor_count; /* cursor show count */ + unsigned char keystate[256]; /* key state */ } input_shm_t;
typedef volatile union diff --git a/server/queue.c b/server/queue.c index 9ccd93c4280..f42b9317080 100644 --- a/server/queue.c +++ b/server/queue.c @@ -107,7 +107,6 @@ struct thread_input int caret_hide; /* caret hide count */ int caret_state; /* caret on/off state */ 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 */ const input_shm_t *shared; /* thread input in session shared memory */ @@ -251,7 +250,6 @@ static struct thread_input *create_thread_input( struct thread *thread ) if ((input = alloc_object( &thread_input_ops ))) { list_init( &input->msg_list ); - memset( input->keystate, 0, sizeof(input->keystate) ); input->keystate_lock = 0; input->shared = NULL;
@@ -280,6 +278,7 @@ static struct thread_input *create_thread_input( struct thread *thread ) set_caret_window( input, shared, 0 ); shared->cursor = 0; shared->cursor_count = 0; + memset( (void *)shared->keystate, 0, sizeof(shared->keystate) ); } SHARED_WRITE_END; } @@ -360,17 +359,23 @@ void free_msg_queue( struct thread *thread ) /* synchronize thread input keystate with the desktop */ static void sync_input_keystate( struct thread_input *input ) { + const input_shm_t *input_shm = input->shared; const desktop_shm_t *desktop_shm; + struct desktop *desktop; int i;
- if (!input->desktop || input->keystate_lock) return; + if (!(desktop = input->desktop) || input->keystate_lock) return; desktop_shm = input->desktop->shared;
- for (i = 0; i < sizeof(input->keystate); ++i) + SHARED_WRITE_BEGIN( input_shm, input_shm_t ) { - if (input->desktop_keystate[i] == desktop_shm->keystate[i]) continue; - input->keystate[i] = input->desktop_keystate[i] = desktop_shm->keystate[i]; + for (i = 0; i < sizeof(shared->keystate); ++i) + { + if (input->desktop_keystate[i] == desktop_shm->keystate[i]) continue; + shared->keystate[i] = input->desktop_keystate[i] = desktop_shm->keystate[i]; + } } + SHARED_WRITE_END; }
/* locks thread input keystate to prevent synchronization */ @@ -1435,7 +1440,15 @@ 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) + { + const input_shm_t *input_shm = input->shared; + SHARED_WRITE_BEGIN( input_shm, input_shm_t ) + { + memset( (void *)shared->keystate, 0, sizeof(shared->keystate) ); + } + SHARED_WRITE_END; + } release_object( input ); return ret; } @@ -1692,7 +1705,12 @@ static void update_key_state( volatile unsigned char *keystate, unsigned int msg
static void update_thread_input_key_state( struct thread_input *input, unsigned int msg, lparam_t wparam ) { - update_key_state( input->keystate, msg, wparam, 0 ); + const input_shm_t *input_shm = input->shared; + SHARED_WRITE_BEGIN( input_shm, input_shm_t ) + { + update_key_state( shared->keystate, msg, wparam, 0 ); + } + SHARED_WRITE_END; }
static void update_desktop_key_state( struct desktop *desktop, unsigned int msg, lparam_t wparam ) @@ -3718,7 +3736,8 @@ DECL_HANDLER(get_key_state) else { struct msg_queue *queue = get_current_queue(); - unsigned char *keystate = queue->input->keystate; + const input_shm_t *input_shm = queue->input->shared; + unsigned char *keystate = (void *)input_shm->keystate; if (req->key >= 0) { sync_input_keystate( queue->input ); @@ -3735,8 +3754,14 @@ DECL_HANDLER(set_key_state) struct msg_queue *queue = get_current_queue(); struct desktop *desktop = queue->input->desktop; data_size_t size = min( 256, get_req_data_size() ); + const input_shm_t *input_shm = queue->input->shared; + + SHARED_WRITE_BEGIN( input_shm, input_shm_t ) + { + memcpy( (void *)shared->keystate, get_req_data(), size ); + } + SHARED_WRITE_END;
- memcpy( queue->input->keystate, get_req_data(), size ); memcpy( queue->input->desktop_keystate, (const void *)desktop->shared->keystate, sizeof(queue->input->desktop_keystate) );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/input.c | 18 ++++++++++++++++++ dlls/win32u/sysparams.c | 3 +++ dlls/win32u/win32u_private.h | 1 + dlls/wineandroid.drv/keyboard.c | 17 +---------------- dlls/winemac.drv/keyboard.c | 21 +-------------------- dlls/winewayland.drv/wayland_keyboard.c | 18 +----------------- dlls/winex11.drv/keyboard.c | 24 +++--------------------- include/ntuser.h | 6 ++++++ 8 files changed, 34 insertions(+), 74 deletions(-)
diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 794dde58359..ba54cd3d7bb 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -989,6 +989,24 @@ BOOL WINAPI NtUserGetKeyboardState( BYTE *state ) return ret; }
+/*********************************************************************** + * get_async_keyboard_state + */ +BOOL get_async_keyboard_state( BYTE state[256] ) +{ + BOOL ret; + + SERVER_START_REQ( get_key_state ) + { + req->async = 1; + req->key = -1; + wine_server_set_reply( req, state, 256 ); + ret = !wine_server_call( req ); + } + SERVER_END_REQ; + return ret; +} + /********************************************************************** * NtUserSetKeyboardState (win32u.@) */ diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 9a06db2c7f6..807f2f4ae81 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -6488,6 +6488,9 @@ ULONG_PTR WINAPI NtUserCallOneParam( ULONG_PTR arg, ULONG code ) case NtUserCallOneParam_D3DKMTOpenAdapterFromGdiDisplayName: return d3dkmt_open_adapter_from_gdi_display_name( (void *)arg );
+ case NtUserCallOneParam_GetAsyncKeyboardState: + return get_async_keyboard_state( (void *)arg ); + /* temporary exports */ case NtUserGetDeskPattern: return get_entry( &entry_DESKPATTERN, 256, (WCHAR *)arg ); diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 0a82c2175ae..fc0f0c62c93 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -96,6 +96,7 @@ extern HWND get_capture(void); extern BOOL get_cursor_pos( POINT *pt ); extern HWND get_focus(void); extern DWORD get_input_state(void); +extern BOOL get_async_keyboard_state( BYTE state[256] ); extern BOOL release_capture(void); extern BOOL set_capture_window( HWND hwnd, UINT gui_flags, HWND *prev_ret ); extern BOOL set_caret_blink_time( unsigned int time ); diff --git a/dlls/wineandroid.drv/keyboard.c b/dlls/wineandroid.drv/keyboard.c index b0380d147da..b53bf64abc1 100644 --- a/dlls/wineandroid.drv/keyboard.c +++ b/dlls/wineandroid.drv/keyboard.c @@ -654,21 +654,6 @@ static const char* vkey_to_name( UINT vkey ) return NULL; }
-static BOOL get_async_key_state( BYTE state[256] ) -{ - BOOL ret; - - SERVER_START_REQ( get_key_state ) - { - req->async = 1; - req->key = -1; - wine_server_set_reply( req, state, 256 ); - ret = !wine_server_call( req ); - } - SERVER_END_REQ; - return ret; -} - static void send_keyboard_input( HWND hwnd, WORD vkey, WORD scan, DWORD flags ) { INPUT input; @@ -690,7 +675,7 @@ void update_keyboard_lock_state( WORD vkey, UINT state ) { BYTE keystate[256];
- if (!get_async_key_state( keystate )) return; + if (!NtUserGetAsyncKeyboardState( keystate )) return;
if (!(keystate[VK_CAPITAL] & 0x01) != !(state & AMETA_CAPS_LOCK_ON) && vkey != VK_CAPITAL) { diff --git a/dlls/winemac.drv/keyboard.c b/dlls/winemac.drv/keyboard.c index 0431cc22150..832e6178466 100644 --- a/dlls/winemac.drv/keyboard.c +++ b/dlls/winemac.drv/keyboard.c @@ -1043,25 +1043,6 @@ static void macdrv_send_keyboard_input(HWND hwnd, WORD vkey, WORD scan, unsigned }
-/*********************************************************************** - * get_async_key_state - */ -static BOOL get_async_key_state(BYTE state[256]) -{ - BOOL ret; - - SERVER_START_REQ(get_key_state) - { - req->async = 1; - req->key = -1; - wine_server_set_reply(req, state, 256); - ret = !wine_server_call(req); - } - SERVER_END_REQ; - return ret; -} - - /*********************************************************************** * update_modifier_state */ @@ -1190,7 +1171,7 @@ void macdrv_hotkey_press(const macdrv_event *event) BOOL got_keystate; DWORD flags;
- if ((got_keystate = get_async_key_state(keystate))) + if ((got_keystate = NtUserGetAsyncKeyboardState(keystate))) { update_modifier_state(MOD_ALT, event->hotkey_press.mod_flags, keystate, VK_LMENU, VK_RMENU, 0x38, 0x138, event->hotkey_press.time_ms, FALSE); diff --git a/dlls/winewayland.drv/wayland_keyboard.c b/dlls/winewayland.drv/wayland_keyboard.c index bdef56e8f0c..5c2fe15273e 100644 --- a/dlls/winewayland.drv/wayland_keyboard.c +++ b/dlls/winewayland.drv/wayland_keyboard.c @@ -617,29 +617,13 @@ static BOOL find_xkb_layout_variant(const char *name, const char **layout, const return FALSE; }
-static BOOL get_async_key_state(BYTE state[256]) -{ - BOOL ret; - - SERVER_START_REQ(get_key_state) - { - req->async = 1; - req->key = -1; - wine_server_set_reply(req, state, 256); - ret = !wine_server_call(req); - } - SERVER_END_REQ; - - return ret; -} - static void release_all_keys(HWND hwnd) { BYTE state[256]; int vkey; INPUT input = {.type = INPUT_KEYBOARD};
- get_async_key_state(state); + NtUserGetAsyncKeyboardState(state);
for (vkey = 1; vkey < 256; vkey++) { diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index 23f07b851a7..bb5bf6220e1 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -1135,24 +1135,6 @@ static void X11DRV_send_keyboard_input( HWND hwnd, WORD vkey, WORD scan, UINT fl }
-/*********************************************************************** - * get_async_key_state - */ -static BOOL get_async_key_state( BYTE state[256] ) -{ - BOOL ret; - - SERVER_START_REQ( get_key_state ) - { - req->async = 1; - req->key = -1; - wine_server_set_reply( req, state, 256 ); - ret = !wine_server_call( req ); - } - SERVER_END_REQ; - return ret; -} - /*********************************************************************** * set_async_key_state */ @@ -1205,7 +1187,7 @@ BOOL X11DRV_KeymapNotify( HWND hwnd, XEvent *event ) keymapnotify_hwnd = thread_data->keymapnotify_hwnd; thread_data->keymapnotify_hwnd = NULL;
- if (!get_async_key_state( keystate )) return FALSE; + if (!NtUserGetAsyncKeyboardState( keystate )) return FALSE;
memset(keys, 0, sizeof(keys));
@@ -1292,7 +1274,7 @@ static void adjust_lock_state( BYTE *keystate, HWND hwnd, WORD vkey, WORD scan, * to block changing state, we can't prevent it on X server side. Having * different states would cause us to try to adjust it again on the next * key event. We prevent that by overriding hooks and setting key states here. */ - if (get_async_key_state( keystate ) && (keystate[vkey] & 0x01) == prev_state) + if (NtUserGetAsyncKeyboardState( keystate ) && (keystate[vkey] & 0x01) == prev_state) { WARN("keystate %x not changed (%#.2x), probably blocked by hooks\n", vkey, keystate[vkey]); keystate[vkey] ^= 0x01; @@ -1307,7 +1289,7 @@ static void update_lock_state( HWND hwnd, WORD vkey, UINT state, UINT time ) /* Note: X sets the below states on key down and clears them on key up. Windows triggers them on key down. */
- if (!get_async_key_state( keystate )) return; + if (!NtUserGetAsyncKeyboardState( keystate )) return;
/* Adjust the CAPSLOCK state if it has been changed outside wine */ if (!(keystate[VK_CAPITAL] & 0x01) != !(state & LockMask) && vkey != VK_CAPITAL) diff --git a/include/ntuser.h b/include/ntuser.h index bd11567290f..4148c8cf0b6 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -912,6 +912,7 @@ enum NtUserCallOneParam_SetKeyboardAutoRepeat, NtUserCallOneParam_SetThreadDpiAwarenessContext, NtUserCallOneParam_D3DKMTOpenAdapterFromGdiDisplayName, + NtUserCallOneParam_GetAsyncKeyboardState, /* temporary exports */ NtUserGetDeskPattern, }; @@ -1037,6 +1038,11 @@ static inline NTSTATUS NtUserD3DKMTOpenAdapterFromGdiDisplayName( D3DKMT_OPENADA return NtUserCallOneParam( (UINT_PTR)desc, NtUserCallOneParam_D3DKMTOpenAdapterFromGdiDisplayName ); }
+static inline BOOL NtUserGetAsyncKeyboardState( BYTE state[256] ) +{ + return NtUserCallOneParam( (UINT_PTR)state, NtUserCallOneParam_GetAsyncKeyboardState ); +} + /* NtUserCallTwoParam codes, not compatible with Windows */ enum {
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/input.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-)
diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index ba54cd3d7bb..36d23eb1d1b 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -972,21 +972,19 @@ SHORT WINAPI NtUserGetKeyState( INT vkey ) */ BOOL WINAPI NtUserGetKeyboardState( BYTE *state ) { - BOOL ret; + struct object_lock lock = OBJECT_LOCK_INIT; + const input_shm_t *input_shm; + NTSTATUS status; UINT i;
TRACE("(%p)\n", state);
- memset( state, 0, 256 ); - SERVER_START_REQ( get_key_state ) - { - req->key = -1; - wine_server_set_reply( req, state, 256 ); - ret = !wine_server_call_err( req ); - for (i = 0; i < 256; i++) state[i] &= 0x81; - } - SERVER_END_REQ; - return ret; + while ((status = get_shared_input( GetCurrentThreadId(), &lock, &input_shm )) == STATUS_PENDING) + memcpy( state, (const void *)input_shm->keystate, 256 ); + if (status) memset( state, 0, 256 ); + + for (i = 0; i < 256; i++) state[i] &= 0x81; + return !status; }
/***********************************************************************
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/input.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 36d23eb1d1b..f0d915a625c 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -992,17 +992,17 @@ BOOL WINAPI NtUserGetKeyboardState( BYTE *state ) */ BOOL get_async_keyboard_state( BYTE state[256] ) { - BOOL ret; + struct object_lock lock = OBJECT_LOCK_INIT; + const desktop_shm_t *desktop_shm; + NTSTATUS status;
- SERVER_START_REQ( get_key_state ) - { - req->async = 1; - req->key = -1; - wine_server_set_reply( req, state, 256 ); - ret = !wine_server_call( req ); - } - SERVER_END_REQ; - return ret; + TRACE("(%p)\n", state); + + while ((status = get_shared_desktop( &lock, &desktop_shm )) == STATUS_PENDING) + memcpy( state, (const void *)desktop_shm->keystate, 256 ); + if (status) memset( state, 0, 256 ); + + return !status; }
/**********************************************************************
From: Rémi Bernon rbernon@codeweavers.com
--- server/protocol.def | 3 +-- server/queue.c | 21 ++++++--------------- 2 files changed, 7 insertions(+), 17 deletions(-)
diff --git a/server/protocol.def b/server/protocol.def index 97a22599475..f69a3e8a846 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2947,10 +2947,9 @@ enum coords_relative /* Retrieve queue keyboard state for current thread or global async state */ @REQ(get_key_state) int async; /* whether to query the async state */ - int key; /* optional key code or -1 */ + int key; /* key code */ @REPLY unsigned char state; /* state of specified key */ - VARARG(keystate,bytes); /* state array for all the keys */ @END
/* Set queue keyboard state for current thread */ diff --git a/server/queue.c b/server/queue.c index f42b9317080..c082d7acab8 100644 --- a/server/queue.c +++ b/server/queue.c @@ -3716,21 +3716,16 @@ DECL_HANDLER(get_thread_input) DECL_HANDLER(get_key_state) { struct desktop *desktop; - data_size_t size = min( 256, get_reply_max_size() );
if (req->async) /* get global async key state */ { if (!(desktop = get_thread_desktop( current, 0 ))) return; - if (req->key >= 0) + SHARED_WRITE_BEGIN( desktop->shared, desktop_shm_t ) { - SHARED_WRITE_BEGIN( desktop->shared, desktop_shm_t ) - { - reply->state = shared->keystate[req->key & 0xff]; - shared->keystate[req->key & 0xff] &= ~0x40; - } - SHARED_WRITE_END; + reply->state = shared->keystate[req->key & 0xff]; + shared->keystate[req->key & 0xff] &= ~0x40; } - set_reply_data( (const void *)desktop->shared->keystate, size ); + SHARED_WRITE_END; release_object( desktop ); } else @@ -3738,12 +3733,8 @@ DECL_HANDLER(get_key_state) struct msg_queue *queue = get_current_queue(); const input_shm_t *input_shm = queue->input->shared; unsigned char *keystate = (void *)input_shm->keystate; - if (req->key >= 0) - { - sync_input_keystate( queue->input ); - reply->state = keystate[req->key & 0xff]; - } - set_reply_data( keystate, size ); + sync_input_keystate( queue->input ); + reply->state = keystate[req->key & 0xff]; } }
From: Rémi Bernon rbernon@codeweavers.com
--- server/protocol.def | 1 + server/queue.c | 24 ++++++++++++++++++------ 2 files changed, 19 insertions(+), 6 deletions(-)
diff --git a/server/protocol.def b/server/protocol.def index f69a3e8a846..12eef14cc67 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -936,6 +936,7 @@ typedef volatile struct user_handle_t cursor; /* handle to the cursor */ int cursor_count; /* cursor show count */ unsigned char keystate[256]; /* key state */ + int keystate_lock; /* keystate is locked */ } input_shm_t;
typedef volatile union diff --git a/server/queue.c b/server/queue.c index c082d7acab8..7411168a2ff 100644 --- a/server/queue.c +++ b/server/queue.c @@ -108,7 +108,6 @@ struct thread_input int caret_state; /* caret on/off state */ struct list msg_list; /* list of hardware messages */ unsigned char desktop_keystate[256]; /* desktop keystate when keystate was synced */ - int keystate_lock; /* keystate is locked */ const input_shm_t *shared; /* thread input in session shared memory */ };
@@ -250,7 +249,6 @@ static struct thread_input *create_thread_input( struct thread *thread ) if ((input = alloc_object( &thread_input_ops ))) { list_init( &input->msg_list ); - input->keystate_lock = 0; input->shared = NULL;
if (!(input->desktop = get_thread_desktop( thread, 0 /* FIXME: access rights */ ))) @@ -279,6 +277,7 @@ static struct thread_input *create_thread_input( struct thread *thread ) shared->cursor = 0; shared->cursor_count = 0; memset( (void *)shared->keystate, 0, sizeof(shared->keystate) ); + shared->keystate_lock = 0; } SHARED_WRITE_END; } @@ -364,7 +363,7 @@ static void sync_input_keystate( struct thread_input *input ) struct desktop *desktop; int i;
- if (!(desktop = input->desktop) || input->keystate_lock) return; + if (!(desktop = input->desktop) || input_shm->keystate_lock) return; desktop_shm = input->desktop->shared;
SHARED_WRITE_BEGIN( input_shm, input_shm_t ) @@ -381,14 +380,27 @@ static void sync_input_keystate( struct thread_input *input ) /* locks thread input keystate to prevent synchronization */ static void lock_input_keystate( struct thread_input *input ) { - input->keystate_lock++; + const input_shm_t *input_shm = input->shared; + + SHARED_WRITE_BEGIN( input_shm, input_shm_t ) + { + shared->keystate_lock++; + } + SHARED_WRITE_END; }
/* 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 ); + const input_shm_t *input_shm = input->shared; + + SHARED_WRITE_BEGIN( input_shm, input_shm_t ) + { + shared->keystate_lock--; + } + SHARED_WRITE_END; + + if (!input_shm->keystate_lock) sync_input_keystate( input ); }
/* change the thread input data of a given thread */
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/input.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index f0d915a625c..61d3c3877c0 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -955,9 +955,19 @@ HKL WINAPI NtUserGetKeyboardLayout( DWORD thread_id ) */ SHORT WINAPI NtUserGetKeyState( INT vkey ) { + struct object_lock lock = OBJECT_LOCK_INIT; + const input_shm_t *input_shm; + BOOL ret = FALSE; SHORT retval = 0; + NTSTATUS status;
- SERVER_START_REQ( get_key_state ) + while ((status = get_shared_input( GetCurrentThreadId(), &lock, &input_shm )) == STATUS_PENDING) + { + ret = !!input_shm->keystate_lock; /* needs a request for sync_input_keystate */ + retval = (signed char)(input_shm->keystate[vkey & 0xff] & 0x81); + } + + if (!ret) SERVER_START_REQ( get_key_state ) { req->key = vkey; if (!wine_server_call( req )) retval = (signed char)(reply->state & 0x81);
This breaks some tests, I'll have a look.