From fab3dfff7d53d496a31c5d2df972ddacfe861a4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Fri, 10 Jul 2020 12:13:36 +0200 Subject: macOS: Modernize QCocoaKeyMapper key map Change-Id: I3e8a4cfa611b6ae575466c493aac438dc831e89a Reviewed-by: Timur Pocheptsov --- src/plugins/platforms/cocoa/qcocoakeymapper.h | 22 +++++---- src/plugins/platforms/cocoa/qcocoakeymapper.mm | 67 +++++++++----------------- 2 files changed, 36 insertions(+), 53 deletions(-) (limited to 'src/plugins/platforms/cocoa') diff --git a/src/plugins/platforms/cocoa/qcocoakeymapper.h b/src/plugins/platforms/cocoa/qcocoakeymapper.h index 7f20a37125..c0540bfe1d 100644 --- a/src/plugins/platforms/cocoa/qcocoakeymapper.h +++ b/src/plugins/platforms/cocoa/qcocoakeymapper.h @@ -69,16 +69,10 @@ QT_BEGIN_NAMESPACE 15. Meta + Alt + Control 16. Meta + Alt + Control + Shift */ -struct KeyboardLayoutItem { - quint32 qtKey[16]; // Can by any Qt::Key_, or unicode character -}; - class QCocoaKeyMapper { public: - QCocoaKeyMapper(); - ~QCocoaKeyMapper(); static Qt::KeyboardModifiers queryKeyboardModifiers(); QList possibleKeys(const QKeyEvent *event) const; @@ -89,9 +83,18 @@ public: static Qt::Key fromCocoaKey(QChar keyCode); private: + using VirtualKeyCode = unsigned short; + struct KeyMap : std::array + { + // Initialize first element to a sentinel that allows us + // to distinguish an uninitialized map from an initialized. + // Using 0 would not allow us to map U+0000 (NUL), however + // unlikely that is. + KeyMap() : std::array{Qt::Key_unknown} {} + }; + bool updateKeyboard(); - void deleteLayouts(); - KeyboardLayoutItem *keyMapForKey(unsigned short macVirtualKey, QChar unicodeKey) const; + const KeyMap &keyMapForKey(VirtualKeyCode virtualKey, QChar unicodeKey) const; QCFType m_currentInputSource = nullptr; @@ -99,7 +102,8 @@ private: const UCKeyboardLayout *m_keyboardLayoutFormat = nullptr; KeyboardLayoutKind m_keyboardKind = kKLKCHRuchrKind; mutable UInt32 m_deadKeyState = 0; // Maintains dead key state beween calls to UCKeyTranslate - mutable KeyboardLayoutItem *m_keyLayout[256]; + + mutable QHash m_keyMap; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoakeymapper.mm b/src/plugins/platforms/cocoa/qcocoakeymapper.mm index 589bbcad23..4f3e886a34 100644 --- a/src/plugins/platforms/cocoa/qcocoakeymapper.mm +++ b/src/plugins/platforms/cocoa/qcocoakeymapper.mm @@ -381,16 +381,6 @@ Qt::Key QCocoaKeyMapper::fromCocoaKey(QChar keyCode) // ------------------------------------------------ -QCocoaKeyMapper::QCocoaKeyMapper() -{ - memset(m_keyLayout, 0, sizeof(m_keyLayout)); -} - -QCocoaKeyMapper::~QCocoaKeyMapper() -{ - deleteLayouts(); -} - Qt::KeyboardModifiers QCocoaKeyMapper::queryKeyboardModifiers() { return fromCocoaModifiers(NSEvent.modifierFlags); @@ -410,7 +400,7 @@ bool QCocoaKeyMapper::updateKeyboard() m_keyboardKind = LMGetKbdType(); m_deadKeyState = 0; - deleteLayouts(); + m_keyMap.clear(); if (auto data = CFDataRef(TISGetInputSourceProperty(source, kTISPropertyUnicodeKeyLayoutData))) { const UCKeyboardLayout *uchrData = reinterpret_cast(CFDataGetBytePtr(data)); @@ -429,17 +419,6 @@ bool QCocoaKeyMapper::updateKeyboard() return true; } -void QCocoaKeyMapper::deleteLayouts() -{ - m_keyboardMode = NullMode; - for (int i = 0; i < 255; ++i) { - if (m_keyLayout[i]) { - delete m_keyLayout[i]; - m_keyLayout[i] = nullptr; - } - } -} - static constexpr Qt::KeyboardModifiers modifierCombinations[] = { Qt::NoModifier, // 0 Qt::ShiftModifier, // 1 @@ -460,31 +439,31 @@ static constexpr Qt::KeyboardModifiers modifierCombinations[] = { }; /* - Returns a key map for the given \macVirtualKey based on all + Returns a key map for the given \virtualKey based on all possible modifier combinations. */ -KeyboardLayoutItem *QCocoaKeyMapper::keyMapForKey(unsigned short macVirtualKey, QChar unicodeKey) const +const QCocoaKeyMapper::KeyMap &QCocoaKeyMapper::keyMapForKey(VirtualKeyCode virtualKey, QChar unicodeKey) const { const_cast(this)->updateKeyboard(); - Q_ASSERT(macVirtualKey < 256); - if (auto *existingKeyMap = m_keyLayout[macVirtualKey]) - return existingKeyMap; + auto &keyMap = m_keyMap[virtualKey]; + if (keyMap[Qt::NoModifier] != Qt::Key_unknown) + return keyMap; // Already filled - qCDebug(lcQpaKeyMapper, "Updating key map for virtual key = 0x%02x!", (uint)macVirtualKey); + qCDebug(lcQpaKeyMapper, "Updating key map for virtual key = 0x%02x!", (uint)virtualKey); UniCharCount maxStringLength = 10; UniChar unicodeString[maxStringLength]; - m_keyLayout[macVirtualKey] = new KeyboardLayoutItem; for (int i = 0; i < 16; ++i) { - UniCharCount actualStringLength = 0; - m_keyLayout[macVirtualKey]->qtKey[i] = 0; + Q_ASSERT(!i || keyMap[i] == 0); auto qtModifiers = modifierCombinations[i]; auto carbonModifiers = toCarbonModifiers(qtModifiers); const UInt32 modifierKeyState = (carbonModifiers >> 8) & 0xFF; - OSStatus err = UCKeyTranslate(m_keyboardLayoutFormat, macVirtualKey, + + UniCharCount actualStringLength = 0; + OSStatus err = UCKeyTranslate(m_keyboardLayoutFormat, virtualKey, kUCKeyActionDown, modifierKeyState, m_keyboardKind, OptionBits(0), &m_deadKeyState, maxStringLength, &actualStringLength, unicodeString); @@ -492,36 +471,36 @@ KeyboardLayoutItem *QCocoaKeyMapper::keyMapForKey(unsigned short macVirtualKey, if (err == noErr && actualStringLength) unicodeKey = QChar(unicodeString[0]); - int qtkey = toKeyCode(unicodeKey, macVirtualKey, qtModifiers); + int qtkey = toKeyCode(unicodeKey, virtualKey, qtModifiers); if (qtkey == Qt::Key_unknown) qtkey = unicodeKey.unicode(); - m_keyLayout[macVirtualKey]->qtKey[i] = qtkey; + keyMap[i] = qtkey; qCDebug(lcQpaKeyMapper, " [%d] (%d,0x%02x,'%c')", i, qtkey, qtkey, qtkey); } - return m_keyLayout[macVirtualKey]; + return keyMap; } QList QCocoaKeyMapper::possibleKeys(const QKeyEvent *event) const { QList ret; - auto *keyMap = keyMapForKey(event->nativeVirtualKey(), QChar(event->key())); - Q_ASSERT(keyMap); + auto keyMap = keyMapForKey(event->nativeVirtualKey(), QChar(event->key())); + + auto unmodifiedKey = keyMap[Qt::NoModifier]; + Q_ASSERT(unmodifiedKey != Qt::Key_unknown); - int baseKey = keyMap->qtKey[Qt::NoModifier]; auto eventModifiers = event->modifiers(); - // The base key is always valid - ret << int(baseKey + eventModifiers); + // The base key, with the complete set of modifiers, + // is always valid, and the first priority. + ret << int(unmodifiedKey + eventModifiers); for (int i = 1; i < 8; ++i) { - int keyAfterApplyingModifiers = keyMap->qtKey[i]; - if (!keyAfterApplyingModifiers) - continue; - if (keyAfterApplyingModifiers == baseKey) + auto keyAfterApplyingModifiers = keyMap[i]; + if (keyAfterApplyingModifiers == unmodifiedKey) continue; // Include key if event modifiers includes, or matches -- cgit v1.2.3