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 <oliver.wolff@qt.io>
This commit is contained in:
Friedemann Kleint 2018-07-13 08:21:31 +02:00
parent d3dc3e7743
commit 81d6cf71cc
8 changed files with 67 additions and 11 deletions

View File

@ -383,7 +383,8 @@
\value AltModifier An Alt key on the keyboard is pressed. \value AltModifier An Alt key on the keyboard is pressed.
\value MetaModifier A Meta key on the keyboard is pressed. \value MetaModifier A Meta key on the keyboard is pressed.
\value KeypadModifier A keypad button is pressed. \value KeypadModifier A keypad button is pressed.
\value GroupSwitchModifier X11 only. A Mode_switch key on the keyboard is pressed. \value GroupSwitchModifier X11 only (unless activated on Windows by a command line argument).
A Mode_switch key on the keyboard is pressed.
\omitvalue KeyboardModifierMask \omitvalue KeyboardModifierMask

View File

@ -594,6 +594,9 @@ static QWindowGeometrySpecification windowGeometrySpecification = Q_WINDOW_GEOME
By default, they will be used if the application is not an By default, they will be used if the application is not an
instance of QApplication or for Qt Quick Controls 2 instance of QApplication or for Qt Quick Controls 2
applications. applications.
\li \c {altgr}, detect the key \c {AltGr} found on some keyboards as
Qt::GroupSwitchModifier.
\endlist \endlist
The following parameter is available for \c {-platform cocoa} (on macOS): The following parameter is available for \c {-platform cocoa} (on macOS):

View File

@ -378,6 +378,11 @@ void QWindowsContext::setTabletAbsoluteRange(int a)
#endif #endif
} }
void QWindowsContext::setDetectAltGrModifier(bool a)
{
d->m_keyMapper.setDetectAltGrModifier(a);
}
int QWindowsContext::processDpiAwareness() int QWindowsContext::processDpiAwareness()
{ {
int result; int result;

View File

@ -208,6 +208,8 @@ public:
void setProcessDpiAwareness(QtWindows::ProcessDpiAwareness dpiAwareness); void setProcessDpiAwareness(QtWindows::ProcessDpiAwareness dpiAwareness);
static int processDpiAwareness(); static int processDpiAwareness();
void setDetectAltGrModifier(bool a);
// Returns a combination of SystemInfoFlags // Returns a combination of SystemInfoFlags
unsigned systemInfo() const; unsigned systemInfo() const;

View File

@ -198,6 +198,8 @@ static inline unsigned parseOptions(const QStringList &paramList,
} else if (param.endsWith(QLatin1String("none"))) { } else if (param.endsWith(QLatin1String("none"))) {
options |= QWindowsIntegration::NoNativeDialogs; options |= QWindowsIntegration::NoNativeDialogs;
} }
} else if (param == QLatin1String("altgr")) {
options |= QWindowsIntegration::DetectAltGrModifier;
} else if (param == QLatin1String("gl=gdi")) { } else if (param == QLatin1String("gl=gdi")) {
options |= QWindowsIntegration::DisableArb; options |= QWindowsIntegration::DisableArb;
} else if (param == QLatin1String("nodirectwrite")) { } else if (param == QLatin1String("nodirectwrite")) {
@ -269,6 +271,7 @@ QWindowsIntegration::QWindowsIntegration(const QStringList &paramList) :
d->m_clipboard.registerViewer(); d->m_clipboard.registerViewer();
#endif #endif
d->m_context.screenManager().handleScreenChanges(); d->m_context.screenManager().handleScreenChanges();
d->m_context.setDetectAltGrModifier((d->m_options & DetectAltGrModifier) != 0);
} }
QWindowsIntegration::~QWindowsIntegration() QWindowsIntegration::~QWindowsIntegration()

View File

