diff options
Diffstat (limited to 'src/plugins/platforms/cocoa/qcocoakeymapper.mm')
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoakeymapper.mm | 440 |
1 files changed, 0 insertions, 440 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoakeymapper.mm b/src/plugins/platforms/cocoa/qcocoakeymapper.mm deleted file mode 100644 index 86143f275b..0000000000 --- a/src/plugins/platforms/cocoa/qcocoakeymapper.mm +++ /dev/null @@ -1,440 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <AppKit/AppKit.h> - -#include "qcocoakeymapper.h" - -#include <QtCore/qloggingcategory.h> -#include <QtGui/QGuiApplication> - -QT_BEGIN_NAMESPACE - -Q_LOGGING_CATEGORY(lcQpaKeyMapper, "qt.qpa.keymapper"); -Q_LOGGING_CATEGORY(lcQpaKeyMapperKeys, "qt.qpa.keymapper.keys"); -Q_LOGGING_CATEGORY(lcQpaKeyMapperModifiers, "qt.qpa.keymapper.modifiers"); - -static constexpr std::tuple<int, Qt::KeyboardModifier> carbonModifierMap[] = { - { shiftKey, Qt::ShiftModifier }, - { rightShiftKey, Qt::ShiftModifier }, - { controlKey, Qt::MetaModifier }, - { rightControlKey, Qt::MetaModifier }, - { cmdKey, Qt::ControlModifier }, - { optionKey, Qt::AltModifier }, - { rightOptionKey, Qt::AltModifier }, - { kEventKeyModifierNumLockMask, Qt::KeypadModifier } -}; - -using CarbonModifiers = UInt32; // As opposed to EventModifiers which is UInt16 - -Qt::KeyboardModifiers fromCarbonModifiers(CarbonModifiers carbonModifiers) -{ - qCDebug(lcQpaKeyMapperModifiers, "Mapping carbon modifiers: %d (0x%04x)", - carbonModifiers, carbonModifiers); - - Qt::KeyboardModifiers qtModifiers = Qt::NoModifier; - for (const auto &[carbonModifier, qtModifier] : carbonModifierMap) { - if (carbonModifiers & carbonModifier) { - qCDebug(lcQpaKeyMapperModifiers) << "Got modifier" << qtModifier; - qtModifiers |= qtModifier; - } - } - - if (qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)) { - Qt::KeyboardModifiers oldModifiers = qtModifiers; - qtModifiers &= ~(Qt::MetaModifier | Qt::ControlModifier); - if (oldModifiers & Qt::ControlModifier) - qtModifiers |= Qt::MetaModifier; - if (oldModifiers & Qt::MetaModifier) - qtModifiers |= Qt::ControlModifier; - } - - return qtModifiers; -} - -static CarbonModifiers toCarbonModifiers(Qt::KeyboardModifiers qtModifiers) -{ - qCDebug(lcQpaKeyMapperModifiers).verbosity(1) << "Mapping" << qtModifiers; - - CarbonModifiers carbonModifiers = 0; - for (const auto &[carbonModifier, qtModifier] : carbonModifierMap) { - if (qtModifiers & qtModifier) { - qCDebug(lcQpaKeyMapperModifiers) << "Got carbon modifier" << carbonModifier; - carbonModifiers |= carbonModifier; - } - } - - if (qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)) { - int oldModifiers = carbonModifiers; - carbonModifiers &= ~(controlKeyBit | cmdKeyBit); - if (oldModifiers & controlKeyBit) - carbonModifiers |= cmdKeyBit; - if (oldModifiers & cmdKeyBit) - carbonModifiers |= controlKeyBit; - } - return carbonModifiers; -} - -// Keyboard keys (non-modifiers) -static QHash<QChar, Qt::Key> standardKeys = { - { kHomeCharCode, Qt::Key_Home }, - { kEnterCharCode, Qt::Key_Enter }, - { kEndCharCode, Qt::Key_End }, - { kBackspaceCharCode, Qt::Key_Backspace }, - { kTabCharCode, Qt::Key_Tab }, - { kPageUpCharCode, Qt::Key_PageUp }, - { kPageDownCharCode, Qt::Key_PageDown }, - { kReturnCharCode, Qt::Key_Return }, - { kEscapeCharCode, Qt::Key_Escape }, - { kLeftArrowCharCode, Qt::Key_Left }, - { kRightArrowCharCode, Qt::Key_Right }, - { kUpArrowCharCode, Qt::Key_Up }, - { kDownArrowCharCode, Qt::Key_Down }, - { kHelpCharCode, Qt::Key_Help }, - { kDeleteCharCode, Qt::Key_Delete }, - // ASCII maps, for debugging - { ':', Qt::Key_Colon }, - { ';', Qt::Key_Semicolon }, - { '<', Qt::Key_Less }, - { '=', Qt::Key_Equal }, - { '>', Qt::Key_Greater }, - { '?', Qt::Key_Question }, - { '@', Qt::Key_At }, - { ' ', Qt::Key_Space }, - { '!', Qt::Key_Exclam }, - { '"', Qt::Key_QuoteDbl }, - { '#', Qt::Key_NumberSign }, - { '$', Qt::Key_Dollar }, - { '%', Qt::Key_Percent }, - { '&', Qt::Key_Ampersand }, - { '\'', Qt::Key_Apostrophe }, - { '(', Qt::Key_ParenLeft }, - { ')', Qt::Key_ParenRight }, - { '*', Qt::Key_Asterisk }, - { '+', Qt::Key_Plus }, - { ',', Qt::Key_Comma }, - { '-', Qt::Key_Minus }, - { '.', Qt::Key_Period }, - { '/', Qt::Key_Slash }, - { '[', Qt::Key_BracketLeft }, - { ']', Qt::Key_BracketRight }, - { '\\', Qt::Key_Backslash }, - { '_', Qt::Key_Underscore }, - { '`', Qt::Key_QuoteLeft }, - { '{', Qt::Key_BraceLeft }, - { '}', Qt::Key_BraceRight }, - { '|', Qt::Key_Bar }, - { '~', Qt::Key_AsciiTilde }, - { '^', Qt::Key_AsciiCircum } -}; - -static QHash<QChar, Qt::Key> virtualKeys = { - { kVK_F1, Qt::Key_F1 }, - { kVK_F2, Qt::Key_F2 }, - { kVK_F3, Qt::Key_F3 }, - { kVK_F4, Qt::Key_F4 }, - { kVK_F5, Qt::Key_F5 }, - { kVK_F6, Qt::Key_F6 }, - { kVK_F7, Qt::Key_F7 }, - { kVK_F8, Qt::Key_F8 }, - { kVK_F9, Qt::Key_F9 }, - { kVK_F10, Qt::Key_F10 }, - { kVK_F11, Qt::Key_F11 }, - { kVK_F12, Qt::Key_F12 }, - { kVK_F13, Qt::Key_F13 }, - { kVK_F14, Qt::Key_F14 }, - { kVK_F15, Qt::Key_F15 }, - { kVK_F16, Qt::Key_F16 }, - { kVK_Return, Qt::Key_Return }, - { kVK_Tab, Qt::Key_Tab }, - { kVK_Escape, Qt::Key_Escape }, - { kVK_Help, Qt::Key_Help }, - { kVK_UpArrow, Qt::Key_Up }, - { kVK_DownArrow, Qt::Key_Down }, - { kVK_LeftArrow, Qt::Key_Left }, - { kVK_RightArrow, Qt::Key_Right }, - { kVK_PageUp, Qt::Key_PageUp }, - { kVK_PageDown, Qt::Key_PageDown } -}; - -static QHash<QChar, Qt::Key> functionKeys = { - { NSUpArrowFunctionKey, Qt::Key_Up }, - { NSDownArrowFunctionKey, Qt::Key_Down }, - { NSLeftArrowFunctionKey, Qt::Key_Left }, - { NSRightArrowFunctionKey, Qt::Key_Right }, - // F1-35 function keys handled manually below - { NSInsertFunctionKey, Qt::Key_Insert }, - { NSDeleteFunctionKey, Qt::Key_Delete }, - { NSHomeFunctionKey, Qt::Key_Home }, - { NSEndFunctionKey, Qt::Key_End }, - { NSPageUpFunctionKey, Qt::Key_PageUp }, - { NSPageDownFunctionKey, Qt::Key_PageDown }, - { NSPrintScreenFunctionKey, Qt::Key_Print }, - { NSScrollLockFunctionKey, Qt::Key_ScrollLock }, - { NSPauseFunctionKey, Qt::Key_Pause }, - { NSSysReqFunctionKey, Qt::Key_SysReq }, - { NSMenuFunctionKey, Qt::Key_Menu }, - { NSPrintFunctionKey, Qt::Key_Printer }, - { NSClearDisplayFunctionKey, Qt::Key_Clear }, - { NSInsertCharFunctionKey, Qt::Key_Insert }, - { NSDeleteCharFunctionKey, Qt::Key_Delete }, - { NSSelectFunctionKey, Qt::Key_Select }, - { NSExecuteFunctionKey, Qt::Key_Execute }, - { NSUndoFunctionKey, Qt::Key_Undo }, - { NSRedoFunctionKey, Qt::Key_Redo }, - { NSFindFunctionKey, Qt::Key_Find }, - { NSHelpFunctionKey, Qt::Key_Help }, - { NSModeSwitchFunctionKey, Qt::Key_Mode_switch } -}; - -static int toKeyCode(const QChar &key, int virtualKey, int modifiers) -{ - qCDebug(lcQpaKeyMapperKeys, "Mapping key: %d (0x%04x) / vk %d (0x%04x)", - key.unicode(), key.unicode(), virtualKey, virtualKey); - - if (key == kClearCharCode && virtualKey == 0x47) - return Qt::Key_Clear; - - if (key.isDigit()) { - qCDebug(lcQpaKeyMapperKeys, "Got digit key: %d", key.digitValue()); - return key.digitValue() + Qt::Key_0; - } - - if (key.isLetter()) { - qCDebug(lcQpaKeyMapperKeys, "Got letter key: %d", (key.toUpper().unicode() - 'A')); - return (key.toUpper().unicode() - 'A') + Qt::Key_A; - } - if (key.isSymbol()) { - qCDebug(lcQpaKeyMapperKeys, "Got symbol key: %d", (key.unicode())); - return key.unicode(); - } - - if (auto qtKey = standardKeys.value(key)) { - // To work like Qt for X11 we issue Backtab when Shift + Tab are pressed - if (qtKey == Qt::Key_Tab && (modifiers & Qt::ShiftModifier)) { - qCDebug(lcQpaKeyMapperKeys, "Got key: Qt::Key_Backtab"); - return Qt::Key_Backtab; - } - - qCDebug(lcQpaKeyMapperKeys) << "Got" << qtKey; - return qtKey; - } - - // Last ditch try to match the scan code - if (auto qtKey = virtualKeys.value(virtualKey)) { - qCDebug(lcQpaKeyMapperKeys) << "Got scancode" << qtKey; - return qtKey; - } - - // Check if they belong to key codes in private unicode range - if (key >= NSUpArrowFunctionKey && key <= NSModeSwitchFunctionKey) { - if (auto qtKey = functionKeys.value(key)) { - qCDebug(lcQpaKeyMapperKeys) << "Got" << qtKey; - return qtKey; - } else if (key >= NSF1FunctionKey && key <= NSF35FunctionKey) { - auto functionKey = Qt::Key_F1 + (key.unicode() - NSF1FunctionKey) ; - qCDebug(lcQpaKeyMapperKeys) << "Got" << functionKey; - return functionKey; - } - } - - qCDebug(lcQpaKeyMapperKeys, "Unknown case.. %d[%d] %d", key.unicode(), key.toLatin1(), virtualKey); - return Qt::Key_unknown; -} - -QCocoaKeyMapper::QCocoaKeyMapper() -{ - memset(m_keyLayout, 0, sizeof(m_keyLayout)); -} - -QCocoaKeyMapper::~QCocoaKeyMapper() -{ - deleteLayouts(); -} - -Qt::KeyboardModifiers QCocoaKeyMapper::queryKeyboardModifiers() -{ - return fromCarbonModifiers(GetCurrentKeyModifiers()); -} - -bool QCocoaKeyMapper::updateKeyboard() -{ - QCFType<TISInputSourceRef> source = TISCopyInputMethodKeyboardLayoutOverride(); - if (!source) - source = TISCopyCurrentKeyboardInputSource(); - - if (m_keyboardMode != NullMode && source == m_currentInputSource) - return false; - - Q_ASSERT(source); - m_currentInputSource = source; - m_keyboardKind = LMGetKbdType(); - m_deadKeyState = 0; - - deleteLayouts(); - - if (auto data = CFDataRef(TISGetInputSourceProperty(source, kTISPropertyUnicodeKeyLayoutData))) { - const UCKeyboardLayout *uchrData = reinterpret_cast<const UCKeyboardLayout *>(CFDataGetBytePtr(data)); - Q_ASSERT(uchrData); - m_keyboardLayoutFormat = uchrData; - m_keyboardMode = UnicodeMode; - } else { - m_keyboardLayoutFormat = nullptr; - m_keyboardMode = NullMode; - } - - qCDebug(lcQpaKeyMapper) << "Updated keyboard to" - << QString::fromCFString(CFStringRef(TISGetInputSourceProperty( - m_currentInputSource, kTISPropertyLocalizedName))); - - 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; - } - } -} - -void QCocoaKeyMapper::clearMappings() -{ - deleteLayouts(); - updateKeyboard(); -} - -static constexpr Qt::KeyboardModifiers modifierCombinations[] = { - Qt::NoModifier, // 0 - Qt::ShiftModifier, // 1 - Qt::ControlModifier, // 2 - Qt::ControlModifier | Qt::ShiftModifier, // 3 - Qt::AltModifier, // 4 - Qt::AltModifier | Qt::ShiftModifier, // 5 - Qt::AltModifier | Qt::ControlModifier, // 6 - Qt::AltModifier | Qt::ShiftModifier | Qt::ControlModifier, // 7 - Qt::MetaModifier, // 8 - Qt::MetaModifier | Qt::ShiftModifier, // 9 - Qt::MetaModifier | Qt::ControlModifier, // 10 - Qt::MetaModifier | Qt::ControlModifier | Qt::ShiftModifier, // 11 - Qt::MetaModifier | Qt::AltModifier, // 12 - Qt::MetaModifier | Qt::AltModifier | Qt::ShiftModifier, // 13 - Qt::MetaModifier | Qt::AltModifier | Qt::ControlModifier, // 14 - Qt::MetaModifier | Qt::AltModifier | Qt::ShiftModifier | Qt::ControlModifier, // 15 -}; - -/* - Returns a key map for the given \macVirtualKey based on all - possible modifier combinations. -*/ -KeyboardLayoutItem *QCocoaKeyMapper::keyMapForKey(unsigned short macVirtualKey, QChar unicodeKey) const -{ - const_cast<QCocoaKeyMapper *>(this)->updateKeyboard(); - - Q_ASSERT(macVirtualKey < 256); - if (auto *existingKeyMap = m_keyLayout[macVirtualKey]) - return existingKeyMap; - - qCDebug(lcQpaKeyMapper, "Updating key map for virtual key = 0x%02x!", (uint)macVirtualKey); - - 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; - - auto qtModifiers = modifierCombinations[i]; - auto carbonModifiers = toCarbonModifiers(qtModifiers); - const UInt32 modifierKeyState = (carbonModifiers >> 8) & 0xFF; - OSStatus err = UCKeyTranslate(m_keyboardLayoutFormat, macVirtualKey, - kUCKeyActionDown, modifierKeyState, m_keyboardKind, OptionBits(0), - &m_deadKeyState, maxStringLength, &actualStringLength, unicodeString); - - // Use translated unicode key if valid - if (err == noErr && actualStringLength) - unicodeKey = QChar(unicodeString[0]); - - int qtkey = toKeyCode(unicodeKey, macVirtualKey, qtModifiers); - if (qtkey == Qt::Key_unknown) - qtkey = unicodeKey.unicode(); - - m_keyLayout[macVirtualKey]->qtKey[i] = qtkey; - - qCDebug(lcQpaKeyMapper, " [%d] (%d,0x%02x,'%c')", i, qtkey, qtkey, qtkey); - } - - return m_keyLayout[macVirtualKey]; -} - -QList<int> QCocoaKeyMapper::possibleKeys(const QKeyEvent *event) const -{ - QList<int> ret; - - auto *keyMap = keyMapForKey(event->nativeVirtualKey(), QChar(event->key())); - Q_ASSERT(keyMap); - - int baseKey = keyMap->qtKey[Qt::NoModifier]; - auto eventModifiers = event->modifiers(); - - // The base key is always valid - ret << int(baseKey + eventModifiers); - - for (int i = 1; i < 8; ++i) { - int keyAfterApplyingModifiers = keyMap->qtKey[i]; - if (!keyAfterApplyingModifiers) - continue; - if (keyAfterApplyingModifiers == baseKey) - continue; - - // Include key if event modifiers includes, or matches - // perfectly, the current candidate modifiers. - auto candidateModifiers = modifierCombinations[i]; - if ((eventModifiers & candidateModifiers) == candidateModifiers) - ret << int(keyAfterApplyingModifiers + (eventModifiers & ~candidateModifiers)); - } - - return ret; -} - -QT_END_NAMESPACE |