From 9faf7e358630cb8e8d63e4a534a9b5b9a56b7e00 Mon Sep 17 00:00:00 2001 From: Vitaliy Margolen Date: Tue, 1 Apr 2008 23:13:45 -0600 Subject: [PATCH] winex11drv: Distinguish left and right keys for shift, ctrl and alt. --- dlls/user32/tests/input.c | 436 +++++++++++++++++++++++++++++++----- dlls/winex11.drv/keyboard.c | 76 +++++-- server/queue.c | 15 +- 3 files changed, 435 insertions(+), 92 deletions(-) diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c index 5d56f7502fd..14f32b90a68 100644 --- a/dlls/user32/tests/input.c +++ b/dlls/user32/tests/input.c @@ -391,66 +391,266 @@ static void empty_message_queue(void) { struct transition_s { WORD wVk; BYTE before_state; - BOOL _todo_wine; +}; + +typedef enum { + sent=0x1, + posted=0x2, + parent=0x4, + wparam=0x8, + lparam=0x10, + defwinproc=0x20, + beginpaint=0x40, + optional=0x80, + hook=0x100, + winevent_hook=0x200 +} msg_flags_t; + +struct message { + UINT message; /* the WM_* code */ + msg_flags_t flags; /* message props */ + WPARAM wParam; /* expected value of wParam */ + LPARAM lParam; /* expected value of lParam */ }; struct sendinput_test_s { WORD wVk; DWORD dwFlags; + BOOL _todo_wine; struct transition_s expected_transitions[MAXKEYEVENTS+1]; - UINT expected_messages[MAXKEYMESSAGES+1]; + struct message expected_messages[MAXKEYMESSAGES+1]; } sendinput_test[] = { /* test ALT+F */ - {VK_LMENU, 0, {{VK_MENU, 0x00, 0}, {VK_LMENU, 0x00, 0}, {0}}, - {WM_SYSKEYDOWN, 0}}, - {'F', 0, {{'F', 0x00, 0}, {0}}, - {WM_SYSKEYDOWN, WM_SYSCHAR, WM_SYSCOMMAND, 0}}, - {'F', KEYEVENTF_KEYUP, {{'F', 0x80, 0}, {0}}, {WM_SYSKEYUP, 0}}, - {VK_LMENU, KEYEVENTF_KEYUP, {{VK_MENU, 0x80, 0}, {VK_LMENU, 0x80, 0}, {0}}, - {WM_KEYUP, 0}}, + {VK_LMENU, 0, 0, {{VK_MENU, 0x00}, {VK_LMENU, 0x00}, {0}}, + {{WM_SYSKEYDOWN, hook|wparam, VK_LMENU}, {WM_SYSKEYDOWN}, {0}}}, + {'F', 0, 0, {{'F', 0x00}, {0}}, + {{WM_SYSKEYDOWN, hook}, {WM_SYSKEYDOWN}, + {WM_SYSCHAR}, + {WM_SYSCOMMAND}, {0}}}, + {'F', KEYEVENTF_KEYUP, 0, {{'F', 0x80}, {0}}, + {{WM_SYSKEYUP, hook}, {WM_SYSKEYUP}, {0}}}, + {VK_LMENU, KEYEVENTF_KEYUP, 0, {{VK_MENU, 0x80}, {VK_LMENU, 0x80}, {0}}, + {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}}, /* test CTRL+O */ - {VK_LCONTROL, 0, {{VK_CONTROL, 0x00, 0}, {VK_LCONTROL, 0x00, 0}, {0}}, - {WM_KEYDOWN, 0}}, - {'O', 0, {{'O', 0x00, 0}, {0}}, {WM_KEYDOWN, WM_CHAR, 0}}, - {'O', KEYEVENTF_KEYUP, {{'O', 0x80, 0}, {0}}, {WM_KEYUP, 0}}, - {VK_LCONTROL, KEYEVENTF_KEYUP, - {{VK_CONTROL, 0x80, 0}, {VK_LCONTROL, 0x80, 0}, {0}}, {WM_KEYUP, 0}}, + {VK_LCONTROL, 0, 0, {{VK_CONTROL, 0x00}, {VK_LCONTROL, 0x00}, {0}}, + {{WM_KEYDOWN, hook}, {WM_KEYDOWN}, {0}}}, + {'O', 0, 0, {{'O', 0x00}, {0}}, + {{WM_KEYDOWN, hook}, {WM_KEYDOWN}, {WM_CHAR}, {0}}}, + {'O', KEYEVENTF_KEYUP, 0, {{'O', 0x80}, {0}}, + {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}}, + {VK_LCONTROL, KEYEVENTF_KEYUP, 0, {{VK_CONTROL, 0x80}, {VK_LCONTROL, 0x80}, {0}}, + {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}}, /* test ALT+CTRL+X */ - {VK_LMENU, 0, {{VK_MENU, 0x00, 0}, {VK_LMENU, 0x00, 0}, {0}}, - {WM_SYSKEYDOWN, 0}}, - {VK_LCONTROL, 0, {{VK_CONTROL, 0x00, 0}, {VK_LCONTROL, 0x00, 0}, {0}}, - {WM_KEYDOWN, 0}}, - {'X', 0, {{'X', 0x00, 0}, {0}}, {WM_KEYDOWN, 0}}, - {'X', KEYEVENTF_KEYUP, {{'X', 0x80, 0}, {0}}, {WM_KEYUP, 0}}, - {VK_LCONTROL, KEYEVENTF_KEYUP, - {{VK_CONTROL, 0x80, 0}, {VK_LCONTROL, 0x80, 0}, {0}}, - {WM_SYSKEYUP, 0}}, - {VK_LMENU, KEYEVENTF_KEYUP, {{VK_MENU, 0x80, 0}, {VK_LMENU, 0x80, 0}, {0}}, - {WM_KEYUP, 0}}, + {VK_LMENU, 0, 0, {{VK_MENU, 0x00}, {VK_LMENU, 0x00}, {0}}, + {{WM_SYSKEYDOWN, hook}, {WM_SYSKEYDOWN}, {0}}}, + {VK_LCONTROL, 0, 0, {{VK_CONTROL, 0x00}, {VK_LCONTROL, 0x00}, {0}}, + {{WM_KEYDOWN, hook}, {WM_KEYDOWN}, {0}}}, + {'X', 0, 0, {{'X', 0x00}, {0}}, + {{WM_KEYDOWN, hook}, {WM_KEYDOWN}, {0}}}, + {'X', KEYEVENTF_KEYUP, 0, {{'X', 0x80}, {0}}, + {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}}, + {VK_LCONTROL, KEYEVENTF_KEYUP, 0, {{VK_CONTROL, 0x80}, {VK_LCONTROL, 0x80}, {0}}, + {{WM_SYSKEYUP, hook}, {WM_SYSKEYUP}, {0}}}, + {VK_LMENU, KEYEVENTF_KEYUP, 0, {{VK_MENU, 0x80}, {VK_LMENU, 0x80}, {0}}, + {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}}, /* test SHIFT+A */ - {VK_LSHIFT, 0, - {{VK_SHIFT, 0x00, 0}, {VK_LSHIFT, 0x00, 0}, {0}}, {WM_KEYDOWN, 0}}, - {'A', 0, {{'A', 0x00, 0}, {0}}, {WM_KEYDOWN, WM_CHAR, 0}}, - {'A', KEYEVENTF_KEYUP, {{'A', 0x80, 0}, {0}}, {WM_KEYUP, 0}}, - {VK_LSHIFT, KEYEVENTF_KEYUP, - {{VK_SHIFT, 0x80, 0}, {VK_LSHIFT, 0x80, 0}, {0}}, {WM_KEYUP, 0}}, + {VK_LSHIFT, 0, 0, {{VK_SHIFT, 0x00}, {VK_LSHIFT, 0x00}, {0}}, + {{WM_KEYDOWN, hook}, {WM_KEYDOWN}, {0}}}, + {'A', 0, 0, {{'A', 0x00}, {0}}, + {{WM_KEYDOWN, hook}, {WM_KEYDOWN}, {WM_CHAR}, {0}}}, + {'A', KEYEVENTF_KEYUP, 0, {{'A', 0x80}, {0}}, + {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}}, + {VK_LSHIFT, KEYEVENTF_KEYUP, 0, {{VK_SHIFT, 0x80}, {VK_LSHIFT, 0x80}, {0}}, + {{WM_KEYUP, hook}, {WM_KEYUP}, {0}}}, + /* test L-SHIFT & R-SHIFT: */ + /* RSHIFT == LSHIFT */ + {VK_RSHIFT, 0, 0, + {{VK_SHIFT, 0x00}, {VK_LSHIFT, 0x00}, {0}}, + {{WM_KEYDOWN, hook|wparam, VK_RSHIFT}, + {WM_KEYDOWN}, {0}}}, + {VK_RSHIFT, KEYEVENTF_KEYUP, 0, + {{VK_SHIFT, 0x80}, {VK_LSHIFT, 0x80}, {0}}, + {{WM_KEYUP, hook, hook|wparam, VK_RSHIFT}, + {WM_KEYUP}, {0}}}, - {0, 0, {{0}}, {0}} /* end */ + /* LSHIFT | KEYEVENTF_EXTENDEDKEY == RSHIFT */ + {VK_LSHIFT, KEYEVENTF_EXTENDEDKEY, 0, + {{VK_SHIFT, 0x00}, {VK_RSHIFT, 0x00}, {0}}, + {{WM_KEYDOWN, hook|wparam|lparam, VK_LSHIFT, LLKHF_EXTENDED}, + {WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0}, {0}}}, + {VK_LSHIFT, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, 0, + {{VK_SHIFT, 0x80}, {VK_RSHIFT, 0x80}, {0}}, + {{WM_KEYUP, hook|wparam|lparam, VK_LSHIFT, LLKHF_UP|LLKHF_EXTENDED}, + {WM_KEYUP, wparam|lparam, VK_SHIFT, KF_UP}, {0}}}, + /* RSHIFT | KEYEVENTF_EXTENDEDKEY == RSHIFT */ + {VK_RSHIFT, KEYEVENTF_EXTENDEDKEY, 0, + {{VK_SHIFT, 0x00}, {VK_RSHIFT, 0x00}, {0}}, + {{WM_KEYDOWN, hook|wparam|lparam, VK_RSHIFT, LLKHF_EXTENDED}, + {WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0}, {0}}}, + {VK_RSHIFT, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, 0, + {{VK_SHIFT, 0x80}, {VK_RSHIFT, 0x80}, {0}}, + {{WM_KEYUP, hook|wparam|lparam, VK_RSHIFT, LLKHF_UP|LLKHF_EXTENDED}, + {WM_KEYUP, wparam|lparam, VK_SHIFT, KF_UP}, {0}}}, + /* SHIFT == LSHIFT */ + {VK_SHIFT, 0, 0, + {{VK_SHIFT, 0x00}, {VK_LSHIFT, 0x00}, {0}}, + {{WM_KEYDOWN, hook|wparam|lparam, VK_SHIFT, 0}, + {WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0}, {0}}}, + {VK_SHIFT, KEYEVENTF_KEYUP, 0, + {{VK_SHIFT, 0x80}, {VK_LSHIFT, 0x80}, {0}}, + {{WM_KEYUP, hook|wparam|lparam, VK_SHIFT, LLKHF_UP}, + {WM_KEYUP, wparam|lparam, VK_SHIFT, KF_UP}, {0}}}, + /* SHIFT | KEYEVENTF_EXTENDEDKEY == RSHIFT */ + {VK_SHIFT, KEYEVENTF_EXTENDEDKEY, 0, + {{VK_SHIFT, 0x00}, {VK_RSHIFT, 0x00}, {0}}, + {{WM_KEYDOWN, hook|wparam|lparam, VK_SHIFT, LLKHF_EXTENDED}, + {WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0}, {0}}}, + {VK_SHIFT, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, 0, + {{VK_SHIFT, 0x80}, {VK_RSHIFT, 0x80}, {0}}, + {{WM_KEYUP, hook|wparam|lparam, VK_SHIFT, LLKHF_UP|LLKHF_EXTENDED}, + {WM_KEYUP, wparam|lparam, VK_SHIFT, KF_UP}, {0}}}, + + /* test L-CONTROL & R-CONTROL: */ + /* RCONTROL == LCONTROL */ + {VK_RCONTROL, 0, 0, + {{VK_CONTROL, 0x00}, {VK_LCONTROL, 0x00}, {0}}, + {{WM_KEYDOWN, hook|wparam, VK_RCONTROL}, + {WM_KEYDOWN, wparam|lparam, VK_CONTROL, 0}, {0}}}, + {VK_RCONTROL, KEYEVENTF_KEYUP, 0, + {{VK_CONTROL, 0x80}, {VK_LCONTROL, 0x80}, {0}}, + {{WM_KEYUP, hook|wparam, VK_RCONTROL}, + {WM_KEYUP, wparam|lparam, VK_CONTROL, KF_UP}, {0}}}, + /* LCONTROL | KEYEVENTF_EXTENDEDKEY == RCONTROL */ + {VK_LCONTROL, KEYEVENTF_EXTENDEDKEY, 0, + {{VK_CONTROL, 0x00}, {VK_RCONTROL, 0x00}, {0}}, + {{WM_KEYDOWN, hook|wparam|lparam, VK_LCONTROL, LLKHF_EXTENDED}, + {WM_KEYDOWN, wparam|lparam, VK_CONTROL, KF_EXTENDED}, {0}}}, + {VK_LCONTROL, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, 0, + {{VK_CONTROL, 0x80}, {VK_RCONTROL, 0x80}, {0}}, + {{WM_KEYUP, hook|wparam|lparam, VK_LCONTROL, LLKHF_UP|LLKHF_EXTENDED}, + {WM_KEYUP, wparam|lparam, VK_CONTROL, KF_UP|KF_EXTENDED}, {0}}}, + /* RCONTROL | KEYEVENTF_EXTENDEDKEY == RCONTROL */ + {VK_RCONTROL, KEYEVENTF_EXTENDEDKEY, 0, + {{VK_CONTROL, 0x00}, {VK_RCONTROL, 0x00}, {0}}, + {{WM_KEYDOWN, hook|wparam|lparam, VK_RCONTROL, LLKHF_EXTENDED}, + {WM_KEYDOWN, wparam|lparam, VK_CONTROL, KF_EXTENDED}, {0}}}, + {VK_RCONTROL, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, 0, + {{VK_CONTROL, 0x80}, {VK_RCONTROL, 0x80}, {0}}, + {{WM_KEYUP, hook|wparam|lparam, VK_RCONTROL, LLKHF_UP|LLKHF_EXTENDED}, + {WM_KEYUP, wparam|lparam, VK_CONTROL, KF_UP|KF_EXTENDED}, {0}}}, + /* CONTROL == LCONTROL */ + {VK_CONTROL, 0, 0, + {{VK_CONTROL, 0x00}, {VK_LCONTROL, 0x00}, {0}}, + {{WM_KEYDOWN, hook|wparam, VK_CONTROL}, + {WM_KEYDOWN, wparam|lparam, VK_CONTROL, 0}, {0}}}, + {VK_CONTROL, KEYEVENTF_KEYUP, 0, + {{VK_CONTROL, 0x80}, {VK_LCONTROL, 0x80}, {0}}, + {{WM_KEYUP, hook|wparam, VK_CONTROL}, + {WM_KEYUP, wparam|lparam, VK_CONTROL, KF_UP}, {0}}}, + /* CONTROL | KEYEVENTF_EXTENDEDKEY == RCONTROL */ + {VK_CONTROL, KEYEVENTF_EXTENDEDKEY, 0, + {{VK_CONTROL, 0x00}, {VK_RCONTROL, 0x00}, {0}}, + {{WM_KEYDOWN, hook|wparam|lparam, VK_CONTROL, LLKHF_EXTENDED}, + {WM_KEYDOWN, wparam|lparam, VK_CONTROL, KF_EXTENDED}, {0}}}, + {VK_CONTROL, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, 0, + {{VK_CONTROL, 0x80}, {VK_RCONTROL, 0x80}, {0}}, + {{WM_KEYUP, hook|wparam|lparam, VK_CONTROL, LLKHF_UP|LLKHF_EXTENDED}, + {WM_KEYUP, wparam|lparam, VK_CONTROL, KF_UP|KF_EXTENDED}, {0}}}, + + /* test L-MENU & R-MENU: */ + /* RMENU == LMENU */ + {VK_RMENU, 0, 0, + {{VK_MENU, 0x00}, {VK_LMENU, 0x00}, {0}}, + {{WM_SYSKEYDOWN, hook|wparam, VK_RMENU}, + {WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0}, {0}}}, + {VK_RMENU, KEYEVENTF_KEYUP, 1, + {{VK_MENU, 0x80}, {VK_LMENU, 0x80}, {0}}, + {{WM_KEYUP, hook|wparam, VK_RMENU}, + {WM_SYSKEYUP, wparam|lparam, VK_MENU, KF_UP}, + {WM_SYSCOMMAND}, {0}}}, + /* LMENU | KEYEVENTF_EXTENDEDKEY == RMENU */ + {VK_LMENU, KEYEVENTF_EXTENDEDKEY, 0, + {{VK_MENU, 0x00}, {VK_RMENU, 0x00}, {0}}, + {{WM_SYSKEYDOWN, hook|wparam|lparam, VK_LMENU, LLKHF_EXTENDED}, + {WM_SYSKEYDOWN, wparam|lparam, VK_MENU, KF_EXTENDED}, {0}}}, + {VK_LMENU, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, 1, + {{VK_MENU, 0x80}, {VK_RMENU, 0x80}, {0}}, + {{WM_KEYUP, hook|wparam|lparam, VK_LMENU, LLKHF_UP|LLKHF_EXTENDED}, + {WM_SYSKEYUP, wparam|lparam, VK_MENU, KF_UP|KF_EXTENDED}, + {WM_SYSCOMMAND}, {0}}}, + /* RMENU | KEYEVENTF_EXTENDEDKEY == RMENU */ + {VK_RMENU, KEYEVENTF_EXTENDEDKEY, 0, + {{VK_MENU, 0x00}, {VK_RMENU, 0x00}, {0}}, + {{WM_SYSKEYDOWN, hook|wparam|lparam, VK_RMENU, LLKHF_EXTENDED}, + {WM_SYSKEYDOWN, wparam|lparam, VK_MENU, KF_EXTENDED}, {0}}}, + {VK_RMENU, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, 1, + {{VK_MENU, 0x80}, {VK_RMENU, 0x80}, {0}}, + {{WM_KEYUP, hook|wparam|lparam, VK_RMENU, LLKHF_UP|LLKHF_EXTENDED}, + {WM_SYSKEYUP, wparam|lparam, VK_MENU, KF_UP|KF_EXTENDED}, + {WM_SYSCOMMAND}, {0}}}, + /* MENU == LMENU */ + {VK_MENU, 0, 0, + {{VK_MENU, 0x00}, {VK_LMENU, 0x00}, {0}}, + {{WM_SYSKEYDOWN, hook|wparam, VK_MENU}, + {WM_SYSKEYDOWN, wparam|lparam, VK_MENU, 0}, {0}}}, + {VK_MENU, KEYEVENTF_KEYUP, 1, + {{VK_MENU, 0x80}, {VK_LMENU, 0x80}, {0}}, + {{WM_KEYUP, hook|wparam, VK_MENU}, + {WM_SYSKEYUP, wparam|lparam, VK_MENU, KF_UP}, + {WM_SYSCOMMAND}, {0}}}, + /* MENU | KEYEVENTF_EXTENDEDKEY == RMENU */ + {VK_MENU, KEYEVENTF_EXTENDEDKEY, 0, + {{VK_MENU, 0x00}, {VK_RMENU, 0x00}, {0}}, + {{WM_SYSKEYDOWN, hook|wparam|lparam, VK_MENU, LLKHF_EXTENDED}, + {WM_SYSKEYDOWN, wparam|lparam, VK_MENU, KF_EXTENDED}, {0}}}, + {VK_MENU, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, 1, + {{VK_MENU, 0x80}, {VK_RMENU, 0x80}, {0}}, + {{WM_KEYUP, hook|wparam|lparam, VK_MENU, LLKHF_UP|LLKHF_EXTENDED}, + {WM_SYSKEYUP, wparam|lparam, VK_MENU, KF_UP|KF_EXTENDED}, + {WM_SYSCOMMAND}, {0}}}, + + /* test LSHIFT & RSHIFT */ + {VK_LSHIFT, 0, 0, + {{VK_SHIFT, 0x00}, {VK_LSHIFT, 0x00}, {0}}, + {{WM_KEYDOWN, hook|wparam|lparam, VK_LSHIFT, 0}, + {WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0}, {0}}}, + {VK_RSHIFT, KEYEVENTF_EXTENDEDKEY, 0, + {{VK_RSHIFT, 0x00}, {0}}, + {{WM_KEYDOWN, hook|wparam|lparam, VK_RSHIFT, LLKHF_EXTENDED}, + {WM_KEYDOWN, wparam|lparam, VK_SHIFT, 0}, {0}}}, + {VK_RSHIFT, KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY, 0, + {{VK_RSHIFT, 0x80}, {0}}, + {{WM_KEYUP, hook|wparam|lparam, VK_RSHIFT, LLKHF_UP|LLKHF_EXTENDED}, + {WM_KEYUP, optional}, {0}}}, + {VK_LSHIFT, KEYEVENTF_KEYUP, 0, + {{VK_SHIFT, 0x80}, {VK_LSHIFT, 0x80}, {0}}, + {{WM_KEYUP, hook|wparam, VK_LSHIFT}, + {WM_KEYUP, wparam|lparam, VK_SHIFT, KF_UP}, {0}}}, + + {0, 0, 0, {{0}}, {{0}}} /* end */ }; -static struct sendinput_test_s *pTest = sendinput_test; -static UINT *pMsg = sendinput_test[0].expected_messages; +static struct message sent_messages[MAXKEYMESSAGES]; +static UINT sent_messages_cnt; /* Verify that only specified key state transitions occur */ -static void compare_and_check(int id, BYTE *ks1, BYTE *ks2, struct transition_s *t) { - int i; +static void compare_and_check(int id, BYTE *ks1, BYTE *ks2, struct sendinput_test_s *test) +{ + int i, failcount = 0; + struct transition_s *t = test->expected_transitions; + UINT actual_cnt = 0; + const struct message *expected = test->expected_messages; + while (t->wVk) { int matched = ((ks1[t->wVk]&0x80) == (t->before_state&0x80) && (ks2[t->wVk]&0x80) == (~t->before_state&0x80)); - if (t->_todo_wine) { + + if (!matched && test->_todo_wine) + { + failcount++; todo_wine { ok(matched, "%02d: %02x from %02x -> %02x " "instead of %02x -> %02x\n", id, t->wVk, @@ -467,25 +667,150 @@ static void compare_and_check(int id, BYTE *ks1, BYTE *ks2, struct transition_s t++; } for (i = 0; i < 256; i++) - ok(ks2[i] == ks1[i], "%02d: %02x from %02x -> %02x unexpected\n", - id, i, ks1[i], ks2[i]); + if (ks2[i] != ks1[i] && test->_todo_wine) + { + failcount++; + todo_wine + ok(FALSE, "%02d: %02x from %02x -> %02x unexpected\n", id, i, ks1[i], ks2[i]); + } + else + ok(ks2[i] == ks1[i], "%02d: %02x from %02x -> %02x unexpected\n", + id, i, ks1[i], ks2[i]); + + while (expected->message && actual_cnt < sent_messages_cnt) + { + const struct message *actual = &sent_messages[actual_cnt]; + + if (expected->message == actual->message) + { + ok((expected->flags & hook) == (actual->flags & hook), + "%x/%x: the msg 0x%04x should have been sent by a hook\n", + test->wVk, test->dwFlags, expected->message); + + if (expected->flags & wparam) + { + if (expected->wParam != actual->wParam && test->_todo_wine) + { + failcount++; + todo_wine + ok(FALSE, "%x/%x: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n", + test->wVk, test->dwFlags, expected->message, expected->wParam, actual->wParam); + } + else + ok(expected->wParam == actual->wParam, + "%x/%x: in msg 0x%04x expecting wParam 0x%lx got 0x%lx\n", + test->wVk, test->dwFlags, expected->message, expected->wParam, actual->wParam); + } + if (expected->flags & lparam) + { + if (expected->lParam != actual->lParam && test->_todo_wine) + { + failcount++; + todo_wine + ok(FALSE, "%x/%x: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n", + test->wVk, test->dwFlags, expected->message, expected->lParam, actual->lParam); + } + else + ok(expected->lParam == actual->lParam, + "%x/%x: in msg 0x%04x expecting lParam 0x%lx got 0x%lx\n", + test->wVk, test->dwFlags, expected->message, expected->lParam, actual->lParam); + } + } + else if (expected->flags & optional) + { + expected++; + continue; + } + else if (test->_todo_wine) + { + failcount++; + todo_wine + ok(FALSE, + "%x/%x: the msg 0x%04x was expected, but got msg 0x%04x instead\n", + test->wVk, test->dwFlags, expected->message, actual->message); + } + else + ok(FALSE, + "%x/%x: the msg 0x%04x was expected, but got msg 0x%04x instead\n", + test->wVk, test->dwFlags, expected->message, actual->message); + + actual_cnt++; + expected++; + } + /* skip all optional trailing messages */ + while (expected->message && (expected->flags & optional)) + expected++; + + + if (expected->message || actual_cnt < sent_messages_cnt) + { + if (test->_todo_wine) + { + failcount++; + todo_wine + ok(FALSE, "%x/%x: the msg sequence is not complete: expected %04x - actual %04x\n", + test->wVk, test->dwFlags, expected->message, sent_messages[actual_cnt].message); + } + else + ok(FALSE, "%x/%x: the msg sequence is not complete: expected %04x - actual %04x\n", + test->wVk, test->dwFlags, expected->message, sent_messages[actual_cnt].message); + } + + if( test->_todo_wine && !failcount) /* succeeded yet marked todo */ + todo_wine + ok(TRUE, "%x/%x: marked \"todo_wine\" but succeeds\n", test->wVk, test->dwFlags); + + sent_messages_cnt = 0; } /* WndProc2 checks that we get at least the messages specified */ static LRESULT CALLBACK WndProc2(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { - if (pTest->wVk != 0) { /* not end */ - while(pTest->wVk != 0 && *pMsg == 0) { - pTest++; - pMsg = pTest->expected_messages; - } - if (Msg == *pMsg) - pMsg++; + if (winetest_debug > 1) trace("MSG: %8x W:%8lx L:%8lx\n", Msg, wParam, lParam); + + if (Msg != WM_PAINT && + Msg != WM_NCPAINT && + Msg != WM_SYNCPAINT && + Msg != WM_ERASEBKGND && + Msg != WM_NCHITTEST && + Msg != WM_GETTEXT && + Msg != WM_GETICON && + Msg != WM_DEVICECHANGE) + { + sent_messages[sent_messages_cnt].message = Msg; + sent_messages[sent_messages_cnt].flags = 0; + sent_messages[sent_messages_cnt].wParam = wParam; + sent_messages[sent_messages_cnt++].lParam = HIWORD(lParam) & (KF_UP|KF_EXTENDED); } return DefWindowProc(hWnd, Msg, wParam, lParam); } +static LRESULT CALLBACK hook_proc(int code, WPARAM wparam, LPARAM lparam) +{ + KBDLLHOOKSTRUCT *hook_info = (KBDLLHOOKSTRUCT *)lparam; + + if (code == HC_ACTION) + { + sent_messages[sent_messages_cnt].message = wparam; + sent_messages[sent_messages_cnt].flags = hook; + sent_messages[sent_messages_cnt].wParam = hook_info->vkCode; + sent_messages[sent_messages_cnt++].lParam = hook_info->flags & (LLKHF_UP|LLKHF_EXTENDED); + +if(0) /* For some reason not stable on Wine */ +{ + if (wparam == WM_KEYDOWN || wparam == WM_SYSKEYDOWN) + ok(!(GetAsyncKeyState(hook_info->vkCode) & 0x8000), "key %x should be up\n", hook_info->vkCode); + else if (wparam == WM_KEYUP || wparam == WM_SYSKEYUP) + ok(GetAsyncKeyState(hook_info->vkCode) & 0x8000, "key %x should be down\n", hook_info->vkCode); +} + + if (winetest_debug > 1) + trace("Hook: w=%lx vk:%8x sc:%8x fl:%8x %lx\n", wparam, + hook_info->vkCode, hook_info->scanCode, hook_info->flags, hook_info->dwExtraInfo); + } + return CallNextHookEx( 0, code, wparam, lparam ); +} static void test_Input_blackbox(void) { TEST_INPUT i; @@ -493,6 +818,7 @@ static void test_Input_blackbox(void) BYTE ks1[256], ks2[256]; LONG_PTR prevWndProc; HWND window; + HHOOK hook; if (!pSendInput) { @@ -505,6 +831,8 @@ static void test_Input_blackbox(void) NULL, NULL); ok(window != NULL, "error: %d\n", (int) GetLastError()); + hook = SetWindowsHookExA(WH_KEYBOARD_LL, hook_proc, GetModuleHandleA( NULL ), 0); + /* must process all initial messages, otherwise X11DRV_KeymapNotify unsets * key state set by SendInput(). */ empty_message_queue(); @@ -514,30 +842,24 @@ static void test_Input_blackbox(void) "error: %d\n", (int) GetLastError()); i.type = INPUT_KEYBOARD; - i.u.ki.wScan = 0; i.u.ki.time = 0; i.u.ki.dwExtraInfo = 0; for (ii = 0; ii < sizeof(sendinput_test)/sizeof(struct sendinput_test_s)-1; ii++) { GetKeyboardState(ks1); + i.u.ki.wScan = ii+1 /* useful for debugging */; i.u.ki.dwFlags = sendinput_test[ii].dwFlags; i.u.ki.wVk = sendinput_test[ii].wVk; pSendInput(1, (INPUT*)&i, sizeof(TEST_INPUT)); empty_message_queue(); GetKeyboardState(ks2); - compare_and_check(ii, ks1, ks2, - sendinput_test[ii].expected_transitions); + compare_and_check(ii, ks1, ks2, &sendinput_test[ii]); } - /* *pMsg should be 0 and (++pTest)->wVk should be 0 */ - if (pTest->wVk && *pMsg == 0) pTest++; - while(pTest->wVk && pTest->expected_messages[0] == 0) { - ++pTest; - } - ok(*pMsg == 0 && pTest->wVk == 0, - "not enough messages found; looking for %x\n", *pMsg); + empty_message_queue(); DestroyWindow(window); + UnhookWindowsHookEx(hook); } static void test_keynames(void) diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c index 33640db8efc..8bb57172392 100644 --- a/dlls/winex11.drv/keyboard.c +++ b/dlls/winex11.drv/keyboard.c @@ -1021,9 +1021,9 @@ static const WORD nonchar_key_vkey[256] = 0, 0, 0, 0, 0, 0, 0, 0, /* FFD0 */ 0, 0, 0, 0, 0, 0, 0, 0, /* FFD8 */ /* modifier keys */ - 0, VK_SHIFT, VK_SHIFT, VK_CONTROL, /* FFE0 */ - VK_CONTROL, VK_CAPITAL, 0, VK_MENU, - VK_MENU, VK_MENU, VK_MENU, 0, 0, 0, 0, 0, /* FFE8 */ + 0, VK_LSHIFT, VK_RSHIFT, VK_LCONTROL, /* FFE0 */ + VK_RCONTROL, VK_CAPITAL, 0, VK_MENU, + VK_MENU, VK_LMENU, VK_RMENU, 0, 0, 0, 0, 0, /* FFE8 */ 0, 0, 0, 0, 0, 0, 0, 0, /* FFF0 */ 0, 0, 0, 0, 0, 0, 0, VK_DELETE /* FFF8 */ }; @@ -1067,7 +1067,7 @@ static const WORD nonchar_key_scan[256] = 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFD8 */ /* modifier keys */ - 0x00, 0x2A, 0x36, 0x1D, 0x11D, 0x3A, 0x00, 0x38, /* FFE0 */ + 0x00, 0x2A, 0x136, 0x1D, 0x11D, 0x3A, 0x00, 0x38, /* FFE0 */ 0x138, 0x38, 0x138, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFE8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* FFF0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x153 /* FFF8 */ @@ -1151,20 +1151,10 @@ void X11DRV_send_keyboard_input( WORD wVk, WORD wScan, DWORD dwFlags, DWORD time UINT message; KEYLP keylp; KBDLLHOOKSTRUCT hook; - WORD wVkStripped; + WORD wVkStripped, wVkL, wVkR, vk_hook = wVk; wVk = LOBYTE(wVk); - /* strip left/right for menu, control, shift */ - if (wVk == VK_LMENU || wVk == VK_RMENU) - wVkStripped = VK_MENU; - else if (wVk == VK_LCONTROL || wVk == VK_RCONTROL) - wVkStripped = VK_CONTROL; - else if (wVk == VK_LSHIFT || wVk == VK_RSHIFT) - wVkStripped = VK_SHIFT; - else - wVkStripped = wVk; - keylp.lp2 = 0; keylp.lp1.count = 1; keylp.lp1.code = wScan; @@ -1174,6 +1164,33 @@ void X11DRV_send_keyboard_input( WORD wVk, WORD wScan, DWORD dwFlags, DWORD time /* it's '1' under windows, when a dialog box appears * and you press one of the underlined keys - DF*/ + /* strip left/right for menu, control, shift */ + switch (wVk) + { + case VK_MENU: case VK_LMENU: case VK_RMENU: + wVk = keylp.lp1.extended ? VK_RMENU : VK_LMENU; + wVkStripped = VK_MENU; + wVkL = VK_LMENU; + wVkR = VK_RMENU; + break; + + case VK_CONTROL: case VK_LCONTROL: case VK_RCONTROL: + wVk = keylp.lp1.extended ? VK_RCONTROL : VK_LCONTROL; + wVkStripped = VK_CONTROL; + wVkL = VK_LCONTROL; + wVkR = VK_RCONTROL; + break; + + case VK_SHIFT: case VK_LSHIFT: case VK_RSHIFT: + wVk = keylp.lp1.extended ? VK_RSHIFT : VK_LSHIFT; + wVkStripped = VK_SHIFT; + wVkL = VK_LSHIFT; + wVkR = VK_RSHIFT; + break; + default: + wVkStripped = wVkL = wVkR = wVk; + } + /* note that there is a test for all this */ if (dwFlags & KEYEVENTF_KEYUP ) { @@ -1187,8 +1204,6 @@ void X11DRV_send_keyboard_input( WORD wVk, WORD wScan, DWORD dwFlags, DWORD time message = WM_SYSKEYUP; TrackSysKey = 0; } - key_state_table[wVk] &= ~0x80; - key_state_table[wVkStripped] &= ~0x80; keylp.lp1.previous = 1; keylp.lp1.transition = 1; } @@ -1196,30 +1211,43 @@ void X11DRV_send_keyboard_input( WORD wVk, WORD wScan, DWORD dwFlags, DWORD time { keylp.lp1.previous = (key_state_table[wVk] & 0x80) != 0; keylp.lp1.transition = 0; - if (!(key_state_table[wVk] & 0x80)) key_state_table[wVk] ^= 0x01; - key_state_table[wVk] |= 0xc0; - key_state_table[wVkStripped] |= 0xc0; message = WM_KEYDOWN; - if ((key_state_table[VK_MENU] & 0x80) && !(key_state_table[VK_CONTROL] & 0x80)) + if ((key_state_table[VK_MENU] & 0x80 || wVkStripped == VK_MENU) && + !(key_state_table[VK_CONTROL] & 0x80 || wVkStripped == VK_CONTROL)) { message = WM_SYSKEYDOWN; TrackSysKey = wVkStripped; } } - keylp.lp1.context = (key_state_table[VK_MENU] & 0x80) != 0; /* 1 if alt */ - TRACE_(key)(" wParam=%04x, lParam=%08lx, InputKeyState=%x\n", wVk, keylp.lp2, key_state_table[wVk] ); - hook.vkCode = wVk; + /* Hook gets whatever key was sent. */ + hook.vkCode = vk_hook; hook.scanCode = wScan; hook.flags = (keylp.lp2 >> 24) | injected_flags; hook.time = time; hook.dwExtraInfo = dwExtraInfo; if (HOOK_CallHooks( WH_KEYBOARD_LL, HC_ACTION, message, (LPARAM)&hook, TRUE )) return; + if (dwFlags & KEYEVENTF_KEYUP ) + { + key_state_table[wVk] &= ~0x80; + key_state_table[wVkStripped] = key_state_table[wVkL] | key_state_table[wVkR]; + } + else + { + if (!(key_state_table[wVk] & 0x80)) key_state_table[wVk] ^= 0x01; + key_state_table[wVk] |= 0xc0; + key_state_table[wVkStripped] = key_state_table[wVkL] | key_state_table[wVkR]; + } + + keylp.lp1.context = (key_state_table[VK_MENU] & 0x80) != 0; /* 1 if alt */ + + if (wVkStripped == VK_SHIFT) keylp.lp1.extended = 0; + SERVER_START_REQ( send_hardware_message ) { req->id = (injected_flags & LLKHF_INJECTED) ? 0 : GetCurrentThreadId(); diff --git a/server/queue.c b/server/queue.c index a32bd7e250f..d90c36bf757 100644 --- a/server/queue.c +++ b/server/queue.c @@ -1122,7 +1122,7 @@ static void set_input_key_state( struct thread_input *input, unsigned char key, static void update_input_key_state( struct thread_input *input, const struct message *msg ) { unsigned char key; - int down = 0, extended; + int down = 0; switch (msg->msg) { @@ -1158,29 +1158,22 @@ static void update_input_key_state( struct thread_input *input, const struct mes case WM_KEYUP: case WM_SYSKEYUP: key = (unsigned char)msg->wparam; - extended = ((msg->lparam >> 16) & KF_EXTENDED) != 0; set_input_key_state( input, key, down ); switch(key) { - case VK_SHIFT: - set_input_key_state( input, extended ? VK_RSHIFT : VK_LSHIFT, down ); - break; - case VK_CONTROL: - set_input_key_state( input, extended ? VK_RCONTROL : VK_LCONTROL, down ); - break; - case VK_MENU: - set_input_key_state( input, extended ? VK_RMENU : VK_LMENU, down ); - break; case VK_LCONTROL: case VK_RCONTROL: + down = (input->keystate[VK_LCONTROL] | input->keystate[VK_RCONTROL]) & 0x80; set_input_key_state( input, VK_CONTROL, down ); break; case VK_LMENU: case VK_RMENU: + down = (input->keystate[VK_LMENU] | input->keystate[VK_RMENU]) & 0x80; set_input_key_state( input, VK_MENU, down ); break; case VK_LSHIFT: case VK_RSHIFT: + down = (input->keystate[VK_LSHIFT] | input->keystate[VK_RSHIFT]) & 0x80; set_input_key_state( input, VK_SHIFT, down ); break; }