From b8b0b841a0e7cfcecaf0b6a5aa67e1b4499374d9 Mon Sep 17 00:00:00 2001 From: Oliver Schmidt Date: Mon, 5 Sep 2011 13:32:01 +0100 Subject: [PATCH] hw/xwin: Fix AltGr key sometimes firing an additional Ctrl-L key I also had problems with the AltGr key. These could reliably be reproduced by holding the AltGr for some seconds (causing Windows generating auto repeat events) I discovered that the mechanism in winkeybd.c function winIsFakeCtrl_L had a problem if PeekMessage cannot obtain the next Alt_R message because it is not there yet. I prepared a patch that remembers the last Ctrl_L event and reacts on a later Alt_R. It was also necessary to alter the order in winWindowProc() in winwndproc.c: the invocation of winIsFakeCtrl_L had to be done before discarding auto-repeated key presses, as winIsFakeCtrl_L() now has an internal state which must be updated by all key events. Reviewed-by: Jon TURNEY Reviewed-by: Colin Harrison --- hw/xwin/winkeybd.c | 97 ++++++++++++++++++++++++++------------------ hw/xwin/winwndproc.c | 8 ++-- 2 files changed, 61 insertions(+), 44 deletions(-) diff --git a/hw/xwin/winkeybd.c b/hw/xwin/winkeybd.c index a3112fffe..0496c40ab 100644 --- a/hw/xwin/winkeybd.c +++ b/hw/xwin/winkeybd.c @@ -328,8 +328,12 @@ winIsFakeCtrl_L (UINT message, WPARAM wParam, LPARAM lParam) LONG lTime; Bool fReturn; + static Bool lastWasControlL = FALSE; + static UINT lastMessage; + static LONG lastTime; + /* - * Fake Ctrl_L presses will be followed by an Alt_R keypress + * Fake Ctrl_L presses will be followed by an Alt_R press * with the same timestamp as the Ctrl_L press. */ if ((message == WM_KEYDOWN || message == WM_SYSKEYDOWN) @@ -341,34 +345,31 @@ winIsFakeCtrl_L (UINT message, WPARAM wParam, LPARAM lParam) /* Get time of current message */ lTime = GetMessageTime (); - /* Look for fake Ctrl_L preceeding an Alt_R press. */ + /* Look for next press message */ fReturn = PeekMessage (&msgNext, NULL, WM_KEYDOWN, WM_SYSKEYDOWN, PM_NOREMOVE); - /* - * Try again if the first call fails. - * NOTE: This usually happens when TweakUI is enabled. - */ - if (!fReturn) - { - /* Voodoo to make sure that the Alt_R message has posted */ - Sleep (0); - - /* Look for fake Ctrl_L preceeding an Alt_R press. */ - fReturn = PeekMessage (&msgNext, NULL, - WM_KEYDOWN, WM_SYSKEYDOWN, - PM_NOREMOVE); - } - if (msgNext.message != WM_KEYDOWN && msgNext.message != WM_SYSKEYDOWN) + if (fReturn && msgNext.message != WM_KEYDOWN && msgNext.message != WM_SYSKEYDOWN) fReturn = 0; + if (!fReturn) + { + lastWasControlL = TRUE; + lastMessage = message; + lastTime = lTime; + } + else + { + lastWasControlL = FALSE; + } + /* Is next press an Alt_R with the same timestamp? */ if (fReturn && msgNext.wParam == VK_MENU && msgNext.time == lTime && (HIWORD (msgNext.lParam) & KF_EXTENDED)) { - /* + /* * Next key press is Alt_R with same timestamp as current * Ctrl_L message. Therefore, this Ctrl_L press is a fake * event, so discard it. @@ -376,12 +377,35 @@ winIsFakeCtrl_L (UINT message, WPARAM wParam, LPARAM lParam) return TRUE; } } + /* + * Sometimes, the Alt_R press message is not yet posted when the + * fake Ctrl_L press message arrives (even though it has the + * same timestamp), so check for an Alt_R press message that has + * arrived since the last Ctrl_L message. + */ + else if ((message == WM_KEYDOWN || message == WM_SYSKEYDOWN) + && wParam == VK_MENU + && (HIWORD (lParam) & KF_EXTENDED)) + { + /* Got a Alt_R press */ - /* + if (lastWasControlL) + { + lTime = GetMessageTime (); + + if (lastTime == lTime) + { + /* Undo the fake Ctrl_L press by sending a fake Ctrl_L release */ + winSendKeyEvent (KEY_LCtrl, FALSE); + } + lastWasControlL = FALSE; + } + } + /* * Fake Ctrl_L releases will be followed by an Alt_R release * with the same timestamp as the Ctrl_L release. */ - if ((message == WM_KEYUP || message == WM_SYSKEYUP) + else if ((message == WM_KEYUP || message == WM_SYSKEYUP) && wParam == VK_CONTROL && (HIWORD (lParam) & KF_EXTENDED) == 0) { @@ -390,29 +414,16 @@ winIsFakeCtrl_L (UINT message, WPARAM wParam, LPARAM lParam) /* Get time of current message */ lTime = GetMessageTime (); - /* Look for fake Ctrl_L release preceeding an Alt_R release. */ + /* Look for next release message */ fReturn = PeekMessage (&msgNext, NULL, - WM_KEYUP, WM_SYSKEYUP, + WM_KEYUP, WM_SYSKEYUP, PM_NOREMOVE); - /* - * Try again if the first call fails. - * NOTE: This usually happens when TweakUI is enabled. - */ - if (!fReturn) - { - /* Voodoo to make sure that the Alt_R message has posted */ - Sleep (0); - - /* Look for fake Ctrl_L release preceeding an Alt_R release. */ - fReturn = PeekMessage (&msgNext, NULL, - WM_KEYUP, WM_SYSKEYUP, - PM_NOREMOVE); - } - - if (msgNext.message != WM_KEYUP && msgNext.message != WM_SYSKEYUP) + if (fReturn && msgNext.message != WM_KEYUP && msgNext.message != WM_SYSKEYUP) fReturn = 0; - + + lastWasControlL = FALSE; + /* Is next press an Alt_R with the same timestamp? */ if (fReturn && (msgNext.message == WM_KEYUP @@ -429,7 +440,13 @@ winIsFakeCtrl_L (UINT message, WPARAM wParam, LPARAM lParam) return TRUE; } } - + else + { + /* On any other press or release message, we don't have a + potentially fake Ctrl_L to worry about anymore... */ + lastWasControlL = FALSE; + } + /* Not a fake control left press/release */ return FALSE; } diff --git a/hw/xwin/winwndproc.c b/hw/xwin/winwndproc.c index a89857a14..ae284b7ad 100644 --- a/hw/xwin/winwndproc.c +++ b/hw/xwin/winwndproc.c @@ -1060,6 +1060,10 @@ winWindowProc (HWND hwnd, UINT message, if ((wParam == VK_LWIN || wParam == VK_RWIN) && !g_fKeyboardHookLL) break; + /* Discard fake Ctrl_L events that precede AltGR on non-US keyboards */ + if (winIsFakeCtrl_L (message, wParam, lParam)) + return 0; + /* * Discard presses generated from Windows auto-repeat */ @@ -1080,10 +1084,6 @@ winWindowProc (HWND hwnd, UINT message, } } - /* Discard fake Ctrl_L presses that precede AltGR on non-US keyboards */ - if (winIsFakeCtrl_L (message, wParam, lParam)) - return 0; - /* Translate Windows key code to X scan code */ winTranslateKey (wParam, lParam, &iScanCode);