From: Rémi Bernon rbernon@codeweavers.com
Before writing to it, it may have been marked as noaccess before in free_shared_object. --- server/object.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/server/object.c b/server/object.c index 3b72b576d50..36c9c60fb65 100644 --- a/server/object.c +++ b/server/object.c @@ -116,6 +116,11 @@ void mark_block_noaccess( void *ptr, size_t size ) /* mark a block of memory as uninitialized for debugging purposes */ void mark_block_uninitialized( void *ptr, size_t size ) { +#if defined(VALGRIND_MAKE_MEM_UNDEFINED) + VALGRIND_DISCARD( VALGRIND_MAKE_MEM_UNDEFINED( ptr, size )); +#elif defined(VALGRIND_MAKE_WRITABLE) + VALGRIND_DISCARD( VALGRIND_MAKE_WRITABLE( ptr, size )); +#endif memset( ptr, 0x55, size ); #if defined(VALGRIND_MAKE_MEM_UNDEFINED) VALGRIND_DISCARD( VALGRIND_MAKE_MEM_UNDEFINED( ptr, size ));
From: Rémi Bernon rbernon@codeweavers.com
Based on a patch by Huw Davies huw@codeweavers.com. --- server/protocol.def | 1 + server/queue.c | 26 ++++++++++++++++---------- server/user.h | 1 - server/winstation.c | 4 ++++ 4 files changed, 21 insertions(+), 11 deletions(-)
diff --git a/server/protocol.def b/server/protocol.def index 20ed82982dd..0592dddaa97 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -904,6 +904,7 @@ struct shared_cursor int x; /* cursor position */ int y; unsigned int last_change; /* time of last position change */ + rectangle_t clip; /* cursor clip rectangle */ };
typedef volatile struct diff --git a/server/queue.c b/server/queue.c index c2e957cfd21..e06f6afe0f7 100644 --- a/server/queue.c +++ b/server/queue.c @@ -410,7 +410,8 @@ static struct message *alloc_hardware_message( lparam_t info, struct hw_msg_sour
static int is_cursor_clipped( struct desktop *desktop ) { - rectangle_t top_rect, clip_rect = desktop->cursor.clip; + const desktop_shm_t *desktop_shm = desktop->shared; + rectangle_t top_rect, clip_rect = desktop_shm->cursor.clip; get_top_window_rectangle( desktop, &top_rect ); return !is_rect_equal( &clip_rect, &top_rect ); } @@ -471,8 +472,8 @@ static int update_desktop_cursor_pos( struct desktop *desktop, user_handle_t win int updated; unsigned int time = get_tick_count();
- x = max( min( x, desktop->cursor.clip.right - 1 ), desktop->cursor.clip.left ); - y = max( min( y, desktop->cursor.clip.bottom - 1 ), desktop->cursor.clip.top ); + x = max( min( x, desktop_shm->cursor.clip.right - 1 ), desktop_shm->cursor.clip.left ); + y = max( min( y, desktop_shm->cursor.clip.bottom - 1 ), desktop_shm->cursor.clip.top );
SHARED_WRITE_BEGIN( desktop_shm, desktop_shm_t ) { @@ -537,29 +538,34 @@ static void get_message_defaults( struct msg_queue *queue, int *x, int *y, unsig void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, unsigned int flags, int reset ) { const desktop_shm_t *desktop_shm = desktop->shared; - rectangle_t top_rect; + rectangle_t top_rect, new_rect; unsigned int old_flags; int x, y;
get_top_window_rectangle( desktop, &top_rect ); if (rect) { - rectangle_t new_rect = *rect; + new_rect = *rect; if (new_rect.left < top_rect.left) new_rect.left = top_rect.left; if (new_rect.right > top_rect.right) new_rect.right = top_rect.right; if (new_rect.top < top_rect.top) new_rect.top = top_rect.top; if (new_rect.bottom > top_rect.bottom) new_rect.bottom = top_rect.bottom; if (new_rect.left > new_rect.right || new_rect.top > new_rect.bottom) new_rect = top_rect; - desktop->cursor.clip = new_rect; } - else desktop->cursor.clip = top_rect; + else new_rect = top_rect; + + SHARED_WRITE_BEGIN( desktop_shm, desktop_shm_t ) + { + shared->cursor.clip = new_rect; + } + SHARED_WRITE_END;
old_flags = desktop->cursor.clip_flags; desktop->cursor.clip_flags = flags;
/* warp the mouse to be inside the clip rect */ - x = max( min( desktop_shm->cursor.x, desktop->cursor.clip.right - 1 ), desktop->cursor.clip.left ); - y = max( min( desktop_shm->cursor.y, desktop->cursor.clip.bottom - 1 ), desktop->cursor.clip.top ); + x = max( min( desktop_shm->cursor.x, new_rect.right - 1 ), new_rect.left ); + y = max( min( desktop_shm->cursor.y, new_rect.bottom - 1 ), new_rect.top ); if (x != desktop_shm->cursor.x || y != desktop_shm->cursor.y) set_cursor_pos( desktop, x, y );
/* request clip cursor rectangle reset to the desktop thread */ @@ -3745,7 +3751,7 @@ DECL_HANDLER(set_cursor)
reply->new_x = desktop_shm->cursor.x; reply->new_y = desktop_shm->cursor.y; - reply->new_clip = desktop->cursor.clip; + reply->new_clip = desktop_shm->cursor.clip; reply->last_change = desktop_shm->cursor.last_change; }
diff --git a/server/user.h b/server/user.h index a20aff99284..7ad1e82ae54 100644 --- a/server/user.h +++ b/server/user.h @@ -56,7 +56,6 @@ struct winstation
struct global_cursor { - rectangle_t clip; /* cursor clip rectangle */ unsigned int clip_flags; /* last cursor clip flags */ user_handle_t win; /* window that contains the cursor */ }; diff --git a/server/winstation.c b/server/winstation.c index 87981f64167..3e08f4b3337 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -310,6 +310,10 @@ static struct desktop *create_desktop( const struct unicode_str *name, unsigned shared->cursor.x = 0; shared->cursor.y = 0; shared->cursor.last_change = 0; + shared->cursor.clip.left = 0; + shared->cursor.clip.top = 0; + shared->cursor.clip.right = 0; + shared->cursor.clip.bottom = 0; } SHARED_WRITE_END; }
From: Rémi Bernon rbernon@codeweavers.com
Based on a patch by Huw Davies huw@codeweavers.com. --- server/queue.c | 12 ++++++------ server/user.h | 9 ++------- server/winstation.c | 3 ++- 3 files changed, 10 insertions(+), 14 deletions(-)
diff --git a/server/queue.c b/server/queue.c index e06f6afe0f7..1a98714004c 100644 --- a/server/queue.c +++ b/server/queue.c @@ -440,7 +440,7 @@ static struct thread_input *get_desktop_cursor_thread_input( struct desktop *des struct thread_input *input = NULL; struct thread *thread;
- if ((thread = get_window_thread( desktop->cursor.win ))) + if ((thread = get_window_thread( desktop->cursor_win ))) { if (thread->queue) input = thread->queue->input; release_object( thread ); @@ -451,9 +451,9 @@ static struct thread_input *get_desktop_cursor_thread_input( struct desktop *des
static int update_desktop_cursor_window( struct desktop *desktop, user_handle_t win ) { - int updated = win != desktop->cursor.win; + int updated = win != desktop->cursor_win; struct thread_input *input; - desktop->cursor.win = win; + desktop->cursor_win = win;
if (updated && (input = get_desktop_cursor_thread_input( desktop ))) { @@ -495,7 +495,7 @@ static void update_desktop_cursor_handle( struct desktop *desktop, struct thread { if (input == get_desktop_cursor_thread_input( desktop )) { - user_handle_t win = desktop->cursor.win; + user_handle_t win = desktop->cursor_win; /* when clipping send the message to the foreground window as well, as some driver have an artificial overlay window */ if (is_cursor_clipped( desktop )) queue_cursor_message( desktop, 0, WM_WINE_SETCURSOR, win, handle ); queue_cursor_message( desktop, win, WM_WINE_SETCURSOR, win, handle ); @@ -560,8 +560,8 @@ void set_clip_rectangle( struct desktop *desktop, const rectangle_t *rect, unsig } SHARED_WRITE_END;
- old_flags = desktop->cursor.clip_flags; - desktop->cursor.clip_flags = flags; + old_flags = desktop->clip_flags; + desktop->clip_flags = flags;
/* warp the mouse to be inside the clip rect */ x = max( min( desktop_shm->cursor.x, new_rect.right - 1 ), new_rect.left ); diff --git a/server/user.h b/server/user.h index 7ad1e82ae54..7355177e13d 100644 --- a/server/user.h +++ b/server/user.h @@ -54,12 +54,6 @@ struct winstation struct namespace *desktop_names; /* namespace for desktops of this winstation */ };
-struct global_cursor -{ - unsigned int clip_flags; /* last cursor clip flags */ - user_handle_t win; /* window that contains the cursor */ -}; - struct key_repeat { int enable; /* enable auto-repeat */ @@ -86,9 +80,10 @@ struct desktop struct timeout_user *close_timeout; /* timeout before closing the desktop */ struct thread_input *foreground_input; /* thread input of foreground thread */ unsigned int users; /* processes and threads using this desktop */ - struct global_cursor cursor; /* global cursor information */ unsigned char keystate[256]; /* asynchronous key state */ struct key_repeat key_repeat; /* key auto-repeat */ + unsigned int clip_flags; /* last cursor clip flags */ + user_handle_t cursor_win; /* window that contains the cursor */ const desktop_shm_t *shared; /* desktop session shared memory */ };
diff --git a/server/winstation.c b/server/winstation.c index 3e08f4b3337..300d899638b 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -292,7 +292,8 @@ static struct desktop *create_desktop( const struct unicode_str *name, unsigned desktop->foreground_input = NULL; desktop->users = 0; list_init( &desktop->threads ); - memset( &desktop->cursor, 0, sizeof(desktop->cursor) ); + desktop->clip_flags = 0; + desktop->cursor_win = 0; memset( desktop->keystate, 0, sizeof(desktop->keystate) ); memset( &desktop->key_repeat, 0, sizeof(desktop->key_repeat) ); list_add_tail( &winstation->desktops, &desktop->entry );
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/input.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-)
diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 2fbe21e56af..4d0c2589c1b 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -2555,24 +2555,21 @@ BOOL WINAPI NtUserGetPointerInfoList( UINT32 id, POINTER_INPUT_TYPE type, UINT_P
BOOL get_clip_cursor( RECT *rect, UINT dpi ) { - BOOL ret; + struct object_lock lock = OBJECT_LOCK_INIT; + const desktop_shm_t *desktop_shm; + NTSTATUS status;
if (!rect) return FALSE;
- SERVER_START_REQ( set_cursor ) - { - req->flags = 0; - if ((ret = !wine_server_call( req ))) - *rect = wine_server_get_rect( reply->new_clip ); - } - SERVER_END_REQ; + while ((status = get_shared_desktop( &lock, &desktop_shm )) == STATUS_PENDING) + *rect = wine_server_get_rect( desktop_shm->cursor.clip );
- if (ret) + if (!status) { HMONITOR monitor = monitor_from_rect( rect, MONITOR_DEFAULTTOPRIMARY, 0 ); *rect = map_dpi_rect( *rect, get_monitor_dpi( monitor ), dpi ); } - return ret; + return !status; }
BOOL process_wine_clipcursor( HWND hwnd, UINT flags, BOOL reset )
From: Rémi Bernon rbernon@codeweavers.com
Based on a patch by Huw Davies huw@codeweavers.com. --- server/queue.c | 11 +++++------ server/user.h | 1 + server/winstation.c | 1 + 3 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/server/queue.c b/server/queue.c index 1a98714004c..c17446a1dd9 100644 --- a/server/queue.c +++ b/server/queue.c @@ -2171,17 +2171,16 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c if (input->kbd.flags & KEYEVENTF_KEYUP) { /* send WM_SYSKEYUP if Alt still pressed and no other key in between */ - /* we use 0x02 as a flag to track if some other SYSKEYUP was sent already */ - if ((desktop->keystate[VK_MENU] & 0x82) != 0x82) break; + if (!(desktop->keystate[VK_MENU] & 0x80) || !desktop->alt_pressed) break; message_code = WM_SYSKEYUP; - desktop->keystate[VK_MENU] &= ~0x02; + desktop->alt_pressed = 0; } else { /* send WM_SYSKEYDOWN for Alt except with Ctrl */ if (desktop->keystate[VK_CONTROL] & 0x80) break; message_code = WM_SYSKEYDOWN; - desktop->keystate[VK_MENU] |= 0x02; + desktop->alt_pressed = 1; } break;
@@ -2191,7 +2190,7 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c if (!(input->kbd.flags & KEYEVENTF_KEYUP)) break; if (!(desktop->keystate[VK_MENU] & 0x80)) break; message_code = WM_SYSKEYUP; - desktop->keystate[VK_MENU] &= ~0x02; + desktop->alt_pressed = 0; break;
default: @@ -2201,7 +2200,7 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c /* fall through */ case VK_F10: message_code = (input->kbd.flags & KEYEVENTF_KEYUP) ? WM_SYSKEYUP : WM_SYSKEYDOWN; - desktop->keystate[VK_MENU] &= ~0x02; + desktop->alt_pressed = 0; break; }
diff --git a/server/user.h b/server/user.h index 7355177e13d..99491293a7c 100644 --- a/server/user.h +++ b/server/user.h @@ -81,6 +81,7 @@ struct desktop struct thread_input *foreground_input; /* thread input of foreground thread */ unsigned int users; /* processes and threads using this desktop */ unsigned char keystate[256]; /* asynchronous key state */ + unsigned char alt_pressed; /* last key press was Alt (used to determine msg on release) */ struct key_repeat key_repeat; /* key auto-repeat */ unsigned int clip_flags; /* last cursor clip flags */ user_handle_t cursor_win; /* window that contains the cursor */ diff --git a/server/winstation.c b/server/winstation.c index 300d899638b..63bdc3389de 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -294,6 +294,7 @@ static struct desktop *create_desktop( const struct unicode_str *name, unsigned list_init( &desktop->threads ); desktop->clip_flags = 0; desktop->cursor_win = 0; + desktop->alt_pressed = 0; memset( desktop->keystate, 0, sizeof(desktop->keystate) ); memset( &desktop->key_repeat, 0, sizeof(desktop->key_repeat) ); list_add_tail( &winstation->desktops, &desktop->entry );
From: Rémi Bernon rbernon@codeweavers.com
Based on a patch by Huw Davies huw@codeweavers.com. --- server/queue.c | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-)
diff --git a/server/queue.c b/server/queue.c index c17446a1dd9..699a8fdf248 100644 --- a/server/queue.c +++ b/server/queue.c @@ -1470,7 +1470,7 @@ static struct timer *set_timer( struct msg_queue *queue, unsigned int rate ) }
/* change the input key state for a given key */ -static void set_input_key_state( unsigned char *keystate, unsigned char key, int down ) +static void set_input_key_state( unsigned char *keystate, unsigned char key, unsigned char down ) { if (down) { @@ -1481,34 +1481,33 @@ static void set_input_key_state( unsigned char *keystate, unsigned char key, int }
/* 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 ) +static void update_key_state( unsigned char *keystate, unsigned int msg, + lparam_t wparam, int desktop ) { - unsigned char key; - int down = 0; + unsigned char key, down = 0, down_val = desktop ? 0xc0 : 0x80;
switch (msg) { case WM_LBUTTONDOWN: - down = (keystate == desktop->keystate) ? 0xc0 : 0x80; + down = down_val; /* fall through */ case WM_LBUTTONUP: set_input_key_state( keystate, VK_LBUTTON, down ); break; case WM_MBUTTONDOWN: - down = (keystate == desktop->keystate) ? 0xc0 : 0x80; + down = down_val; /* fall through */ case WM_MBUTTONUP: set_input_key_state( keystate, VK_MBUTTON, down ); break; case WM_RBUTTONDOWN: - down = (keystate == desktop->keystate) ? 0xc0 : 0x80; + down = down_val; /* fall through */ case WM_RBUTTONUP: set_input_key_state( keystate, VK_RBUTTON, down ); break; case WM_XBUTTONDOWN: - down = (keystate == desktop->keystate) ? 0xc0 : 0x80; + down = down_val; /* fall through */ case WM_XBUTTONUP: if (wparam >> 16 == XBUTTON1) set_input_key_state( keystate, VK_XBUTTON1, down ); @@ -1516,7 +1515,7 @@ static void update_input_key_state( struct desktop *desktop, unsigned char *keys break; case WM_KEYDOWN: case WM_SYSKEYDOWN: - down = (keystate == desktop->keystate) ? 0xc0 : 0x80; + down = down_val; /* fall through */ case WM_KEYUP: case WM_SYSKEYUP: @@ -1544,6 +1543,16 @@ static void update_input_key_state( struct desktop *desktop, unsigned char *keys } }
+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 ); +} + +static void update_desktop_key_state( struct desktop *desktop, unsigned int msg, lparam_t wparam ) +{ + update_key_state( desktop->keystate, msg, wparam, 1 ); +} + /* release the hardware message currently being processed by the given thread */ static void release_hardware_message( struct msg_queue *queue, unsigned int hw_id ) { @@ -1569,7 +1578,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_thread_input_key_state( input, msg->msg, msg->wparam ); list_remove( &msg->entry ); free_message( msg ); } @@ -1696,7 +1705,7 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg unsigned int msg_code; int flags;
- update_input_key_state( desktop, desktop->keystate, msg->msg, msg->wparam ); + update_desktop_key_state( desktop, msg->msg, msg->wparam ); last_input_time = get_tick_count(); if (msg->msg != WM_MOUSEMOVE) always_queue = 1;
@@ -1736,7 +1745,7 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg flags = thread ? get_rawinput_device_flags( thread->process, msg ) : 0; if (!win || !thread || (flags & RIDEV_NOLEGACY)) { - if (input && !(flags & RIDEV_NOLEGACY)) update_input_key_state( input->desktop, input->keystate, msg->msg, msg->wparam ); + if (input && !(flags & RIDEV_NOLEGACY)) update_thread_input_key_state( input, msg->msg, msg->wparam ); free_message( msg ); return; } @@ -2528,7 +2537,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_thread_input_key_state( input, msg->msg, msg->wparam ); list_remove( &msg->entry ); free_message( msg ); continue; @@ -2544,7 +2553,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_thread_input_key_state( input, msg->msg, msg->wparam ); list_remove( &msg->entry ); free_message( msg ); }
From: Rémi Bernon rbernon@codeweavers.com
Based on a patch by Huw Davies huw@codeweavers.com. --- server/protocol.def | 1 + server/queue.c | 81 ++++++++++++++++++++++++++++----------------- server/winstation.c | 2 +- 3 files changed, 53 insertions(+), 31 deletions(-)
diff --git a/server/protocol.def b/server/protocol.def index 0592dddaa97..11539654dc3 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -910,6 +910,7 @@ struct shared_cursor typedef volatile struct { struct shared_cursor cursor; /* global cursor information */ + unsigned char keystate[256]; /* asynchronous key state */ } desktop_shm_t;
typedef volatile union diff --git a/server/queue.c b/server/queue.c index 699a8fdf248..a7814c83737 100644 --- a/server/queue.c +++ b/server/queue.c @@ -278,7 +278,8 @@ static struct thread_input *create_thread_input( struct thread *thread ) release_object( input ); return NULL; } - memcpy( input->desktop_keystate, input->desktop->keystate, sizeof(input->desktop_keystate) ); + memcpy( input->desktop_keystate, (const void *)input->desktop->shared->keystate, + sizeof(input->desktop_keystate) ); } return input; } @@ -338,12 +339,16 @@ void free_msg_queue( struct thread *thread ) /* synchronize thread input keystate with the desktop */ static void sync_input_keystate( struct thread_input *input ) { + const desktop_shm_t *desktop_shm; int i; + if (!input->desktop || input->keystate_lock) return; + desktop_shm = input->desktop->shared; + 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]; + if (input->desktop_keystate[i] == desktop_shm->keystate[i]) continue; + input->keystate[i] = input->desktop_keystate[i] = desktop_shm->keystate[i]; } }
@@ -1470,7 +1475,7 @@ static struct timer *set_timer( struct msg_queue *queue, unsigned int rate ) }
/* change the input key state for a given key */ -static void set_input_key_state( unsigned char *keystate, unsigned char key, unsigned char down ) +static void set_input_key_state( volatile unsigned char *keystate, unsigned char key, unsigned char down ) { if (down) { @@ -1481,7 +1486,7 @@ static void set_input_key_state( unsigned char *keystate, unsigned char key, uns }
/* update the input key state for a keyboard message */ -static void update_key_state( unsigned char *keystate, unsigned int msg, +static void update_key_state( volatile unsigned char *keystate, unsigned int msg, lparam_t wparam, int desktop ) { unsigned char key, down = 0, down_val = desktop ? 0xc0 : 0x80; @@ -1550,7 +1555,11 @@ static void update_thread_input_key_state( struct thread_input *input, unsigned
static void update_desktop_key_state( struct desktop *desktop, unsigned int msg, lparam_t wparam ) { - update_key_state( desktop->keystate, msg, wparam, 1 ); + SHARED_WRITE_BEGIN( desktop->shared, desktop_shm_t ) + { + update_key_state( shared->keystate, msg, wparam, 1 ); + } + SHARED_WRITE_END; }
/* release the hardware message currently being processed by the given thread */ @@ -1585,15 +1594,16 @@ static void release_hardware_message( struct msg_queue *queue, unsigned int hw_i
static int queue_hotkey_message( struct desktop *desktop, struct message *msg ) { + const desktop_shm_t *desktop_shm = desktop->shared; struct hotkey *hotkey; unsigned int modifiers = 0;
if (msg->msg != WM_KEYDOWN && msg->msg != WM_SYSKEYDOWN) return 0;
- if (desktop->keystate[VK_MENU] & 0x80) modifiers |= MOD_ALT; - if (desktop->keystate[VK_CONTROL] & 0x80) modifiers |= MOD_CONTROL; - if (desktop->keystate[VK_SHIFT] & 0x80) modifiers |= MOD_SHIFT; - if ((desktop->keystate[VK_LWIN] & 0x80) || (desktop->keystate[VK_RWIN] & 0x80)) modifiers |= MOD_WIN; + if (desktop_shm->keystate[VK_MENU] & 0x80) modifiers |= MOD_ALT; + if (desktop_shm->keystate[VK_CONTROL] & 0x80) modifiers |= MOD_CONTROL; + if (desktop_shm->keystate[VK_SHIFT] & 0x80) modifiers |= MOD_SHIFT; + if ((desktop_shm->keystate[VK_LWIN] & 0x80) || (desktop_shm->keystate[VK_RWIN] & 0x80)) modifiers |= MOD_WIN;
LIST_FOR_EACH_ENTRY( hotkey, &desktop->hotkeys, struct hotkey, entry ) { @@ -1713,7 +1723,7 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg { case QS_KEY: if (queue_hotkey_message( desktop, msg )) return; - if (desktop->keystate[VK_MENU] & 0x80) msg->lparam |= KF_ALTDOWN << 16; + if (desktop_shm->keystate[VK_MENU] & 0x80) msg->lparam |= KF_ALTDOWN << 16; if (msg->wparam == VK_SHIFT || msg->wparam == VK_LSHIFT || msg->wparam == VK_RSHIFT) msg->lparam &= ~(KF_EXTENDED << 16); break; @@ -1722,13 +1732,13 @@ static void queue_hardware_message( struct desktop *desktop, struct message *msg /* fallthrough */ case QS_MOUSEBUTTON: if (update_desktop_cursor_pos( desktop, msg->win, msg->x, msg->y )) always_queue = 1; - if (desktop->keystate[VK_LBUTTON] & 0x80) msg->wparam |= MK_LBUTTON; - if (desktop->keystate[VK_MBUTTON] & 0x80) msg->wparam |= MK_MBUTTON; - if (desktop->keystate[VK_RBUTTON] & 0x80) msg->wparam |= MK_RBUTTON; - if (desktop->keystate[VK_SHIFT] & 0x80) msg->wparam |= MK_SHIFT; - if (desktop->keystate[VK_CONTROL] & 0x80) msg->wparam |= MK_CONTROL; - if (desktop->keystate[VK_XBUTTON1] & 0x80) msg->wparam |= MK_XBUTTON1; - if (desktop->keystate[VK_XBUTTON2] & 0x80) msg->wparam |= MK_XBUTTON2; + if (desktop_shm->keystate[VK_LBUTTON] & 0x80) msg->wparam |= MK_LBUTTON; + if (desktop_shm->keystate[VK_MBUTTON] & 0x80) msg->wparam |= MK_MBUTTON; + if (desktop_shm->keystate[VK_RBUTTON] & 0x80) msg->wparam |= MK_RBUTTON; + if (desktop_shm->keystate[VK_SHIFT] & 0x80) msg->wparam |= MK_SHIFT; + if (desktop_shm->keystate[VK_CONTROL] & 0x80) msg->wparam |= MK_CONTROL; + if (desktop_shm->keystate[VK_XBUTTON1] & 0x80) msg->wparam |= MK_XBUTTON1; + if (desktop_shm->keystate[VK_XBUTTON2] & 0x80) msg->wparam |= MK_XBUTTON2; break; } msg->x = desktop_shm->cursor.x; @@ -2134,6 +2144,7 @@ static void stop_key_repeat( struct desktop *desktop ) static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, const hw_input_t *input, unsigned int origin, struct msg_queue *sender, int repeat ) { + const desktop_shm_t *desktop_shm = desktop->shared; struct hw_msg_source source = { IMDT_KEYBOARD, origin }; struct hardware_msg_data *msg_data; struct message *msg; @@ -2180,14 +2191,14 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c if (input->kbd.flags & KEYEVENTF_KEYUP) { /* send WM_SYSKEYUP if Alt still pressed and no other key in between */ - if (!(desktop->keystate[VK_MENU] & 0x80) || !desktop->alt_pressed) break; + if (!(desktop_shm->keystate[VK_MENU] & 0x80) || !desktop->alt_pressed) break; message_code = WM_SYSKEYUP; desktop->alt_pressed = 0; } else { /* send WM_SYSKEYDOWN for Alt except with Ctrl */ - if (desktop->keystate[VK_CONTROL] & 0x80) break; + if (desktop_shm->keystate[VK_CONTROL] & 0x80) break; message_code = WM_SYSKEYDOWN; desktop->alt_pressed = 1; } @@ -2197,15 +2208,15 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c case VK_RCONTROL: /* send WM_SYSKEYUP on release if Alt still pressed */ if (!(input->kbd.flags & KEYEVENTF_KEYUP)) break; - if (!(desktop->keystate[VK_MENU] & 0x80)) break; + if (!(desktop_shm->keystate[VK_MENU] & 0x80)) break; message_code = WM_SYSKEYUP; desktop->alt_pressed = 0; break;
default: /* send WM_SYSKEY for Alt-anykey and for F10 */ - if (desktop->keystate[VK_CONTROL] & 0x80) break; - if (!(desktop->keystate[VK_MENU] & 0x80)) break; + if (desktop_shm->keystate[VK_CONTROL] & 0x80) break; + if (!(desktop_shm->keystate[VK_MENU] & 0x80)) break; /* fall through */ case VK_F10: message_code = (input->kbd.flags & KEYEVENTF_KEYUP) ? WM_SYSKEYUP : WM_SYSKEYDOWN; @@ -2281,7 +2292,7 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c if (input->kbd.flags & KEYEVENTF_EXTENDEDKEY) flags |= KF_EXTENDED; /* FIXME: set KF_DLGMODE and KF_MENUMODE when needed */ if (input->kbd.flags & KEYEVENTF_KEYUP) flags |= KF_REPEAT | KF_UP; - else if (desktop->keystate[vkey] & 0x80) flags |= KF_REPEAT; + else if (desktop_shm->keystate[vkey] & 0x80) flags |= KF_REPEAT;
lparam &= 0xff0000; /* mask off scan code high bits for non-unicode input */ msg_data->flags |= (flags & (KF_EXTENDED | KF_ALTDOWN | KF_UP)) >> 8; @@ -3523,10 +3534,14 @@ DECL_HANDLER(get_key_state) if (!(desktop = get_thread_desktop( current, 0 ))) return; if (req->key >= 0) { - reply->state = desktop->keystate[req->key & 0xff]; - desktop->keystate[req->key & 0xff] &= ~0x40; + SHARED_WRITE_BEGIN( desktop->shared, desktop_shm_t ) + { + reply->state = shared->keystate[req->key & 0xff]; + shared->keystate[req->key & 0xff] &= ~0x40; + } + SHARED_WRITE_END; } - set_reply_data( desktop->keystate, size ); + set_reply_data( (const void *)desktop->shared->keystate, size ); release_object( desktop ); } else @@ -3546,15 +3561,21 @@ DECL_HANDLER(get_key_state) /* set queue keyboard state for current thread */ DECL_HANDLER(set_key_state) { - struct desktop *desktop; struct msg_queue *queue = get_current_queue(); + struct desktop *desktop = queue->input->desktop; 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 ); + memcpy( queue->input->desktop_keystate, (const void *)desktop->shared->keystate, + sizeof(queue->input->desktop_keystate) ); + if (req->async && (desktop = get_thread_desktop( current, 0 ))) { - memcpy( desktop->keystate, get_req_data(), size ); + SHARED_WRITE_BEGIN( desktop->shared, desktop_shm_t ) + { + memcpy( (void *)shared->keystate, get_req_data(), size ); + } + SHARED_WRITE_END; release_object( desktop ); } } diff --git a/server/winstation.c b/server/winstation.c index 63bdc3389de..45c7defa1f7 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -295,7 +295,6 @@ static struct desktop *create_desktop( const struct unicode_str *name, unsigned desktop->clip_flags = 0; desktop->cursor_win = 0; desktop->alt_pressed = 0; - memset( desktop->keystate, 0, sizeof(desktop->keystate) ); memset( &desktop->key_repeat, 0, sizeof(desktop->key_repeat) ); list_add_tail( &winstation->desktops, &desktop->entry ); list_init( &desktop->hotkeys ); @@ -316,6 +315,7 @@ static struct desktop *create_desktop( const struct unicode_str *name, unsigned shared->cursor.clip.top = 0; shared->cursor.clip.right = 0; shared->cursor.clip.bottom = 0; + memset( (void *)shared->keystate, 0, sizeof(shared->keystate) ); } SHARED_WRITE_END; }
From: Rémi Bernon rbernon@codeweavers.com
Based on a patch by Huw Davies huw@codeweavers.com. --- dlls/win32u/hook.c | 2 -- dlls/win32u/input.c | 44 +++++++++--------------------------- dlls/win32u/message.c | 16 +++---------- dlls/win32u/ntuser_private.h | 8 ------- dlls/win32u/sysparams.c | 2 -- dlls/win32u/win32u_private.h | 1 - dlls/win32u/winstation.c | 2 -- 7 files changed, 14 insertions(+), 61 deletions(-)
diff --git a/dlls/win32u/hook.c b/dlls/win32u/hook.c index fab2b960fa5..eca9e7d6ce9 100644 --- a/dlls/win32u/hook.c +++ b/dlls/win32u/hook.c @@ -345,8 +345,6 @@ static LRESULT call_hook( struct win_hook_params *info, const WCHAR *module, siz if (params != info) free( params ); }
- if (info->id == WH_KEYBOARD_LL || info->id == WH_MOUSE_LL) - InterlockedIncrement( &global_key_state_counter ); /* force refreshing the key state cache */ return ret; }
diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 4d0c2589c1b..a582826d18e 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -406,7 +406,6 @@ static const KBDTABLES kbdus_tables =
static LONG clipping_cursor; /* clipping thread counter */
-LONG global_key_state_counter = 0; BOOL grab_pointer = TRUE; BOOL grab_fullscreen = FALSE;
@@ -810,52 +809,31 @@ static void check_for_events( UINT flags ) */ SHORT WINAPI NtUserGetAsyncKeyState( INT key ) { - struct user_key_state_info *key_state_info = get_user_thread_info()->key_state; - INT counter = global_key_state_counter; - BYTE prev_key_state; - SHORT ret; + const desktop_shm_t *desktop_shm; + struct object_lock lock = OBJECT_LOCK_INIT; + NTSTATUS status; + BYTE state = 0; + SHORT ret = 0;
if (key < 0 || key >= 256) return 0;
check_for_events( QS_INPUT );
- if (key_state_info && !(key_state_info->state[key] & 0xc0) && - key_state_info->counter == counter && NtGetTickCount() - key_state_info->time < 50) - { - /* use cached value */ - return 0; - } - else if (!key_state_info) - { - key_state_info = calloc( 1, sizeof(*key_state_info) ); - get_user_thread_info()->key_state = key_state_info; - } + while ((status = get_shared_desktop( &lock, &desktop_shm )) == STATUS_PENDING) + state = desktop_shm->keystate[key];
- ret = 0; + if (status) return 0; + if (!(state & 0x40)) return (state & 0x80) << 8; + + /* Need to make a server call to reset the last pressed bit */ SERVER_START_REQ( get_key_state ) { req->async = 1; req->key = key; - if (key_state_info) - { - prev_key_state = key_state_info->state[key]; - wine_server_set_reply( req, key_state_info->state, sizeof(key_state_info->state) ); - } if (!wine_server_call( req )) { if (reply->state & 0x40) ret |= 0x0001; if (reply->state & 0x80) ret |= 0x8000; - if (key_state_info) - { - /* force refreshing the key state cache - some multithreaded programs - * (like Adobe Photoshop CS5) expect that changes to the async key state - * are also immediately available in other threads. */ - if (prev_key_state != key_state_info->state[key]) - counter = InterlockedIncrement( &global_key_state_counter ); - - key_state_info->time = NtGetTickCount(); - key_state_info->counter = counter; - } } } SERVER_END_REQ; diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index d1f49ca3ed9..b7062414658 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -3469,7 +3469,7 @@ NTSTATUS send_hardware_message( HWND hwnd, UINT flags, const INPUT *input, LPARA struct send_message_info info; int prev_x, prev_y, new_x, new_y; NTSTATUS ret; - BOOL wait, affects_key_state = FALSE; + BOOL wait;
info.type = MSG_HARDWARE; info.dest_tid = 0; @@ -3495,10 +3495,6 @@ NTSTATUS send_hardware_message( HWND hwnd, UINT flags, const INPUT *input, LPARA req->input.mouse.flags = input->mi.dwFlags; req->input.mouse.time = input->mi.time; req->input.mouse.info = input->mi.dwExtraInfo; - affects_key_state = !!(input->mi.dwFlags & (MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP | - MOUSEEVENTF_RIGHTDOWN | MOUSEEVENTF_RIGHTUP | - MOUSEEVENTF_MIDDLEDOWN | MOUSEEVENTF_MIDDLEUP | - MOUSEEVENTF_XDOWN | MOUSEEVENTF_XUP)); break; case INPUT_KEYBOARD: if (input->ki.dwFlags & KEYEVENTF_SCANCODE) @@ -3523,7 +3519,6 @@ NTSTATUS send_hardware_message( HWND hwnd, UINT flags, const INPUT *input, LPARA req->input.kbd.flags = input->ki.dwFlags & ~KEYEVENTF_SCANCODE; req->input.kbd.time = input->ki.time; req->input.kbd.info = input->ki.dwExtraInfo; - affects_key_state = TRUE; break; case INPUT_HARDWARE: req->input.hw.msg = input->hi.uMsg; @@ -3553,13 +3548,8 @@ NTSTATUS send_hardware_message( HWND hwnd, UINT flags, const INPUT *input, LPARA } SERVER_END_REQ;
- if (!ret) - { - if (affects_key_state) - InterlockedIncrement( &global_key_state_counter ); /* force refreshing the key state cache */ - if ((flags & SEND_HWMSG_INJECTED) && (prev_x != new_x || prev_y != new_y)) - user_driver->pSetCursorPos( new_x, new_y ); - } + if (!ret && (flags & SEND_HWMSG_INJECTED) && (prev_x != new_x || prev_y != new_y)) + user_driver->pSetCursorPos( new_x, new_y );
if (wait) { diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index 39943e2261b..d95ea03d45f 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -116,7 +116,6 @@ struct user_thread_info HHOOK hook; /* Current hook */ UINT active_hooks; /* Bitmap of active hooks */ struct received_message_info *receive_info; /* Message being currently received */ - struct user_key_state_info *key_state; /* Cache of global key state */ struct imm_thread_data *imm_thread_data; /* IMM thread data */ HKL kbd_layout; /* Current keyboard layout */ UINT kbd_layout_id; /* Current keyboard layout ID */ @@ -134,13 +133,6 @@ static inline struct user_thread_info *get_user_thread_info(void) return CONTAINING_RECORD( NtUserGetThreadInfo(), struct user_thread_info, client_info ); }
-struct user_key_state_info -{ - UINT time; /* Time of last key state refresh */ - INT counter; /* Counter to invalidate the key state */ - BYTE state[256]; /* State for each key */ -}; - struct hook_extra_info { HHOOK handle; diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 34de10168e2..9a06db2c7f6 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -6334,8 +6334,6 @@ static void thread_detach(void) destroy_thread_windows(); user_driver->pThreadDetach();
- free( thread_info->key_state ); - thread_info->key_state = 0; free( thread_info->rawinput );
cleanup_imm_thread(); diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index f7ba2c1a423..e2e35d6c40d 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -90,7 +90,6 @@ extern void unregister_imm_window( HWND hwnd ); extern BOOL grab_pointer; extern BOOL grab_fullscreen; extern BOOL destroy_caret(void); -extern LONG global_key_state_counter; extern HWND get_active_window(void); extern HWND get_capture(void); extern BOOL get_cursor_pos( POINT *pt ); diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index 7168a614735..1676539c69c 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -441,11 +441,9 @@ BOOL WINAPI NtUserSetThreadDesktop( HDESK handle ) if (ret) /* reset the desktop windows */ { struct user_thread_info *thread_info = get_user_thread_info(); - struct user_key_state_info *key_state_info = thread_info->key_state; get_session_thread_data()->shared_desktop = find_shared_session_object( locator ); thread_info->client_info.top_window = 0; thread_info->client_info.msg_window = 0; - if (key_state_info) key_state_info->time = 0; if (was_virtual_desktop != is_virtual_desktop()) update_display_cache( FALSE ); } return ret;
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=146468
Your paranoid android.
=== debian11b (64 bit WoW report) ===
kernel32: comm.c:1574: Test failed: AbortWaitCts hComPortEvent failed comm.c:1586: Test failed: Unexpected time 1001, expected around 500
@rbernon `win32u, server: Use the shared memory for GetClipCursor and GetAsyncKeyState.` The patch, along with the ntsync patches, caused my games to freeze when starting with a black screen.
Proton changed [win32u/input.c NtUserGetAsyncKeyState](https://github.com/ValveSoftware/wine/blob/25af144e4ac4e8de6bf4d8ea5d960af06...) in commit [38660173bb5aa5250ad414ac27517dce25b30a6a ](https://github.com/ValveSoftware/wine/commit/38660173bb5aa5250ad414ac27517dc...)
I simplified the NtUserGetAsyncKeyState function to look like this. I'm not sure if it's correct, but it's helped me.
```C SHORT WINAPI NtUserGetAsyncKeyState( INT key ) { const desktop_shm_t *desktop_shm; struct object_lock lock = OBJECT_LOCK_INIT; NTSTATUS status; BYTE state = 0;
if (key < 0 || key >= 256) return 0;
check_for_events( QS_INPUT );
while ((status = get_shared_desktop( &lock, &desktop_shm )) == STATUS_PENDING) state = desktop_shm->keystate[key];
return (state & 0x80) << 8; } ```
On Fri Jun 21 10:34:07 2024 +0000, Grigory Vasilyev wrote:
@rbernon `win32u, server: Use the shared memory for GetClipCursor and GetAsyncKeyState.` The patch, along with the ntsync patches, caused my games to freeze when starting with a black screen. Proton changed [win32u/input.c NtUserGetAsyncKeyState](https://github.com/ValveSoftware/wine/blob/25af144e4ac4e8de6bf4d8ea5d960af06...) in commit [38660173bb5aa5250ad414ac27517dce25b30a6a ](https://github.com/ValveSoftware/wine/commit/38660173bb5aa5250ad414ac27517dc...) I simplified the NtUserGetAsyncKeyState function to look like this. I'm not sure if it's correct, but it's helped me.
SHORT WINAPI NtUserGetAsyncKeyState( INT key ) { const desktop_shm_t *desktop_shm; struct object_lock lock = OBJECT_LOCK_INIT; NTSTATUS status; BYTE state = 0; if (key < 0 || key >= 256) return 0; check_for_events( QS_INPUT ); while ((status = get_shared_desktop( &lock, &desktop_shm )) == STATUS_PENDING) state = desktop_shm->keystate[key]; return (state & 0x80) << 8; }
Yes, and it saves another wineserver request but it's also not strictly correct (hence Proton "HACK" flag).
Is this happening with just this MR? Can you name one game specifically where it happens?
On Fri Jun 21 10:35:10 2024 +0000, Rémi Bernon wrote:
Yes, and it saves another wineserver request but it's also not strictly correct (hence Proton "HACK" flag). Is this happening with just this MR? Can you name one game specifically where it happens?
@rbernon I haven't tested this MR separately yet, I need time.
The error occurred when I added [wip/shared-memories](https://gitlab.winehq.org/rbernon/wine/-/commits/wip/shared-memories) and encountered several errors. One of the errors was a black screen in games. This happened in all games at startup, for example Overwatch 2. The second error that I had was that in games the CAPS LOCK button was pressed and the text was typed in capital letters, but I could not find why this was happening. This is probably not a problem with the SHIFT button, because SHIFT in games is assigned to running, and switching occurs normally.
On Fri Jun 21 10:44:56 2024 +0000, Grigory Vasilyev wrote:
@rbernon I haven't tested this MR separately yet, I need time. The error occurred when I added [wip/shared-memories](https://gitlab.winehq.org/rbernon/wine/-/commits/wip/shared-memories) and encountered several errors. One of the errors was a black screen in games. This happened in all games at startup, for example Overwatch 2. The second error that I had was that in games the CAPS LOCK button was pressed and the text was typed in capital letters, but I could not find why this was happening. This is probably not a problem with the SHIFT button, because SHIFT in games is assigned to running, and switching occurs normally.
Well, I don't know. I've run a couple of games with these changes and I don't see any issues (haven't tried Overwatch 2 as I don't have it downloaded).
On Fri Jun 21 11:14:28 2024 +0000, Rémi Bernon wrote:
Well, I don't know. I've run a couple of games with these changes and I don't see any issues (haven't tried Overwatch 2 as I don't have it downloaded).
@rbernon I tested only this MR separately without the other `wip/shared-memories` patches, everything works well. I can assume that this has something to do with the `wake_mask`, `wake_bits`, patches in `wip/shared-memories` and there are probably errors somewhere when working together with `ntsync`.M aybe I didn't rebase the patches correctly.
On Fri Jun 21 11:53:45 2024 +0000, Grigory Vasilyev wrote:
@rbernon I tested only this MR separately without the other `wip/shared-memories` patches, everything works well. I can assume that this has something to do with the `wake_mask`, `wake_bits`, patches in `wip/shared-memories` and there are probably errors somewhere when working together with `ntsync`.M aybe I didn't rebase the patches correctly.
Thanks for the confirmation!