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:
parent
d3dc3e7743
commit
81d6cf71cc
@ -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
|
||||||
|
|
||||||
|
@ -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):
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -198,6 +198,8 @@ static inline unsigned parseOptions(const QStringList ¶mList,
|
|||||||
} 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 ¶mList) :
|
|||||||
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()
|
||||||
|
@ -69,6 +69,7 @@ public:
|
|||||||
AlwaysUseNativeMenus = 0x100,
|
AlwaysUseNativeMenus = 0x100,
|
||||||
NoNativeMenus = 0x200,
|
NoNativeMenus = 0x200,
|
||||||
DontUseWMPointer = 0x400,
|
DontUseWMPointer = 0x400,
|
||||||
|
DetectAltGrModifier = 0x800
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit QWindowsIntegration(const QStringList ¶mList);
|
explicit QWindowsIntegration(const QStringList ¶mList);
|
||||||
|
@ -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)) {
|
||||||
|
@ -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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user