@ -69,6 +69,7 @@ public:
AlwaysUseNativeMenus = 0x100, AlwaysUseNativeMenus = 0x100,
NoNativeMenus = 0x200, NoNativeMenus = 0x200,
DontUseWMPointer = 0x400, DontUseWMPointer = 0x400,
DetectAltGrModifier = 0x800
}; };
explicit QWindowsIntegration(const QStringList &paramList); explicit QWindowsIntegration(const QStringList &paramList);

View File

@ -672,6 +672,7 @@ void QWindowsKeyMapper::changeKeyboard()
bidi = true; bidi = true;
keyboardInputDirection = bidi ? Qt::RightToLeft : Qt::LeftToRight; 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 // 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 #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 UINT msgType = msg.message;
const quint32 scancode = (msg.lParam >> 16) & scancodeBitmask; 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) // Get the modifier states (may be altered later, depending on key code)
int state = 0; int state = 0;
state |= (nModifiers & ShiftAny ? int(Qt::ShiftModifier) : 0); state |= (nModifiers & ShiftAny ? int(Qt::ShiftModifier) : 0);
state |= (nModifiers & ControlAny ? int(Qt::ControlModifier) : 0); state |= (nModifiers & AltLeft ? int(Qt::AltModifier) : 0);
state |= (nModifiers & AltAny ? 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); state |= (nModifiers & MetaAny ? int(Qt::MetaModifier) : 0);
// A multi-character key or a Input method character // A multi-character key or a Input method character
// not found by our look-ahead // not found by our look-ahead
if (msgType == WM_CHAR || msgType == WM_IME_CHAR) { 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 & ControlAny ? 0x2 : 0);
modifiersIndex |= (nModifiers & AltAny ? 0x4 : 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]; 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: // Invert state logic:
// If the key actually pressed is a modifier key, then we remove its modifier key from the // 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 // 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; state = state ^ Qt::ShiftModifier;
else if (code == Qt::Key_Alt) else if (code == Qt::Key_Alt)
state = state ^ Qt::AltModifier; state = state ^ Qt::AltModifier;
else if (code == Qt::Key_AltGr)
// If the bit 24 of lParm is set you received a enter, state = state ^ Qt::GroupSwitchModifier;
// otherwise a Return. (This is the extended key bit)
if ((code == Qt::Key_Return) && (msg.lParam & 0x1000000))
code = Qt::Key_Enter;
// All cursor keys without extended bit // All cursor keys without extended bit
if (!(msg.lParam & 0x1000000)) { if (!(msg.lParam & 0x1000000)) {

View File

@ -81,6 +81,9 @@ public:
void setUseRTLExtensions(bool e) { m_useRTLExtensions = e; } void setUseRTLExtensions(bool e) { m_useRTLExtensions = e; }
bool useRTLExtensions() const { return m_useRTLExtensions; } 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); bool translateKeyEvent(QWindow *widget, HWND hwnd, const MSG &msg, LRESULT *result);
QWindow *keyGrabber() const { return m_keyGrabber; } QWindow *keyGrabber() const { return m_keyGrabber; }
@ -90,7 +93,7 @@ public:
QList<int> possibleKeys(const QKeyEvent *e) const; QList<int> possibleKeys(const QKeyEvent *e) const;
private: 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); bool translateMultimediaKeyEventInternal(QWindow *receiver, const MSG &msg);
void updateKeyMap(const MSG &msg); void updateKeyMap(const MSG &msg);
@ -106,6 +109,9 @@ private:
QChar m_lastHighSurrogate; QChar m_lastHighSurrogate;
static const size_t NumKeyboardLayoutItems = 256; static const size_t NumKeyboardLayoutItems = 256;
KeyboardLayoutItem keyLayout[NumKeyboardLayoutItems]; KeyboardLayoutItem keyLayout[NumKeyboardLayoutItems];
bool m_detectAltGrModifier = false;
bool m_seenAltGr = false;
}; };
enum WindowsNativeModifiers { enum WindowsNativeModifiers {