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 <jon.turney@dronecode.org.uk>
Reviewed-by: Colin Harrison <colin.harrison@virgin.net>
This commit is contained in:
Oliver Schmidt 2011-09-05 13:32:01 +01:00 committed by Jon TURNEY
parent 3d3114d55a
commit b8b0b841a0
2 changed files with 61 additions and 44 deletions

View File

@ -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,28 +345,25 @@ 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
@ -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,
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,6 +440,12 @@ 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;

View File

@ -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);