win32u: Invalidate all cached keys after input.

This patch addresses an issue in Second Life and potentially other
multi-threaded applications which process WM_KEYDOWN in one thread
and then verify that the key is "still down" with GetAsyncKeyState
from another thread. Wine uses a per-thread key cache, resulting
in inconsistent views of key status. Caches are now invalidated
when an input event is injected by the driver or via SendInput.
This commit is contained in:
Henry Goffin 2023-02-28 12:40:23 -08:00 committed by Alexandre Julliard
parent 7c3941ce7e
commit 0e85ac17a4
5 changed files with 9 additions and 16 deletions

View file

@ -2585,13 +2585,11 @@ LRESULT send_internal_message_timeout( DWORD dest_pid, DWORD dest_tid,
*/
NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, const RAWINPUT *rawinput, UINT flags )
{
struct user_key_state_info *key_state_info = get_user_thread_info()->key_state;
struct send_message_info info;
int prev_x, prev_y, new_x, new_y;
INT counter = global_key_state_counter;
USAGE hid_usage_page, hid_usage;
NTSTATUS ret;
BOOL wait;
BOOL wait, affects_key_state = FALSE;
info.type = MSG_HARDWARE;
info.dest_tid = 0;
@ -2629,6 +2627,10 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, const RAWINPUT *r
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:
req->input.kbd.vkey = input->ki.wVk;
@ -2636,6 +2638,7 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, const RAWINPUT *r
req->input.kbd.flags = input->ki.dwFlags;
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;
@ -2664,8 +2667,6 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, const RAWINPUT *r
}
break;
}
if (key_state_info) wine_server_set_reply( req, key_state_info->state,
sizeof(key_state_info->state) );
ret = wine_server_call( req );
wait = reply->wait;
prev_x = reply->prev_x;
@ -2677,11 +2678,8 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, const RAWINPUT *r
if (!ret)
{
if (key_state_info)
{
key_state_info->time = NtGetTickCount();
key_state_info->counter = counter;
}
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 );
}

View file

@ -2768,7 +2768,6 @@ struct send_hardware_message_reply
int prev_y;
int new_x;
int new_y;
/* VARARG(keystate,bytes); */
char __pad_28[4];
};
#define SEND_HWMSG_INJECTED 0x01
@ -6356,7 +6355,7 @@ union generic_reply
/* ### protocol_version begin ### */
#define SERVER_PROTOCOL_VERSION 760
#define SERVER_PROTOCOL_VERSION 761
/* ### protocol_version end ### */

View file

@ -2078,7 +2078,6 @@ enum message_type
int prev_y;
int new_x; /* new cursor position */
int new_y;
VARARG(keystate,bytes); /* global state array for all the keys */
@END
#define SEND_HWMSG_INJECTED 0x01

View file

@ -2551,7 +2551,6 @@ DECL_HANDLER(send_hardware_message)
struct desktop *desktop;
unsigned int origin = (req->flags & SEND_HWMSG_INJECTED ? IMO_INJECTED : IMO_HARDWARE);
struct msg_queue *sender = get_current_queue();
data_size_t size = min( 256, get_reply_max_size() );
if (!(desktop = get_thread_desktop( current, 0 ))) return;
@ -2587,7 +2586,6 @@ DECL_HANDLER(send_hardware_message)
reply->new_x = desktop->cursor.x;
reply->new_y = desktop->cursor.y;
set_reply_data( desktop->keystate, size );
release_object( desktop );
}

View file

@ -2662,7 +2662,6 @@ static void dump_send_hardware_message_reply( const struct send_hardware_message
fprintf( stderr, ", prev_y=%d", req->prev_y );
fprintf( stderr, ", new_x=%d", req->new_x );
fprintf( stderr, ", new_y=%d", req->new_y );
dump_varargs_bytes( ", keystate=", cur_size );
}
static void dump_get_message_request( const struct get_message_request *req )