The first commits add some test infrastructure to be able check raw input keyboard events, along with a few tests relevant to the code paths in this MR. This MR also introduces support for checking async key state in tests.
For some fixes it was difficult to express the current Wine behavior with TODOs in the expected sequence, so tests for these were added along with the fix.
-- v3: server: Set VK_PACKET async state in raw input legacy mode.
From: Alexandros Frantzis alexandros.frantzis@collabora.com
--- dlls/user32/tests/input.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+)
diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index c123f8fa439..f21b9e24555 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -1169,6 +1169,25 @@ static void test_SendInput_keyboard_messages( WORD vkey, WORD scan, WCHAR wch, W {0}, };
+ struct send_input_keyboard_test unicode_vkey_ctrl[] = + { + {.scan = 0x3c0, .vkey = VK_CONTROL, .flags = KEYEVENTF_UNICODE, + .expect_state = {[VK_CONTROL] = 0x80, [VK_LCONTROL] = 0x80}, .todo_state = {[VK_LCONTROL] = TRUE}, + .expect = {KEY_HOOK(WM_KEYDOWN, 0xc0, VK_LCONTROL, .todo_value = TRUE), KEY_MSG(WM_KEYDOWN, 0xc0, VK_CONTROL), {0}}}, + {.scan = 0x3c0, .vkey = VK_CONTROL, .flags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP, + .expect = {KEY_HOOK(WM_KEYUP, 0xc0, VK_LCONTROL, .todo_value = TRUE), KEY_MSG(WM_KEYUP, 0xc0, VK_CONTROL), {0}}}, + {0}, + }; + + struct send_input_keyboard_test unicode_vkey_packet[] = + { + {.scan = 0x3c0, .vkey = VK_PACKET, .flags = KEYEVENTF_UNICODE, .expect_state = {[VK_PACKET] = 0x80}, + .expect = {KEY_HOOK(WM_KEYDOWN, 0xc0, VK_PACKET), KEY_MSG(WM_KEYDOWN, 0, VK_PACKET, .todo_value = TRUE), WIN_MSG(WM_CHAR, 0xc0, 1), {0}}}, + {.scan = 0x3c0, .vkey = VK_PACKET, .flags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP, + .expect = {KEY_HOOK(WM_KEYUP, 0xc0, VK_PACKET), KEY_MSG(WM_KEYUP, 0, VK_PACKET, .todo_value = TRUE), {0}}}, + {0}, + }; + struct send_input_keyboard_test numpad_scan[] = { {.scan = 0x4b, .flags = KEYEVENTF_SCANCODE, .expect_state = {[VK_LEFT] = 0x80}, @@ -1288,6 +1307,8 @@ static void test_SendInput_keyboard_messages( WORD vkey, WORD scan, WCHAR wch, W check_send_input_keyboard_test( unicode, TRUE ); check_send_input_keyboard_test( lmenu_unicode_peeked, TRUE ); check_send_input_keyboard_test( unicode_vkey, TRUE ); + check_send_input_keyboard_test( unicode_vkey_ctrl, TRUE ); + check_send_input_keyboard_test( unicode_vkey_packet, TRUE ); check_send_input_keyboard_test( numpad_scan, TRUE ); check_send_input_keyboard_test( numpad_scan_numlock, TRUE ); winetest_pop_context(); @@ -1333,6 +1354,8 @@ static void test_SendInput_keyboard_messages( WORD vkey, WORD scan, WCHAR wch, W check_send_input_keyboard_test( unicode, FALSE ); check_send_input_keyboard_test( lmenu_unicode, FALSE ); check_send_input_keyboard_test( unicode_vkey, FALSE ); + check_send_input_keyboard_test( unicode_vkey_ctrl, FALSE ); + check_send_input_keyboard_test( unicode_vkey_packet, FALSE ); check_send_input_keyboard_test( numpad_scan, FALSE ); check_send_input_keyboard_test( numpad_scan_numlock, FALSE ); winetest_pop_context();
From: Alexandros Frantzis alexandros.frantzis@collabora.com
--- dlls/user32/tests/input.c | 161 +++++++++++++++++++++++++++++++++++++- 1 file changed, 160 insertions(+), 1 deletion(-)
diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index f21b9e24555..382e15b9ed2 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -111,6 +111,7 @@ enum user_function MSG_TEST_WIN = 1, LL_HOOK_KEYBD, LL_HOOK_MOUSE, + RAW_INPUT_KEYBOARD, };
struct user_call @@ -143,6 +144,12 @@ struct user_call UINT time; UINT_PTR extra; } ll_hook_ms; + struct + { + HWND hwnd; + BYTE code; + RAWKEYBOARD kbd; + } raw_input; };
BOOL todo; @@ -225,6 +232,15 @@ static int ok_call_( const char *file, int line, const struct user_call *expecte if (0 && (ret = expected->ll_hook_ms.time - received->ll_hook_ms.time)) goto done; if ((ret = (expected->ll_hook_ms.extra - received->ll_hook_ms.extra))) goto done; break; + case RAW_INPUT_KEYBOARD: + if ((ret = expected->raw_input.hwnd - received->raw_input.hwnd)) goto done; + if ((ret = expected->raw_input.code - received->raw_input.code)) goto done; + if ((ret = expected->raw_input.kbd.MakeCode - received->raw_input.kbd.MakeCode)) goto done; + if ((ret = expected->raw_input.kbd.Flags - received->raw_input.kbd.Flags)) goto done; + if ((ret = expected->raw_input.kbd.VKey - received->raw_input.kbd.VKey)) goto done; + if ((ret = expected->raw_input.kbd.Message - received->raw_input.kbd.Message)) goto done; + if ((ret = expected->raw_input.kbd.ExtraInformation - received->raw_input.kbd.ExtraInformation)) goto done; + break; }
done: @@ -249,6 +265,13 @@ done: wine_dbgstr_point(&received->ll_hook_ms.point), received->ll_hook_ms.data, received->ll_hook_ms.flags, received->ll_hook_ms.time, received->ll_hook_ms.extra ); return ret; + case RAW_INPUT_KEYBOARD: + todo_wine_if( expected->todo || expected->todo_value ) + ok_(file, line)( !ret, "got WM_INPUT key hwnd %p, code %d, make_code %#x, flags %#x, vkey %s, message %s, extra %#lx\n", + received->raw_input.hwnd, received->raw_input.code, received->raw_input.kbd.MakeCode, + received->raw_input.kbd.Flags, debugstr_vk(received->raw_input.kbd.VKey), + debugstr_wm(received->raw_input.kbd.Message), received->raw_input.kbd.ExtraInformation ); + return ret; }
switch (expected->func) @@ -270,6 +293,13 @@ done: wine_dbgstr_point(&received->ll_hook_ms.point), received->ll_hook_ms.data, received->ll_hook_ms.flags, received->ll_hook_ms.time, received->ll_hook_ms.extra ); return ret; + case RAW_INPUT_KEYBOARD: + todo_wine_if( expected->todo || expected->todo_value ) + ok_(file, line)( !ret, "got WM_INPUT key hwnd %p, code %d, make_code %#x, flags %#x, vkey %s, message %s, extra %#lx\n", + expected->raw_input.hwnd, expected->raw_input.code, expected->raw_input.kbd.MakeCode, + expected->raw_input.kbd.Flags, debugstr_vk(expected->raw_input.kbd.VKey), + debugstr_wm(expected->raw_input.kbd.Message), expected->raw_input.kbd.ExtraInformation ); + return ret; }
return 0; @@ -342,9 +372,32 @@ static void append_ll_hook_ms( UINT msg, const MSLLHOOKSTRUCT *info ) } }
+static void append_rawinput_message( HWND hwnd, WPARAM wparam, HRAWINPUT handle ) +{ + RAWINPUT rawinput; + UINT size = sizeof(rawinput), ret; + + ret = GetRawInputData( handle, RID_INPUT, &rawinput, &size, sizeof(RAWINPUTHEADER) ); + ok_ne( ret, (UINT)-1, UINT, "%u" ); + + if (rawinput.header.dwType == RIM_TYPEKEYBOARD) + { + struct user_call call = + { + .func = RAW_INPUT_KEYBOARD, + .raw_input = {.hwnd = hwnd, .code = GET_RAWINPUT_CODE_WPARAM(wparam), .kbd = rawinput.data.keyboard} + }; + ULONG index = InterlockedIncrement( ¤t_sequence_len ) - 1; + ok( index < ARRAY_SIZE(current_sequence), "got %lu calls\n", index ); + if (!append_message_hwnd) call.message.hwnd = 0; + current_sequence[index] = call; + } +} + static void append_message( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ) { - if (!p_accept_message || p_accept_message( msg )) + if (msg == WM_INPUT) append_rawinput_message( hwnd, wparam, (HRAWINPUT)lparam ); + else if (!p_accept_message || p_accept_message( msg )) { struct user_call call = {.func = MSG_TEST_WIN, .message = {.hwnd = hwnd, .msg = msg, .wparam = wparam, .lparam = lparam}}; ULONG index = InterlockedIncrement( ¤t_sequence_len ) - 1; @@ -1381,6 +1434,111 @@ static void test_keynames(void) } }
+static BOOL accept_keyboard_messages_raw( UINT msg ) +{ + return is_keyboard_message( msg ) || msg == WM_INPUT; +} + +static void test_SendInput_raw_key_messages( WORD vkey, WORD wch, HKL hkl ) +{ +#define WIN_MSG(m, w, l, ...) {.func = MSG_TEST_WIN, .message = {.msg = m, .wparam = w, .lparam = l}, ## __VA_ARGS__} +#define RAW_KEY(s, f, v, m, ...) {.func = RAW_INPUT_KEYBOARD, .raw_input.kbd = {.MakeCode = s, .Flags = f, .VKey = v, .Message = m}, ## __VA_ARGS__} +#define KEY_MSG(m, s, v, ...) WIN_MSG( m, v, MAKELONG(1, (s) | (m == WM_KEYUP || m == WM_SYSKEYUP ? (KF_UP | KF_REPEAT) : 0)), ## __VA_ARGS__ ) + struct send_input_keyboard_test raw_legacy[] = + { + {.vkey = vkey, + .expect = {RAW_KEY(1, RI_KEY_MAKE, vkey, WM_KEYDOWN), KEY_MSG(WM_KEYDOWN, 1, vkey), WIN_MSG(WM_CHAR, wch, MAKELONG(1, 1)), {0}}}, + {.vkey = vkey, .flags = KEYEVENTF_KEYUP, + .expect = {RAW_KEY(2, RI_KEY_BREAK, vkey, WM_KEYUP), KEY_MSG(WM_KEYUP, 2, vkey), {0}}}, + {0}, + }; + struct send_input_keyboard_test raw_nolegacy[] = + { + {.vkey = vkey, .expect = {RAW_KEY(1, RI_KEY_MAKE, vkey, WM_KEYDOWN), {0}}}, + {.vkey = vkey, .flags = KEYEVENTF_KEYUP, .expect = {RAW_KEY(2, RI_KEY_BREAK, vkey, WM_KEYUP), {0}}}, + {0}, + }; + struct send_input_keyboard_test raw_vk_packet_legacy[] = + { + {.vkey = VK_PACKET, .expect_state = {[VK_PACKET] = 0x80}, + .expect = {RAW_KEY(1, RI_KEY_MAKE, VK_PACKET, WM_KEYDOWN), KEY_MSG(WM_KEYDOWN, 1, VK_PACKET), {0, .todo = TRUE}}}, + {.vkey = VK_PACKET, .flags = KEYEVENTF_KEYUP, + .expect = {RAW_KEY(2, RI_KEY_BREAK, VK_PACKET, WM_KEYUP), KEY_MSG(WM_KEYUP, 2, VK_PACKET), {0}}}, + {0}, + }; + struct send_input_keyboard_test raw_vk_packet_nolegacy[] = + { + {.vkey = VK_PACKET, .expect = {RAW_KEY(1, RI_KEY_MAKE, VK_PACKET, WM_KEYDOWN), {0}}}, + {.vkey = VK_PACKET, .flags = KEYEVENTF_KEYUP, .expect = {RAW_KEY(2, RI_KEY_BREAK, VK_PACKET, WM_KEYUP), {0}}}, + {0}, + }; +#undef WIN_MSG +#undef RAW_KEY +#undef KEY_MSG + RAWINPUTDEVICE rid = {.usUsagePage = HID_USAGE_PAGE_GENERIC, .usUsage = HID_USAGE_GENERIC_KEYBOARD}; + int receive; + HWND hwnd; + + raw_legacy[0].expect_state[vkey] = 0x80; + + hwnd = CreateWindowW( L"static", NULL, WS_POPUP | WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, NULL, NULL ); + ok_ne( NULL, hwnd, HWND, "%p" ); + wait_messages( 100, FALSE ); + + /* If we have had a spurious layout change, wch may be incorrect. */ + if (GetKeyboardLayout( 0 ) != hkl) + { + win_skip( "Spurious keyboard layout changed detected (expected: %p got: %p)\n", + hkl, GetKeyboardLayout( 0 ) ); + ok_ret( 1, DestroyWindow( hwnd ) ); + wait_messages( 100, FALSE ); + ok_seq( empty_sequence ); + return; + } + + p_accept_message = accept_keyboard_messages_raw; + + for (receive = 0; receive <= 1; receive++) + { + winetest_push_context( receive ? "receive" : "peek" ); + + if (receive) + { + /* test received messages */ + LONG_PTR old_proc = SetWindowLongPtrW( hwnd, GWLP_WNDPROC, (LONG_PTR)append_message_wndproc ); + ok_ne( 0, old_proc, LONG_PTR, "%#Ix" ); + } + + rid.dwFlags = 0; + ok_ret( 1, RegisterRawInputDevices( &rid, 1, sizeof(rid) ) ); + + /* get both WM_INPUT and legacy messages */ + check_send_input_keyboard_test( raw_legacy, !receive ); + check_send_input_keyboard_test( raw_vk_packet_legacy, !receive ); + + rid.dwFlags = RIDEV_REMOVE; + ok_ret( 1, RegisterRawInputDevices( &rid, 1, sizeof(rid) ) ); + + rid.dwFlags = RIDEV_NOLEGACY; + ok_ret( 1, RegisterRawInputDevices( &rid, 1, sizeof(rid) ) ); + + /* get only WM_INPUT messages */ + check_send_input_keyboard_test( raw_nolegacy, !receive ); + check_send_input_keyboard_test( raw_vk_packet_nolegacy, !receive ); + + rid.dwFlags = RIDEV_REMOVE; + ok_ret( 1, RegisterRawInputDevices( &rid, 1, sizeof(rid) ) ); + + winetest_pop_context(); + } + + ok_ret( 1, DestroyWindow( hwnd ) ); + wait_messages( 100, FALSE ); + ok_seq( empty_sequence ); + + p_accept_message = NULL; +} + static void test_GetMouseMovePointsEx( char **argv ) { #define BUFLIM 64 @@ -5896,6 +6054,7 @@ static void test_input_desktop( char **argv ) test_RegisterRawInputDevices(); test_GetRawInputData(); test_GetRawInputBuffer(); + test_SendInput_raw_key_messages( 'F', wch, hkl );
test_LoadKeyboardLayoutEx( hkl );
From: Alexandros Frantzis alexandros.frantzis@collabora.com
--- dlls/user32/tests/input.c | 12 ++++++------ server/queue.c | 3 +++ 2 files changed, 9 insertions(+), 6 deletions(-)
diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index 382e15b9ed2..560baa399da 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -907,9 +907,9 @@ static void test_SendInput_keyboard_messages( WORD vkey, WORD scan, WCHAR wch, W static const struct send_input_keyboard_test shift[] = { {.vkey = VK_SHIFT, .expect_state = {[VK_SHIFT] = 0x80, [VK_LSHIFT] = 0x80}, - .expect = {KEY_HOOK(WM_KEYDOWN, 1, VK_LSHIFT, .todo_value = TRUE), KEY_MSG(WM_KEYDOWN, 1, VK_SHIFT), {0}}}, + .expect = {KEY_HOOK(WM_KEYDOWN, 1, VK_LSHIFT), KEY_MSG(WM_KEYDOWN, 1, VK_SHIFT), {0}}}, {.vkey = VK_SHIFT, .flags = KEYEVENTF_KEYUP, - .expect = {KEY_HOOK(WM_KEYUP, 2, VK_LSHIFT, .todo_value = TRUE), KEY_MSG(WM_KEYUP, 2, VK_SHIFT), {0}}}, + .expect = {KEY_HOOK(WM_KEYUP, 2, VK_LSHIFT), KEY_MSG(WM_KEYUP, 2, VK_SHIFT), {0}}}, {0}, }; static const struct send_input_keyboard_test shift_ext[] = @@ -948,17 +948,17 @@ static void test_SendInput_keyboard_messages( WORD vkey, WORD scan, WCHAR wch, W static const struct send_input_keyboard_test control[] = { {.vkey = VK_CONTROL, .expect_state = {[VK_CONTROL] = 0x80, [VK_LCONTROL] = 0x80}, - .expect = {KEY_HOOK(WM_KEYDOWN, 1, VK_LCONTROL, .todo_value = TRUE), KEY_MSG(WM_KEYDOWN, 1, VK_CONTROL), {0}}}, + .expect = {KEY_HOOK(WM_KEYDOWN, 1, VK_LCONTROL), KEY_MSG(WM_KEYDOWN, 1, VK_CONTROL), {0}}}, {.vkey = VK_CONTROL, .flags = KEYEVENTF_KEYUP, .expect_state = {0}, - .expect = {KEY_HOOK(WM_KEYUP, 2, VK_LCONTROL, .todo_value = TRUE), KEY_MSG(WM_KEYUP, 2, VK_CONTROL), {0}}}, + .expect = {KEY_HOOK(WM_KEYUP, 2, VK_LCONTROL), KEY_MSG(WM_KEYUP, 2, VK_CONTROL), {0}}}, {0}, }; static const struct send_input_keyboard_test control_ext[] = { {.vkey = VK_CONTROL, .flags = KEYEVENTF_EXTENDEDKEY, .expect_state = {[VK_CONTROL] = 0x80, [VK_RCONTROL] = 0x80}, - .expect = {KEY_HOOK_(WM_KEYDOWN, 1, VK_RCONTROL, LLKHF_EXTENDED, .todo_value = TRUE), KEY_MSG_(WM_KEYDOWN, 1, VK_CONTROL, KF_EXTENDED), {0}}}, + .expect = {KEY_HOOK_(WM_KEYDOWN, 1, VK_RCONTROL, LLKHF_EXTENDED), KEY_MSG_(WM_KEYDOWN, 1, VK_CONTROL, KF_EXTENDED), {0}}}, {.vkey = VK_CONTROL, .flags = KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, - .expect = {KEY_HOOK_(WM_KEYUP, 2, VK_RCONTROL, LLKHF_EXTENDED, .todo_value = TRUE), KEY_MSG_(WM_KEYUP, 2, VK_CONTROL, KF_EXTENDED), {0}}}, + .expect = {KEY_HOOK_(WM_KEYUP, 2, VK_RCONTROL, LLKHF_EXTENDED), KEY_MSG_(WM_KEYUP, 2, VK_CONTROL, KF_EXTENDED), {0}}}, {0}, };
diff --git a/server/queue.c b/server/queue.c index 6d4396234f2..3ffa48c3928 100644 --- a/server/queue.c +++ b/server/queue.c @@ -2111,16 +2111,19 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c case VK_LMENU: case VK_RMENU: vkey = (input->kbd.flags & KEYEVENTF_EXTENDEDKEY) ? VK_RMENU : VK_LMENU; + if ((input->kbd.vkey & 0xff) == VK_MENU) hook_vkey = vkey; break; case VK_CONTROL: case VK_LCONTROL: case VK_RCONTROL: vkey = (input->kbd.flags & KEYEVENTF_EXTENDEDKEY) ? VK_RCONTROL : VK_LCONTROL; + if ((input->kbd.vkey & 0xff) == VK_CONTROL) hook_vkey = vkey; break; case VK_SHIFT: case VK_LSHIFT: case VK_RSHIFT: vkey = (input->kbd.flags & KEYEVENTF_EXTENDEDKEY) ? VK_RSHIFT : VK_LSHIFT; + if ((input->kbd.vkey & 0xff) == VK_SHIFT) hook_vkey = vkey; break; } }
From: Alexandros Frantzis alexandros.frantzis@collabora.com
--- dlls/user32/tests/input.c | 7 +++---- server/queue.c | 41 ++++++++++++++++++--------------------- 2 files changed, 22 insertions(+), 26 deletions(-)
diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index 560baa399da..0bcea006db1 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -1224,11 +1224,10 @@ static void test_SendInput_keyboard_messages( WORD vkey, WORD scan, WCHAR wch, W
struct send_input_keyboard_test unicode_vkey_ctrl[] = { - {.scan = 0x3c0, .vkey = VK_CONTROL, .flags = KEYEVENTF_UNICODE, - .expect_state = {[VK_CONTROL] = 0x80, [VK_LCONTROL] = 0x80}, .todo_state = {[VK_LCONTROL] = TRUE}, - .expect = {KEY_HOOK(WM_KEYDOWN, 0xc0, VK_LCONTROL, .todo_value = TRUE), KEY_MSG(WM_KEYDOWN, 0xc0, VK_CONTROL), {0}}}, + {.scan = 0x3c0, .vkey = VK_CONTROL, .flags = KEYEVENTF_UNICODE, .expect_state = {[VK_CONTROL] = 0x80, [VK_LCONTROL] = 0x80}, + .expect = {KEY_HOOK(WM_KEYDOWN, 0xc0, VK_LCONTROL), KEY_MSG(WM_KEYDOWN, 0xc0, VK_CONTROL), {0}}}, {.scan = 0x3c0, .vkey = VK_CONTROL, .flags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP, - .expect = {KEY_HOOK(WM_KEYUP, 0xc0, VK_LCONTROL, .todo_value = TRUE), KEY_MSG(WM_KEYUP, 0xc0, VK_CONTROL), {0}}}, + .expect = {KEY_HOOK(WM_KEYUP, 0xc0, VK_LCONTROL), KEY_MSG(WM_KEYUP, 0xc0, VK_CONTROL), {0}}}, {0}, };
diff --git a/server/queue.c b/server/queue.c index 3ffa48c3928..7d1cf780837 100644 --- a/server/queue.c +++ b/server/queue.c @@ -2103,29 +2103,26 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c
if (!(time = input->kbd.time)) time = get_tick_count();
- if (!(input->kbd.flags & KEYEVENTF_UNICODE)) + switch (vkey) { - switch (vkey) - { - case VK_MENU: - case VK_LMENU: - case VK_RMENU: - vkey = (input->kbd.flags & KEYEVENTF_EXTENDEDKEY) ? VK_RMENU : VK_LMENU; - if ((input->kbd.vkey & 0xff) == VK_MENU) hook_vkey = vkey; - break; - case VK_CONTROL: - case VK_LCONTROL: - case VK_RCONTROL: - vkey = (input->kbd.flags & KEYEVENTF_EXTENDEDKEY) ? VK_RCONTROL : VK_LCONTROL; - if ((input->kbd.vkey & 0xff) == VK_CONTROL) hook_vkey = vkey; - break; - case VK_SHIFT: - case VK_LSHIFT: - case VK_RSHIFT: - vkey = (input->kbd.flags & KEYEVENTF_EXTENDEDKEY) ? VK_RSHIFT : VK_LSHIFT; - if ((input->kbd.vkey & 0xff) == VK_SHIFT) hook_vkey = vkey; - break; - } + case VK_MENU: + case VK_LMENU: + case VK_RMENU: + vkey = (input->kbd.flags & KEYEVENTF_EXTENDEDKEY) ? VK_RMENU : VK_LMENU; + if ((input->kbd.vkey & 0xff) == VK_MENU) hook_vkey = vkey; + break; + case VK_CONTROL: + case VK_LCONTROL: + case VK_RCONTROL: + vkey = (input->kbd.flags & KEYEVENTF_EXTENDEDKEY) ? VK_RCONTROL : VK_LCONTROL; + if ((input->kbd.vkey & 0xff) == VK_CONTROL) hook_vkey = vkey; + break; + case VK_SHIFT: + case VK_LSHIFT: + case VK_RSHIFT: + vkey = (input->kbd.flags & KEYEVENTF_EXTENDEDKEY) ? VK_RSHIFT : VK_LSHIFT; + if ((input->kbd.vkey & 0xff) == VK_SHIFT) hook_vkey = vkey; + break; }
message_code = (input->kbd.flags & KEYEVENTF_KEYUP) ? WM_KEYUP : WM_KEYDOWN;
From: Alexandros Frantzis alexandros.frantzis@collabora.com
--- dlls/user32/tests/input.c | 35 +++++++++++++++++++++++++++++++++++ server/queue.c | 5 +++-- 2 files changed, 38 insertions(+), 2 deletions(-)
diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index 0bcea006db1..f4d3b182ca7 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -1471,6 +1471,35 @@ static void test_SendInput_raw_key_messages( WORD vkey, WORD wch, HKL hkl ) {.vkey = VK_PACKET, .flags = KEYEVENTF_KEYUP, .expect = {RAW_KEY(2, RI_KEY_BREAK, VK_PACKET, WM_KEYUP), {0}}}, {0}, }; + struct send_input_keyboard_test raw_unicode_legacy[] = + { + {.scan = 0x3c0, .flags = KEYEVENTF_UNICODE, .expect_state = {[VK_PACKET] = 0x80}, + .expect = {KEY_MSG(WM_KEYDOWN, 0, VK_PACKET, .todo_value = TRUE), WIN_MSG(WM_CHAR, 0x3c0, 1), {0}}}, + {.scan = 0x3c0, .flags = KEYEVENTF_KEYUP | KEYEVENTF_UNICODE, + .expect = {KEY_MSG(WM_KEYUP, 0, VK_PACKET, .todo_value = TRUE), {0}}}, + {0}, + }; + struct send_input_keyboard_test raw_unicode_nolegacy[] = + { + {.scan = 0x3c0, .flags = KEYEVENTF_UNICODE}, + {.scan = 0x3c0, .flags = KEYEVENTF_KEYUP | KEYEVENTF_UNICODE}, + {0}, + }; + struct send_input_keyboard_test raw_unicode_vkey_ctrl_legacy[] = + { + {.scan = 0x3c0, .vkey = VK_CONTROL, .flags = KEYEVENTF_UNICODE, + .expect_state = {[VK_CONTROL] = 0x80, [VK_LCONTROL] = 0x80}, + .expect = {KEY_MSG(WM_KEYDOWN, 0xc0, VK_CONTROL), {0}}}, + {.scan = 0x3c0, .vkey = VK_CONTROL, .flags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP, + .expect = {KEY_MSG(WM_KEYUP, 0xc0, VK_CONTROL), {0}}}, + {0}, + }; + struct send_input_keyboard_test raw_unicode_vkey_ctrl_nolegacy[] = + { + {.scan = 0x3c0, .vkey = VK_CONTROL, .flags = KEYEVENTF_UNICODE}, + {.scan = 0x3c0, .vkey = VK_CONTROL, .flags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP}, + {0}, + }; #undef WIN_MSG #undef RAW_KEY #undef KEY_MSG @@ -1514,6 +1543,9 @@ static void test_SendInput_raw_key_messages( WORD vkey, WORD wch, HKL hkl ) /* get both WM_INPUT and legacy messages */ check_send_input_keyboard_test( raw_legacy, !receive ); check_send_input_keyboard_test( raw_vk_packet_legacy, !receive ); + /* no WM_INPUT message for unicode */ + check_send_input_keyboard_test( raw_unicode_legacy, !receive ); + check_send_input_keyboard_test( raw_unicode_vkey_ctrl_legacy, !receive );
rid.dwFlags = RIDEV_REMOVE; ok_ret( 1, RegisterRawInputDevices( &rid, 1, sizeof(rid) ) ); @@ -1524,6 +1556,9 @@ static void test_SendInput_raw_key_messages( WORD vkey, WORD wch, HKL hkl ) /* get only WM_INPUT messages */ check_send_input_keyboard_test( raw_nolegacy, !receive ); check_send_input_keyboard_test( raw_vk_packet_nolegacy, !receive ); + /* no WM_INPUT message for unicode */ + check_send_input_keyboard_test( raw_unicode_nolegacy, !receive ); + check_send_input_keyboard_test( raw_unicode_vkey_ctrl_nolegacy, !receive );
rid.dwFlags = RIDEV_REMOVE; ok_ret( 1, RegisterRawInputDevices( &rid, 1, sizeof(rid) ) ); diff --git a/server/queue.c b/server/queue.c index 7d1cf780837..4d48da1d484 100644 --- a/server/queue.c +++ b/server/queue.c @@ -2099,6 +2099,7 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c unsigned int message_code, time; lparam_t lparam = input->kbd.scan << 16; unsigned int flags = 0; + BOOL unicode = input->kbd.flags & KEYEVENTF_UNICODE; int wait;
if (!(time = input->kbd.time)) time = get_tick_count(); @@ -2188,7 +2189,7 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c } }
- if ((foreground = get_foreground_thread( desktop, win ))) + if (!unicode && (foreground = get_foreground_thread( desktop, win ))) { struct rawinput_message raw_msg = {0}; raw_msg.foreground = foreground; @@ -2216,7 +2217,7 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c msg->msg = message_code; if (origin == IMO_INJECTED) msg_data->flags = LLKHF_INJECTED;
- if (input->kbd.flags & KEYEVENTF_UNICODE && !vkey) + if (unicode && !vkey) { vkey = hook_vkey = VK_PACKET; }
From: Alexandros Frantzis alexandros.frantzis@collabora.com
--- dlls/user32/tests/input.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-)
diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index f4d3b182ca7..94db58e6796 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -628,6 +628,9 @@ struct send_input_keyboard_test struct user_call expect[8]; BYTE expect_state[256]; BOOL todo_state[256]; + BOOL async; + BYTE expect_async[256]; + BOOL todo_async[256]; };
static LRESULT CALLBACK ll_hook_kbd_proc(int code, WPARAM wparam, LPARAM lparam) @@ -668,6 +671,22 @@ static void check_keyboard_state_( int line, const BYTE expect_state[256], const } }
+#define check_keyboard_async( a, b ) check_keyboard_async_( __LINE__, a, b ) +static void check_keyboard_async_( int line, const BYTE expect_state[256], const BOOL todo_state[256] ) +{ + UINT i; + + /* TODO: figure out if the async state for vkey 0 provides any information and + * add it to the check. */ + for (i = 1; i < 256; i++) + { + BYTE state = GetAsyncKeyState(i) >> 8; + todo_wine_if( todo_state[i] ) + ok_(__FILE__, line)( (expect_state[i] & 0x80) == (state & 0x80), + "async got %s: %#x\n", debugstr_vk( i ), state ); + } +} + static void clear_keyboard_state( void ) { static BYTE empty_state[256] = {0}; @@ -713,6 +732,7 @@ static void check_send_input_keyboard_test_( const struct send_input_keyboard_te
ok_seq( test->expect ); check_keyboard_state( test->expect_state, test->todo_state ); + if (test->async) check_keyboard_async( test->expect_async, test->todo_async );
winetest_pop_context(); } @@ -1453,7 +1473,7 @@ static void test_SendInput_raw_key_messages( WORD vkey, WORD wch, HKL hkl ) }; struct send_input_keyboard_test raw_nolegacy[] = { - {.vkey = vkey, .expect = {RAW_KEY(1, RI_KEY_MAKE, vkey, WM_KEYDOWN), {0}}}, + {.vkey = vkey, .async = TRUE, .expect = {RAW_KEY(1, RI_KEY_MAKE, vkey, WM_KEYDOWN), {0}}}, {.vkey = vkey, .flags = KEYEVENTF_KEYUP, .expect = {RAW_KEY(2, RI_KEY_BREAK, vkey, WM_KEYUP), {0}}}, {0}, }; @@ -1467,7 +1487,8 @@ static void test_SendInput_raw_key_messages( WORD vkey, WORD wch, HKL hkl ) }; struct send_input_keyboard_test raw_vk_packet_nolegacy[] = { - {.vkey = VK_PACKET, .expect = {RAW_KEY(1, RI_KEY_MAKE, VK_PACKET, WM_KEYDOWN), {0}}}, + {.vkey = VK_PACKET, .async = TRUE, .expect_async = {[VK_PACKET] = 0x80}, + .expect = {RAW_KEY(1, RI_KEY_MAKE, VK_PACKET, WM_KEYDOWN), {0}}}, {.vkey = VK_PACKET, .flags = KEYEVENTF_KEYUP, .expect = {RAW_KEY(2, RI_KEY_BREAK, VK_PACKET, WM_KEYUP), {0}}}, {0}, }; @@ -1481,7 +1502,8 @@ static void test_SendInput_raw_key_messages( WORD vkey, WORD wch, HKL hkl ) }; struct send_input_keyboard_test raw_unicode_nolegacy[] = { - {.scan = 0x3c0, .flags = KEYEVENTF_UNICODE}, + {.scan = 0x3c0, .flags = KEYEVENTF_UNICODE, .async = TRUE, + .expect_async = {[VK_PACKET] = 0x80}, .todo_async = {[VK_PACKET] = TRUE}}, {.scan = 0x3c0, .flags = KEYEVENTF_KEYUP | KEYEVENTF_UNICODE}, {0}, }; @@ -1496,7 +1518,8 @@ static void test_SendInput_raw_key_messages( WORD vkey, WORD wch, HKL hkl ) }; struct send_input_keyboard_test raw_unicode_vkey_ctrl_nolegacy[] = { - {.scan = 0x3c0, .vkey = VK_CONTROL, .flags = KEYEVENTF_UNICODE}, + {.scan = 0x3c0, .vkey = VK_CONTROL, .flags = KEYEVENTF_UNICODE, .async = TRUE, + .expect_async = {[VK_CONTROL] = 0x80, [VK_LCONTROL] = 0x80}}, {.scan = 0x3c0, .vkey = VK_CONTROL, .flags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP}, {0}, }; @@ -1508,6 +1531,7 @@ static void test_SendInput_raw_key_messages( WORD vkey, WORD wch, HKL hkl ) HWND hwnd;
raw_legacy[0].expect_state[vkey] = 0x80; + raw_nolegacy[0].expect_async[vkey] = 0x80;
hwnd = CreateWindowW( L"static", NULL, WS_POPUP | WS_VISIBLE, 0, 0, 100, 100, NULL, NULL, NULL, NULL ); ok_ne( NULL, hwnd, HWND, "%p" );
From: Alexandros Frantzis alexandros.frantzis@collabora.com
--- dlls/user32/tests/input.c | 3 +-- server/queue.c | 9 ++++----- 2 files changed, 5 insertions(+), 7 deletions(-)
diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index 94db58e6796..9196e67c15b 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -1502,8 +1502,7 @@ static void test_SendInput_raw_key_messages( WORD vkey, WORD wch, HKL hkl ) }; struct send_input_keyboard_test raw_unicode_nolegacy[] = { - {.scan = 0x3c0, .flags = KEYEVENTF_UNICODE, .async = TRUE, - .expect_async = {[VK_PACKET] = 0x80}, .todo_async = {[VK_PACKET] = TRUE}}, + {.scan = 0x3c0, .flags = KEYEVENTF_UNICODE, .async = TRUE, .expect_async = {[VK_PACKET] = 0x80}}, {.scan = 0x3c0, .flags = KEYEVENTF_KEYUP | KEYEVENTF_UNICODE}, {0}, }; diff --git a/server/queue.c b/server/queue.c index 4d48da1d484..e881e40271d 100644 --- a/server/queue.c +++ b/server/queue.c @@ -2106,6 +2106,9 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c
switch (vkey) { + case 0: + if (unicode) vkey = hook_vkey = VK_PACKET; + break; case VK_MENU: case VK_LMENU: case VK_RMENU: @@ -2217,11 +2220,7 @@ static int queue_keyboard_message( struct desktop *desktop, user_handle_t win, c msg->msg = message_code; if (origin == IMO_INJECTED) msg_data->flags = LLKHF_INJECTED;
- if (unicode && !vkey) - { - vkey = hook_vkey = VK_PACKET; - } - else + if (!unicode || input->kbd.vkey) { if (input->kbd.flags & KEYEVENTF_EXTENDEDKEY) flags |= KF_EXTENDED; /* FIXME: set KF_DLGMODE and KF_MENUMODE when needed */
On Fri May 31 13:07:29 2024 +0000, Alexandros Frantzis wrote:
changed this line in [version 3 of the diff](/wine/wine/-/merge_requests/5754/diffs?diff_id=116018&start_sha=39c4662456baf85e9907bf878bc6796281dbb6bf#14b74bf2d7f44f52a31e4ee1baa51371f14df769_2193_2195)
Done in v3!