macOS: Don't wrap key event keys in QChar

Key events have a wider range of possible values than the unicode range,
as they also include all the special keys as defined in Qt::Keys.

Instead of turning the argument to keyMapForKey into an integer,
we can remove the argument completely, as it was only used as a
fallback in the cases where UCKeyTranslate (or in the future,
charactersByApplyingModifiers:), failed to map the virtual key
and modifiers to a character. But in those cases we should not
fall back to the Qt key from the key event, as that doesn't
match what the keyboard layout defines. Most keyboard layouts
explicitly define the base key as the key for these "undefined"
mappings, but if the keyboard layout does not, we should not
produce any input in the application, to match what AppKit does
in this case.

Fixes: QTBUG-90315
Fixes: QTBUG-92891
Change-Id: Ib9ffd9521049ee8e4b103597c1d34cbe3d23dbdf
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
(cherry picked from commit 6faa33192c99f3432b28591b991918b47bd6fa09)
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
This commit is contained in:
Tor Arne Vestbø 2021-01-27 18:32:48 +01:00
parent 9e908fc57a
commit f3e861819d
2 changed files with 17 additions and 13 deletions

View File

@ -481,7 +481,7 @@ static constexpr Qt::KeyboardModifiers modifierCombinations[] = {
Returns a key map for the given \virtualKey based on all Returns a key map for the given \virtualKey based on all
possible modifier combinations. possible modifier combinations.
*/ */
const QAppleKeyMapper::KeyMap &QAppleKeyMapper::keyMapForKey(VirtualKeyCode virtualKey, QChar unicodeKey) const const QAppleKeyMapper::KeyMap &QAppleKeyMapper::keyMapForKey(VirtualKeyCode virtualKey) const
{ {
static_assert(sizeof(modifierCombinations) / sizeof(Qt::KeyboardModifiers) == kNumModifierCombinations); static_assert(sizeof(modifierCombinations) / sizeof(Qt::KeyboardModifiers) == kNumModifierCombinations);
@ -491,7 +491,7 @@ const QAppleKeyMapper::KeyMap &QAppleKeyMapper::keyMapForKey(VirtualKeyCode virt
if (keyMap[Qt::NoModifier] != Qt::Key_unknown) if (keyMap[Qt::NoModifier] != Qt::Key_unknown)
return keyMap; // Already filled return keyMap; // Already filled
qCDebug(lcQpaKeyMapper, "Updating key map for virtual key = 0x%02x!", (uint)virtualKey); qCDebug(lcQpaKeyMapper, "Updating key map for virtual key 0x%02x", (uint)virtualKey);
// Key mapping via [NSEvent charactersByApplyingModifiers:] only works for key down // Key mapping via [NSEvent charactersByApplyingModifiers:] only works for key down
// events, but we might (wrongly) get into this code path for other key events such // events, but we might (wrongly) get into this code path for other key events such
@ -515,9 +515,10 @@ const QAppleKeyMapper::KeyMap &QAppleKeyMapper::keyMapForKey(VirtualKeyCode virt
kUCKeyActionDown, modifierKeyState, m_keyboardKind, OptionBits(0), kUCKeyActionDown, modifierKeyState, m_keyboardKind, OptionBits(0),
&m_deadKeyState, maxStringLength, &actualStringLength, unicodeString); &m_deadKeyState, maxStringLength, &actualStringLength, unicodeString);
// Use translated unicode key if valid // Use translated Unicode key if valid
QChar carbonUnicodeKey;
if (err == noErr && actualStringLength) if (err == noErr && actualStringLength)
unicodeKey = QChar(unicodeString[0]); carbonUnicodeKey = QChar(unicodeString[0]);
if (@available(macOS 10.15, *)) { if (@available(macOS 10.15, *)) {
if (canMapCocoaEvent) { if (canMapCocoaEvent) {
@ -528,21 +529,24 @@ const QAppleKeyMapper::KeyMap &QAppleKeyMapper::keyMapForKey(VirtualKeyCode virt
auto *charactersWithModifiers = [NSApp.currentEvent charactersByApplyingModifiers:cocoaModifiers]; auto *charactersWithModifiers = [NSApp.currentEvent charactersByApplyingModifiers:cocoaModifiers];
Q_ASSERT(charactersWithModifiers && charactersWithModifiers.length > 0); Q_ASSERT(charactersWithModifiers && charactersWithModifiers.length > 0);
auto cocoaUnicodeKey = QChar([charactersWithModifiers characterAtIndex:0]); auto cocoaUnicodeKey = QChar([charactersWithModifiers characterAtIndex:0]);
if (cocoaUnicodeKey != unicodeKey) { if (cocoaUnicodeKey != carbonUnicodeKey) {
qCWarning(lcQpaKeyMapper) << "Mismatch between Cocoa" << cocoaUnicodeKey qCWarning(lcQpaKeyMapper) << "Mismatch between Cocoa" << cocoaUnicodeKey
<< "and Carbon" << unicodeKey << "for virtual key" << virtualKey << "and Carbon" << carbonUnicodeKey << "for virtual key" << virtualKey
<< "with" << qtModifiers; << "with" << qtModifiers;
} }
} }
} }
int qtkey = toKeyCode(unicodeKey, virtualKey, qtModifiers); int qtKey = toKeyCode(carbonUnicodeKey, virtualKey, qtModifiers);
if (qtkey == Qt::Key_unknown) if (qtKey == Qt::Key_unknown)
qtkey = unicodeKey.unicode(); qtKey = carbonUnicodeKey.unicode();
keyMap[i] = qtkey; keyMap[i] = qtKey;
qCDebug(lcQpaKeyMapper, " [%d] (%d,0x%02x,'%c')", i, qtkey, qtkey, qtkey); qCDebug(lcQpaKeyMapper).verbosity(0) << "\t" << qtModifiers
<< "+" << qUtf8Printable(QString::asprintf("0x%02x", virtualKey))
<< "=" << qUtf8Printable(QString::asprintf("%d / 0x%02x /", qtKey, qtKey))
<< QString::asprintf("%c", qtKey);
} }
return keyMap; return keyMap;
@ -556,7 +560,7 @@ QList<int> QAppleKeyMapper::possibleKeys(const QKeyEvent *event) const
if (!nativeVirtualKey) if (!nativeVirtualKey)
return ret; return ret;
auto keyMap = keyMapForKey(nativeVirtualKey, QChar(event->key())); auto keyMap = keyMapForKey(nativeVirtualKey);
auto unmodifiedKey = keyMap[Qt::NoModifier]; auto unmodifiedKey = keyMap[Qt::NoModifier];
Q_ASSERT(unmodifiedKey != Qt::Key_unknown); Q_ASSERT(unmodifiedKey != Qt::Key_unknown);

View File

@ -95,7 +95,7 @@ private:
bool updateKeyboard(); bool updateKeyboard();
using VirtualKeyCode = unsigned short; using VirtualKeyCode = unsigned short;
const KeyMap &keyMapForKey(VirtualKeyCode virtualKey, QChar unicodeKey) const; const KeyMap &keyMapForKey(VirtualKeyCode virtualKey) const;
QCFType<TISInputSourceRef> m_currentInputSource = nullptr; QCFType<TISInputSourceRef> m_currentInputSource = nullptr;