From 72f6bd8d51911f8a2a0dadc7fa10509fa86970a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Luis=20Boya=20Garc=C3=ADa?= Date: Wed, 16 Oct 2013 17:34:52 +0200 Subject: Fix virtual key mapping on MS Windows In order to map MS Windows virtual keys to Qt keys without messing with dead keys now I use the built-in keyMap structure of QWindowsKeyMapper and assert every cell in the keymap is properly updated. In order to guarantee this even when the user changes the keyboard layout, WndProc now manages the WM_INPUTLANGCHANGE message, which is handled by QWindowsKeyMapper, resetting the layout structure. I don't fully understand yet some things about QWindowsKeyMapper, i.e. how QWindowsKeyMapper::updatePossibleKeyCodes workarounds the dead key issue with ToAscii; but it seems to work fine in all the tests I've done. Any further testing is highly appreciated, though. [ChangeLog][[QtGui][Platform Specific Changes][Windows] Fixed virtual key mapping on Windows. Task-number: QTBUG-33409 Task-number: QTBUG-8764 Task-number: QTBUG-10032 Change-Id: I4f7709a90906b03f4504deea1ff5c361e9f94b3f (cherry picked from commit f0d014a16b5c9b55245834459c46ea34d15d14be) Reviewed-by: Friedemann Kleint --- src/corelib/kernel/qcoreapplication_win.cpp | 5 ++++ src/gui/kernel/qkeymapper_win.cpp | 37 ++++++++++------------------- 2 files changed, 17 insertions(+), 25 deletions(-) diff --git a/src/corelib/kernel/qcoreapplication_win.cpp b/src/corelib/kernel/qcoreapplication_win.cpp index 025690b..983d1f5 100644 --- a/src/corelib/kernel/qcoreapplication_win.cpp +++ b/src/corelib/kernel/qcoreapplication_win.cpp @@ -875,6 +875,11 @@ QString decodeMSG(const MSG& msg) } break; #endif +#ifdef WM_INPUTLANGCHANGE + case WM_INPUTLANGCHANGE: + parameters = QLatin1String("Keyboard layout changed"); + break; +#endif // WM_INPUTLANGCHANGE #ifdef WM_NCACTIVATE case WM_NCACTIVATE: { diff --git a/src/gui/kernel/qkeymapper_win.cpp b/src/gui/kernel/qkeymapper_win.cpp index 34b0b4f..5a2e78e 100644 --- a/src/gui/kernel/qkeymapper_win.cpp +++ b/src/gui/kernel/qkeymapper_win.cpp @@ -662,7 +662,7 @@ void QKeyMapperPrivate::updateKeyMap(const MSG &msg) { unsigned char kbdBuffer[256]; // Will hold the complete keyboard state GetKeyboardState(kbdBuffer); - quint32 scancode = (msg.lParam >> 16) & 0xfff; + const quint32 scancode = (msg.lParam >> 16) & 0xff; updatePossibleKeyCodes(kbdBuffer, scancode, msg.wParam); } @@ -797,10 +797,12 @@ bool QKeyMapperPrivate::translateKeyEvent(QWidget *widget, const MSG &msg, bool bool k0 = false; bool k1 = false; int msgType = msg.message; + // Add this key to the keymap if it is not present yet. + updateKeyMap(msg); + + const quint32 scancode = (msg.lParam >> 16) & 0xff; + const quint32 vk_key = msg.wParam; - quint32 scancode = (msg.lParam >> 16) & 0xfff; - quint32 vk_key = MapVirtualKey(scancode, 1); - bool isNumpad = (msg.wParam >= VK_NUMPAD0 && msg.wParam <= VK_NUMPAD9); quint32 nModifiers = 0; #if defined(Q_OS_WINCE) @@ -835,10 +837,6 @@ bool QKeyMapperPrivate::translateKeyEvent(QWidget *widget, const MSG &msg, bool state |= (nModifiers & AltAny ? int(Qt::AltModifier) : 0); state |= (nModifiers & MetaAny ? int(Qt::MetaModifier) : 0); - // Now we know enough to either have MapVirtualKey or our own keymap tell us if it's a deadkey - bool isDeadKey = isADeadKey(msg.wParam, state) - || MapVirtualKey(msg.wParam, 2) & 0x80000000; - // A multi-character key not found by our look-ahead if (msgType == WM_CHAR) { QString s; @@ -921,23 +919,12 @@ bool QKeyMapperPrivate::translateKeyEvent(QWidget *widget, const MSG &msg, bool return true; // Translate VK_* (native) -> Key_* (Qt) keys - // If it's a dead key, we cannot use the toKeyOrUnicode() function, since that will change - // the internal state of the keyboard driver, resulting in that dead keys no longer works. - // ..also if we're typing numbers on the keypad, while holding down the Alt modifier. - int code = 0; - if (isNumpad && (nModifiers & AltAny)) { - code = winceKeyBend(msg.wParam); - } else if (!isDeadKey) { - // QTBUG-8764, QTBUG-10032 - // Can't call toKeyOrUnicode because that would call ToUnicode, and, if a dead key - // is pressed at the moment, Windows would NOT use it to compose a character for the next - // WM_CHAR event. - - // Instead, use MapVirtualKey, which will provide adequate values. - code = MapVirtualKey(msg.wParam, MAPVK_VK_TO_CHAR); - if (code < 0x20 || code == 0x7f) // The same logic as in toKeyOrUnicode() - code = winceKeyBend(msg.wParam); - } + int modifiersIndex = 0; + modifiersIndex |= (nModifiers & ShiftAny ? 0x1 : 0); + modifiersIndex |= (nModifiers & ControlAny ? 0x2 : 0); + modifiersIndex |= (nModifiers & AltAny ? 0x4 : 0); + + int code = keyLayout[vk_key]->qtKey[modifiersIndex]; // Invert state logic: // If the key actually pressed is a modifier key, then we remove its modifier key from the -- cgit v0.12