From 81d6cf71cc9202374a706305402a34dd1a06c2bd Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 13 Jul 2018 08:21:31 +0200 Subject: Windows QPA: Add option to detect AltGr key presses According to MSDN, AltGr key presses are sent as a sequence of SYS left Ctrl + right Alt. Add an option to detect AltGr as modifier key. Task-number: QTBUG-69317 Change-Id: I30ce169d2e6dbbae194ff714abfbc732b53652ce Reviewed-by: Oliver Wolff --- src/plugins/platforms/windows/qwindowscontext.cpp | 5 ++ src/plugins/platforms/windows/qwindowscontext.h | 2 + .../platforms/windows/qwindowsintegration.cpp | 3 ++ .../platforms/windows/qwindowsintegration.h | 1 + .../platforms/windows/qwindowskeymapper.cpp | 53 ++++++++++++++++++---- src/plugins/platforms/windows/qwindowskeymapper.h | 8 +++- 6 files changed, 62 insertions(+), 10 deletions(-) (limited to 'src/plugins/platforms/windows') diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index bba7d044f7..e29e5b8187 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -378,6 +378,11 @@ void QWindowsContext::setTabletAbsoluteRange(int a) #endif } +void QWindowsContext::setDetectAltGrModifier(bool a) +{ + d->m_keyMapper.setDetectAltGrModifier(a); +} + int QWindowsContext::processDpiAwareness() { int result; diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h index fe83c83934..3709d9deee 100644 --- a/src/plugins/platforms/windows/qwindowscontext.h +++ b/src/plugins/platforms/windows/qwindowscontext.h @@ -208,6 +208,8 @@ public: void setProcessDpiAwareness(QtWindows::ProcessDpiAwareness dpiAwareness); static int processDpiAwareness(); + void setDetectAltGrModifier(bool a); + // Returns a combination of SystemInfoFlags unsigned systemInfo() const; diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index 1a1d51cae1..4824de5c9c 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -198,6 +198,8 @@ static inline unsigned parseOptions(const QStringList ¶mList, } else if (param.endsWith(QLatin1String("none"))) { options |= QWindowsIntegration::NoNativeDialogs; } + } else if (param == QLatin1String("altgr")) { + options |= QWindowsIntegration::DetectAltGrModifier; } else if (param == QLatin1String("gl=gdi")) { options |= QWindowsIntegration::DisableArb; } else if (param == QLatin1String("nodirectwrite")) { @@ -269,6 +271,7 @@ QWindowsIntegration::QWindowsIntegration(const QStringList ¶mList) : d->m_clipboard.registerViewer(); #endif d->m_context.screenManager().handleScreenChanges(); + d->m_context.setDetectAltGrModifier((d->m_options & DetectAltGrModifier) != 0); } QWindowsIntegration::~QWindowsIntegration() diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h index 25f485679d..da86852766 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.h +++ b/src/plugins/platforms/windows/qwindowsintegration.h @@ -69,6 +69,7 @@ public: AlwaysUseNativeMenus = 0x100, NoNativeMenus = 0x200, DontUseWMPointer = 0x400, + DetectAltGrModifier = 0x800 }; explicit QWindowsIntegration(const QStringList ¶mList); diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp index e7efd6e057..1209b6c4b4 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.cpp +++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp @@ -672,6 +672,7 @@ void QWindowsKeyMapper::changeKeyboard() bidi = true; keyboardInputDirection = bidi ? Qt::RightToLeft : Qt::LeftToRight; + m_seenAltGr = false; } // Helper function that is used when obtaining the list of characters that can be produced by one key and @@ -906,8 +907,34 @@ bool QWindowsKeyMapper::translateMultimediaKeyEventInternal(QWindow *window, con #endif } -bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, const MSG &msg, bool /* grab */, LRESULT *lResult) +// QTBUG-69317: Check for AltGr found on some keyboards +// which is a sequence of left Ctrl (SYSKEY) + right Menu (Alt). +static bool isAltGr(MSG *msg) { + enum : LONG_PTR { RightFlag = 0x1000000 }; + if (msg->wParam != VK_CONTROL || (msg->lParam & RightFlag) != 0 + || (msg->message != WM_KEYDOWN && msg->message != WM_SYSKEYUP)) { + return false; + } + const UINT expectedMessage = msg->message == WM_SYSKEYUP + ? WM_KEYUP : msg->message; + MSG peekedMsg; + if (PeekMessage(&peekedMsg, msg->hwnd, 0, 0, PM_NOREMOVE) == FALSE + || peekedMsg.message != expectedMessage || peekedMsg.wParam != VK_MENU + || (peekedMsg.lParam & RightFlag) == 0) { + return false; + } + *msg = peekedMsg; + PeekMessage(&peekedMsg, msg->hwnd, 0, 0, PM_REMOVE); + return true; +} + +bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, MSG msg, + bool /* grab */, LRESULT *lResult) +{ + const bool altGr = m_detectAltGrModifier && isAltGr(&msg); + if (altGr) + m_seenAltGr = true; const UINT msgType = msg.message; const quint32 scancode = (msg.lParam >> 16) & scancodeBitmask; @@ -936,10 +963,12 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, const MSG &ms // Get the modifier states (may be altered later, depending on key code) int state = 0; state |= (nModifiers & ShiftAny ? int(Qt::ShiftModifier) : 0); - state |= (nModifiers & ControlAny ? int(Qt::ControlModifier) : 0); - state |= (nModifiers & AltAny ? int(Qt::AltModifier) : 0); + state |= (nModifiers & AltLeft ? int(Qt::AltModifier) : 0); + if ((nModifiers & AltRight) != 0) + state |= m_seenAltGr ? Qt::GroupSwitchModifier : Qt::AltModifier; + if ((nModifiers & ControlAny) != 0 && (state & Qt::GroupSwitchModifier) == 0) + state |= Qt::ControlModifier; state |= (nModifiers & MetaAny ? int(Qt::MetaModifier) : 0); - // A multi-character key or a Input method character // not found by our look-ahead if (msgType == WM_CHAR || msgType == WM_IME_CHAR) { @@ -1010,8 +1039,17 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, const MSG &ms modifiersIndex |= (nModifiers & ControlAny ? 0x2 : 0); modifiersIndex |= (nModifiers & AltAny ? 0x4 : 0); + // Note: For the resulting key, AltGr is equivalent to Alt + Ctrl (as + // opposed to Linux); hence no entry in KeyboardLayoutItem is required int code = keyLayout[vk_key].qtKey[modifiersIndex]; + // If the bit 24 of lParm is set you received a enter, + // otherwise a Return. (This is the extended key bit) + if ((code == Qt::Key_Return) && (msg.lParam & 0x1000000)) + code = Qt::Key_Enter; + else if (altGr) + code = Qt::Key_AltGr; + // Invert state logic: // If the key actually pressed is a modifier key, then we remove its modifier key from the // state, since a modifier-key can't have itself as a modifier @@ -1021,11 +1059,8 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, const MSG &ms state = state ^ Qt::ShiftModifier; else if (code == Qt::Key_Alt) state = state ^ Qt::AltModifier; - - // If the bit 24 of lParm is set you received a enter, - // otherwise a Return. (This is the extended key bit) - if ((code == Qt::Key_Return) && (msg.lParam & 0x1000000)) - code = Qt::Key_Enter; + else if (code == Qt::Key_AltGr) + state = state ^ Qt::GroupSwitchModifier; // All cursor keys without extended bit if (!(msg.lParam & 0x1000000)) { diff --git a/src/plugins/platforms/windows/qwindowskeymapper.h b/src/plugins/platforms/windows/qwindowskeymapper.h index d569c82437..a454f0f973 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.h +++ b/src/plugins/platforms/windows/qwindowskeymapper.h @@ -81,6 +81,9 @@ public: void setUseRTLExtensions(bool e) { m_useRTLExtensions = e; } bool useRTLExtensions() const { return m_useRTLExtensions; } + void setDetectAltGrModifier(bool a) { m_detectAltGrModifier = a; } + bool detectAltGrModifier() const { return m_detectAltGrModifier; } + bool translateKeyEvent(QWindow *widget, HWND hwnd, const MSG &msg, LRESULT *result); QWindow *keyGrabber() const { return m_keyGrabber; } @@ -90,7 +93,7 @@ public: QList possibleKeys(const QKeyEvent *e) const; private: - bool translateKeyEventInternal(QWindow *receiver, const MSG &msg, bool grab, LRESULT *lResult); + bool translateKeyEventInternal(QWindow *receiver, MSG msg, bool grab, LRESULT *lResult); bool translateMultimediaKeyEventInternal(QWindow *receiver, const MSG &msg); void updateKeyMap(const MSG &msg); @@ -106,6 +109,9 @@ private: QChar m_lastHighSurrogate; static const size_t NumKeyboardLayoutItems = 256; KeyboardLayoutItem keyLayout[NumKeyboardLayoutItems]; + bool m_detectAltGrModifier = false; + bool m_seenAltGr = false; + }; enum WindowsNativeModifiers { -- cgit v1.2.3