diff options
19 files changed, 274 insertions, 48 deletions
diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 979de8aadf..40c373c6d9 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -359,6 +359,7 @@ qt_internal_extend_target(Gui CONDITION MACOS platform/macos/qcocoanativeinterface.mm LIBRARIES ${FWAppKit} + ${FWCarbon} PUBLIC_LIBRARIES ${FWAppKit} ) @@ -369,6 +370,7 @@ qt_internal_extend_target(Gui CONDITION APPLE painting/qcoregraphics.mm painting/qcoregraphics_p.h painting/qrasterbackingstore.cpp painting/qrasterbackingstore_p.h platform/darwin/qmacmime.mm platform/darwin/qmacmime_p.h + platform/darwin/qapplekeymapper.mm platform/darwin/qapplekeymapper_p.h text/coretext/qcoretextfontdatabase.mm text/coretext/qcoretextfontdatabase_p.h text/coretext/qfontengine_coretext.mm text/coretext/qfontengine_coretext_p.h LIBRARIES diff --git a/src/gui/kernel/qshortcutmap.cpp b/src/gui/kernel/qshortcutmap.cpp index 2945115402..d83a00bc48 100644 --- a/src/gui/kernel/qshortcutmap.cpp +++ b/src/gui/kernel/qshortcutmap.cpp @@ -43,7 +43,8 @@ #include "qdebug.h" #include "qevent.h" #include "qlist.h" -#include "qcoreapplication.h" +#include "qguiapplication.h" +#include "qwindow.h" #include <private/qkeymapper_p.h> #include <QtCore/qloggingcategory.h> @@ -665,6 +666,46 @@ void QShortcutMap::dispatchEvent(QKeyEvent *e) QCoreApplication::sendEvent(const_cast<QObject *>(next->owner), &se); } +QList<QKeySequence> QShortcutMap::keySequences(bool getAll) const +{ + Q_D(const QShortcutMap); + QList<QKeySequence> keys; + for (auto sequence : d->sequences) { + bool addSequence = false; + if (sequence.enabled) { + if (getAll || sequence.context == Qt::ApplicationShortcut || + sequence.owner == QGuiApplication::focusObject()) { + addSequence = true; + } else { + QObject *possibleWindow = sequence.owner; + while (possibleWindow) { + if (qobject_cast<QWindow *>(possibleWindow)) + break; + possibleWindow = possibleWindow->parent(); + } + if (possibleWindow == QGuiApplication::focusWindow()) { + if (sequence.context == Qt::WindowShortcut) { + addSequence = true; + } else if (sequence.context == Qt::WidgetWithChildrenShortcut) { + QObject *possibleWidget = QGuiApplication::focusObject(); + while (possibleWidget->parent()) { + possibleWidget = possibleWidget->parent(); + if (possibleWidget == sequence.owner) { + addSequence = true; + break; + } + } + } + } + } + if (addSequence) + keys << sequence.keyseq; + } + } + return keys; + +} + /* \internal QShortcutMap dump function, only available when DEBUG_QSHORTCUTMAP is defined. diff --git a/src/gui/kernel/qshortcutmap_p.h b/src/gui/kernel/qshortcutmap_p.h index ff92a38e56..287549ea3a 100644 --- a/src/gui/kernel/qshortcutmap_p.h +++ b/src/gui/kernel/qshortcutmap_p.h @@ -86,6 +86,7 @@ public: bool tryShortcut(QKeyEvent *e); bool hasShortcutForKeySequence(const QKeySequence &seq) const; + QList<QKeySequence> keySequences(bool getAll = false) const; #ifdef Dump_QShortcutMap void dumpMap() const; diff --git a/src/plugins/platforms/cocoa/qcocoakeymapper.mm b/src/gui/platform/darwin/qapplekeymapper.mm index caa68ae694..c66fe784ed 100644 --- a/src/plugins/platforms/cocoa/qcocoakeymapper.mm +++ b/src/gui/platform/darwin/qapplekeymapper.mm @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2020 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. @@ -37,9 +37,17 @@ ** ****************************************************************************/ +#include <qglobal.h> + +#ifdef Q_OS_MACOS #include <AppKit/AppKit.h> +#endif + +#if defined(QT_PLATFORM_UIKIT) +#include <UIKit/UIKit.h> +#endif -#include "qcocoakeymapper.h" +#include "qapplekeymapper_p.h" #include <QtCore/qloggingcategory.h> #include <QtGui/QGuiApplication> @@ -65,6 +73,33 @@ static Qt::KeyboardModifiers swapModifiersIfNeeded(const Qt::KeyboardModifiers m return swappedModifiers; } +Qt::Key QAppleKeyMapper::fromNSString(Qt::KeyboardModifiers qtModifiers, NSString *characters, + NSString *charactersIgnoringModifiers) +{ + if ([characters isEqualToString:@"\t"]) { + if (qtModifiers & Qt::ShiftModifier) + return Qt::Key_Backtab; + return Qt::Key_Tab; + } else if ([characters isEqualToString:@"\r"]) { + if (qtModifiers & Qt::KeypadModifier) + return Qt::Key_Enter; + return Qt::Key_Return; + } + if ([characters length] != 0 || [charactersIgnoringModifiers length] != 0) { + QChar ch; + if (((qtModifiers & Qt::MetaModifier) || (qtModifiers & Qt::AltModifier)) && + ([charactersIgnoringModifiers length] != 0)) { + ch = QChar([charactersIgnoringModifiers characterAtIndex:0]); + } else if ([characters length] != 0) { + ch = QChar([characters characterAtIndex:0]); + } + if (!ch.isNull()) + return Qt::Key(ch.toUpper().unicode()); + } + return Qt::Key_unknown; +} + +#ifdef Q_OS_MACOS static constexpr std::tuple<NSEventModifierFlags, Qt::KeyboardModifier> cocoaModifierMap[] = { { NSEventModifierFlagShift, Qt::ShiftModifier }, { NSEventModifierFlagControl, Qt::ControlModifier }, @@ -73,7 +108,7 @@ static constexpr std::tuple<NSEventModifierFlags, Qt::KeyboardModifier> cocoaMod { NSEventModifierFlagNumericPad, Qt::KeypadModifier } }; -Qt::KeyboardModifiers QCocoaKeyMapper::fromCocoaModifiers(NSEventModifierFlags cocoaModifiers) +Qt::KeyboardModifiers QAppleKeyMapper::fromCocoaModifiers(NSEventModifierFlags cocoaModifiers) { Qt::KeyboardModifiers qtModifiers = Qt::NoModifier; for (const auto &[cocoaModifier, qtModifier] : cocoaModifierMap) { @@ -84,7 +119,7 @@ Qt::KeyboardModifiers QCocoaKeyMapper::fromCocoaModifiers(NSEventModifierFlags c return swapModifiersIfNeeded(qtModifiers); } -NSEventModifierFlags QCocoaKeyMapper::toCocoaModifiers(Qt::KeyboardModifiers qtModifiers) +NSEventModifierFlags QAppleKeyMapper::toCocoaModifiers(Qt::KeyboardModifiers qtModifiers) { qtModifiers = swapModifiersIfNeeded(qtModifiers); @@ -353,7 +388,7 @@ static const QHash<char16_t, Qt::Key> cocoaKeys = { { NSHelpFunctionKey, Qt::Key_Help }, }; -QChar QCocoaKeyMapper::toCocoaKey(Qt::Key key) +QChar QAppleKeyMapper::toCocoaKey(Qt::Key key) { // Prioritize overloaded keys if (key == Qt::Key_Return) @@ -371,7 +406,7 @@ QChar QCocoaKeyMapper::toCocoaKey(Qt::Key key) return reverseCocoaKeys.value(key); } -Qt::Key QCocoaKeyMapper::fromCocoaKey(QChar keyCode) +Qt::Key QAppleKeyMapper::fromCocoaKey(QChar keyCode) { if (auto key = cocoaKeys.value(keyCode.unicode())) return key; @@ -381,12 +416,12 @@ Qt::Key QCocoaKeyMapper::fromCocoaKey(QChar keyCode) // ------------------------------------------------ -Qt::KeyboardModifiers QCocoaKeyMapper::queryKeyboardModifiers() +Qt::KeyboardModifiers QAppleKeyMapper::queryKeyboardModifiers() { return fromCocoaModifiers(NSEvent.modifierFlags); } -bool QCocoaKeyMapper::updateKeyboard() +bool QAppleKeyMapper::updateKeyboard() { QCFType<TISInputSourceRef> source = TISCopyInputMethodKeyboardLayoutOverride(); if (!source) @@ -442,11 +477,11 @@ static constexpr Qt::KeyboardModifiers modifierCombinations[] = { Returns a key map for the given \virtualKey based on all possible modifier combinations. */ -const QCocoaKeyMapper::KeyMap &QCocoaKeyMapper::keyMapForKey(VirtualKeyCode virtualKey, QChar unicodeKey) const +const QAppleKeyMapper::KeyMap &QAppleKeyMapper::keyMapForKey(VirtualKeyCode virtualKey, QChar unicodeKey) const { static_assert(sizeof(modifierCombinations) / sizeof(Qt::KeyboardModifiers) == kNumModifierCombinations); - const_cast<QCocoaKeyMapper *>(this)->updateKeyboard(); + const_cast<QAppleKeyMapper *>(this)->updateKeyboard(); auto &keyMap = m_keyMap[virtualKey]; if (keyMap[Qt::NoModifier] != Qt::Key_unknown) @@ -509,7 +544,7 @@ const QCocoaKeyMapper::KeyMap &QCocoaKeyMapper::keyMapForKey(VirtualKeyCode virt return keyMap; } -QList<int> QCocoaKeyMapper::possibleKeys(const QKeyEvent *event) const +QList<int> QAppleKeyMapper::possibleKeys(const QKeyEvent *event) const { QList<int> ret; @@ -544,4 +579,75 @@ QList<int> QCocoaKeyMapper::possibleKeys(const QKeyEvent *event) const return ret; } + + +#else +// Keyboard keys (non-modifiers) +API_AVAILABLE(ios(13.4)) static QHash<NSString *, Qt::Key> uiKitKeys = { +#if QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_13_4) + { UIKeyInputF1, Qt::Key_F1 }, + { UIKeyInputF2, Qt::Key_F2 }, + { UIKeyInputF3, Qt::Key_F3 }, + { UIKeyInputF4, Qt::Key_F4 }, + { UIKeyInputF5, Qt::Key_F5 }, + { UIKeyInputF6, Qt::Key_F6 }, + { UIKeyInputF7, Qt::Key_F7 }, + { UIKeyInputF8, Qt::Key_F8 }, + { UIKeyInputF9, Qt::Key_F9 }, + { UIKeyInputF10, Qt::Key_F10 }, + { UIKeyInputF11, Qt::Key_F11 }, + { UIKeyInputF12, Qt::Key_F12 }, + { UIKeyInputHome, Qt::Key_Home }, + { UIKeyInputEnd, Qt::Key_End }, + { UIKeyInputPageUp, Qt::Key_PageUp }, + { UIKeyInputPageDown, Qt::Key_PageDown }, +#endif + { UIKeyInputEscape, Qt::Key_Escape }, + { UIKeyInputUpArrow, Qt::Key_Up }, + { UIKeyInputDownArrow, Qt::Key_Down }, + { UIKeyInputLeftArrow, Qt::Key_Left }, + { UIKeyInputRightArrow, Qt::Key_Right } +}; + +API_AVAILABLE(ios(13.4)) Qt::Key QAppleKeyMapper::fromUIKitKey(NSString *keyCode) +{ + if (auto key = uiKitKeys.value(keyCode)) + return key; + + return Qt::Key_unknown; +} + +static constexpr std::tuple<ulong, Qt::KeyboardModifier> uiKitModifierMap[] = { + { UIKeyModifierShift, Qt::ShiftModifier }, + { UIKeyModifierControl, Qt::ControlModifier }, + { UIKeyModifierCommand, Qt::MetaModifier }, + { UIKeyModifierAlternate, Qt::AltModifier }, + { UIKeyModifierNumericPad, Qt::KeypadModifier } +}; + +ulong QAppleKeyMapper::toUIKitModifiers(Qt::KeyboardModifiers qtModifiers) +{ + qtModifiers = swapModifiersIfNeeded(qtModifiers); + + ulong nativeModifiers = 0; + for (const auto &[nativeModifier, qtModifier] : uiKitModifierMap) { + if (qtModifiers & qtModifier) + nativeModifiers |= nativeModifier; + } + + return nativeModifiers; +} + +Qt::KeyboardModifiers QAppleKeyMapper::fromUIKitModifiers(ulong nativeModifiers) +{ + Qt::KeyboardModifiers qtModifiers = Qt::NoModifier; + for (const auto &[nativeModifier, qtModifier] : uiKitModifierMap) { + if (nativeModifiers & nativeModifier) + qtModifiers |= qtModifier; + } + + return swapModifiersIfNeeded(qtModifiers); +} +#endif + QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoakeymapper.h b/src/gui/platform/darwin/qapplekeymapper_p.h index dbf164c18e..8664ab378b 100644 --- a/src/plugins/platforms/cocoa/qcocoakeymapper.h +++ b/src/gui/platform/darwin/qapplekeymapper_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. @@ -37,10 +37,12 @@ ** ****************************************************************************/ -#ifndef QCOCOAKEYMAPPER_H -#define QCOCOAKEYMAPPER_H +#ifndef QAPPLEKEYMAPPER_H +#define QAPPLEKEYMAPPER_H +#ifdef Q_OS_MACOS #include <Carbon/Carbon.h> +#endif #include <QtCore/QList> #include <QtGui/QKeyEvent> @@ -49,19 +51,26 @@ QT_BEGIN_NAMESPACE -class QCocoaKeyMapper +class Q_GUI_EXPORT QAppleKeyMapper { public: static Qt::KeyboardModifiers queryKeyboardModifiers(); QList<int> possibleKeys(const QKeyEvent *event) const; - + static Qt::Key fromNSString(Qt::KeyboardModifiers qtMods, NSString *characters, + NSString *charactersIgnoringModifiers); +#ifdef Q_OS_MACOS static Qt::KeyboardModifiers fromCocoaModifiers(NSEventModifierFlags cocoaModifiers); static NSEventModifierFlags toCocoaModifiers(Qt::KeyboardModifiers); static QChar toCocoaKey(Qt::Key key); static Qt::Key fromCocoaKey(QChar keyCode); - +#else + static Qt::Key fromUIKitKey(NSString *keyCode); + static Qt::KeyboardModifiers fromUIKitModifiers(ulong uikitModifiers); + static ulong toUIKitModifiers(Qt::KeyboardModifiers); +#endif private: +#ifdef Q_OS_MACOS static constexpr int kNumModifierCombinations = 16; struct KeyMap : std::array<char32_t, kNumModifierCombinations> { @@ -85,6 +94,7 @@ private: mutable UInt32 m_deadKeyState = 0; // Maintains dead key state beween calls to UCKeyTranslate mutable QHash<VirtualKeyCode, KeyMap> m_keyMap; +#endif }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/CMakeLists.txt b/src/plugins/platforms/cocoa/CMakeLists.txt index d9832c2c6c..8dbf534c9b 100644 --- a/src/plugins/platforms/cocoa/CMakeLists.txt +++ b/src/plugins/platforms/cocoa/CMakeLists.txt @@ -26,7 +26,6 @@ qt_internal_add_plugin(QCocoaIntegrationPlugin qcocoainputcontext.h qcocoainputcontext.mm qcocoaintegration.h qcocoaintegration.mm qcocoaintrospection.h qcocoaintrospection.mm - qcocoakeymapper.h qcocoakeymapper.mm qcocoamenu.h qcocoamenu.mm qcocoamenubar.h qcocoamenubar.mm qcocoamenuitem.h qcocoamenuitem.mm diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm index e6e46cda81..40d8f639fc 100644 --- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm +++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm @@ -371,7 +371,7 @@ QT_USE_NAMESPACE return; QScopedScopeLevelCounter scopeLevelCounter(QGuiApplicationPrivate::instance()->threadData.loadRelaxed()); - QGuiApplicationPrivate::modifier_buttons = QCocoaKeyMapper::fromCocoaModifiers([NSEvent modifierFlags]); + QGuiApplicationPrivate::modifier_buttons = QAppleKeyMapper::fromCocoaModifiers([NSEvent modifierFlags]); static QMetaMethod activatedSignal = QMetaMethod::fromSignal(&QCocoaMenuItem::activated); activatedSignal.invoke(platformItem, Qt::QueuedConnection); diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.h b/src/plugins/platforms/cocoa/qcocoaintegration.h index 4f1969dd98..caf47e38d3 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.h +++ b/src/plugins/platforms/cocoa/qcocoaintegration.h @@ -48,7 +48,6 @@ #include "qcocoaclipboard.h" #include "qcocoadrag.h" #include "qcocoaservices.h" -#include "qcocoakeymapper.h" #if QT_CONFIG(vulkan) #include "qcocoavulkaninstance.h" #endif @@ -57,6 +56,7 @@ #include <qpa/qplatformintegration.h> #include <QtGui/private/qcoretextfontdatabase_p.h> #include <QtGui/private/qopenglcontext_p.h> +#include <QtGui/private/qapplekeymapper_p.h> Q_FORWARD_DECLARE_OBJC_CLASS(NSToolbar); @@ -156,7 +156,7 @@ private: QScopedPointer<QCocoaDrag> mCocoaDrag; QScopedPointer<QCocoaNativeInterface> mNativeInterface; QScopedPointer<QCocoaServices> mServices; - QScopedPointer<QCocoaKeyMapper> mKeyboardMapper; + QScopedPointer<QAppleKeyMapper> mKeyboardMapper; #if QT_CONFIG(vulkan) mutable QCocoaVulkanInstance *mCocoaVulkanInstance = nullptr; diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index 872d9bb7f1..1ab30df7e8 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -136,7 +136,7 @@ QCocoaIntegration::QCocoaIntegration(const QStringList ¶mList) , mCocoaDrag(new QCocoaDrag) , mNativeInterface(new QCocoaNativeInterface) , mServices(new QCocoaServices) - , mKeyboardMapper(new QCocoaKeyMapper) + , mKeyboardMapper(new QAppleKeyMapper) { logVersionInformation(); @@ -420,7 +420,7 @@ QVariant QCocoaIntegration::styleHint(StyleHint hint) const Qt::KeyboardModifiers QCocoaIntegration::queryKeyboardModifiers() const { - return QCocoaKeyMapper::queryKeyboardModifiers(); + return QAppleKeyMapper::queryKeyboardModifiers(); } QList<int> QCocoaIntegration::possibleKeys(const QKeyEvent *event) const diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.mm b/src/plugins/platforms/cocoa/qcocoamenuitem.mm index 4806b244c3..f11d7bd996 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuitem.mm +++ b/src/plugins/platforms/cocoa/qcocoamenuitem.mm @@ -50,9 +50,9 @@ #include "qcocoahelpers.h" #include "qcocoaapplication.h" // for custom application category #include "qcocoamenuloader.h" -#include "qcocoakeymapper.h" #include <QtGui/private/qcoregraphics_p.h> #include <QtCore/qregularexpression.h> +#include <QtGui/private/qapplekeymapper_p.h> #include <QtCore/QDebug> @@ -356,7 +356,7 @@ NSMenuItem *QCocoaMenuItem::sync() auto key = accel[0].key(); auto modifiers = accel[0].keyboardModifiers(); - QChar cocoaKey = QCocoaKeyMapper::toCocoaKey(key); + QChar cocoaKey = QAppleKeyMapper::toCocoaKey(key); if (cocoaKey.isNull()) cocoaKey = QChar(key).toLower().unicode(); // Similar to qt_mac_removePrivateUnicode change the delete key, @@ -365,7 +365,7 @@ NSMenuItem *QCocoaMenuItem::sync() cocoaKey = QChar(NSDeleteCharacter); m_native.keyEquivalent = QStringView(&cocoaKey, 1).toNSString(); - m_native.keyEquivalentModifierMask = QCocoaKeyMapper::toCocoaModifiers(modifiers); + m_native.keyEquivalentModifierMask = QAppleKeyMapper::toCocoaModifiers(modifiers); } else #endif { diff --git a/src/plugins/platforms/cocoa/qcocoansmenu.mm b/src/plugins/platforms/cocoa/qcocoansmenu.mm index b94d31251e..6760ae59ff 100644 --- a/src/plugins/platforms/cocoa/qcocoansmenu.mm +++ b/src/plugins/platforms/cocoa/qcocoansmenu.mm @@ -46,10 +46,10 @@ #include "qcocoawindow.h" #include "qnsview.h" #include "qcocoahelpers.h" -#include "qcocoakeymapper.h" #include <QtCore/qcoreapplication.h> #include <QtCore/qcoreevent.h> +#include <QtGui/private/qapplekeymapper_p.h> static NSString *qt_mac_removePrivateUnicode(NSString *string) { @@ -254,7 +254,7 @@ static NSString *qt_mac_removePrivateUnicode(NSString *string) QChar ch; int keyCode; ulong nativeModifiers = event.modifierFlags; - Qt::KeyboardModifiers modifiers = QCocoaKeyMapper::fromCocoaModifiers(nativeModifiers); + Qt::KeyboardModifiers modifiers = QAppleKeyMapper::fromCocoaModifiers(nativeModifiers); NSString *charactersIgnoringModifiers = event.charactersIgnoringModifiers; NSString *characters = event.characters; @@ -264,7 +264,7 @@ static NSString *qt_mac_removePrivateUnicode(NSString *string) } else { ch = QChar([charactersIgnoringModifiers characterAtIndex:0]); } - keyCode = QCocoaKeyMapper::fromCocoaKey(ch); + keyCode = QAppleKeyMapper::fromCocoaKey(ch); } else { // might be a dead key ch = QChar::ReplacementCharacter; diff --git a/src/plugins/platforms/cocoa/qnsview_dragging.mm b/src/plugins/platforms/cocoa/qnsview_dragging.mm index d4ab5f4a24..945217e928 100644 --- a/src/plugins/platforms/cocoa/qnsview_dragging.mm +++ b/src/plugins/platforms/cocoa/qnsview_dragging.mm @@ -197,7 +197,7 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin if (!target) return NSDragOperationNone; - const auto modifiers = QCocoaKeyMapper::fromCocoaModifiers(NSApp.currentEvent.modifierFlags); + const auto modifiers = QAppleKeyMapper::fromCocoaModifiers(NSApp.currentEvent.modifierFlags); const auto buttons = currentlyPressedMouseButtons(); const auto point = mapWindowCoordinates(m_platformWindow->window(), target, windowPoint); @@ -261,7 +261,7 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin QPlatformDropQtResponse response(false, Qt::IgnoreAction); QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag(); - const auto modifiers = QCocoaKeyMapper::fromCocoaModifiers(NSApp.currentEvent.modifierFlags); + const auto modifiers = QAppleKeyMapper::fromCocoaModifiers(NSApp.currentEvent.modifierFlags); const auto buttons = currentlyPressedMouseButtons(); const auto point = mapWindowCoordinates(m_platformWindow->window(), target, windowPoint); @@ -302,7 +302,7 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin // this case won't send the matching release event, so we have to // synthesize it here. m_buttons = currentlyPressedMouseButtons(); - const auto modifiers = QCocoaKeyMapper::fromCocoaModifiers(NSApp.currentEvent.modifierFlags); + const auto modifiers = QAppleKeyMapper::fromCocoaModifiers(NSApp.currentEvent.modifierFlags); NSPoint windowPoint = [self.window convertRectFromScreen:NSMakeRect(screenPoint.x, screenPoint.y, 1, 1)].origin; NSPoint nsViewPoint = [self convertPoint: windowPoint fromView: nil]; diff --git a/src/plugins/platforms/cocoa/qnsview_keys.mm b/src/plugins/platforms/cocoa/qnsview_keys.mm index 09d78485f4..23b8254d63 100644 --- a/src/plugins/platforms/cocoa/qnsview_keys.mm +++ b/src/plugins/platforms/cocoa/qnsview_keys.mm @@ -45,7 +45,7 @@ { ulong timestamp = [nsevent timestamp] * 1000; ulong nativeModifiers = [nsevent modifierFlags]; - Qt::KeyboardModifiers modifiers = QCocoaKeyMapper::fromCocoaModifiers(nativeModifiers); + Qt::KeyboardModifiers modifiers = QAppleKeyMapper::fromCocoaModifiers(nativeModifiers); NSString *charactersIgnoringModifiers = [nsevent charactersIgnoringModifiers]; NSString *characters = [nsevent characters]; if (m_inputSource != characters) { @@ -74,7 +74,7 @@ ch = QChar([charactersIgnoringModifiers characterAtIndex:0]); else if ([characters length] != 0) ch = QChar([characters characterAtIndex:0]); - keyCode = QCocoaKeyMapper::fromCocoaKey(ch); + keyCode = QAppleKeyMapper::fromCocoaKey(ch); } // we will send a key event unless the input method sets m_sendKeyEvent to false @@ -194,7 +194,7 @@ { ulong timestamp = [nsevent timestamp] * 1000; ulong nativeModifiers = [nsevent modifierFlags]; - Qt::KeyboardModifiers modifiers = QCocoaKeyMapper::fromCocoaModifiers(nativeModifiers); + Qt::KeyboardModifiers modifiers = QAppleKeyMapper::fromCocoaModifiers(nativeModifiers); // Scan codes are hardware dependent codes for each key. There is no way to get these // from Carbon or Cocoa, so leave it 0, as documented in QKeyEvent::nativeScanCode(). @@ -238,7 +238,7 @@ (lastKnownModifiers & mac_mask) ? QEvent::KeyRelease : QEvent::KeyPress, qtCode, - modifiers ^ QCocoaKeyMapper::fromCocoaModifiers(mac_mask), + modifiers ^ QAppleKeyMapper::fromCocoaModifiers(mac_mask), nativeScanCode, nativeVirtualKey, nativeModifiers ^ mac_mask); } diff --git a/src/plugins/platforms/cocoa/qnsview_mouse.mm b/src/plugins/platforms/cocoa/qnsview_mouse.mm index 336f1085b9..d00cfb7886 100644 --- a/src/plugins/platforms/cocoa/qnsview_mouse.mm +++ b/src/plugins/platforms/cocoa/qnsview_mouse.mm @@ -279,7 +279,7 @@ QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag(); nativeDrag->setLastMouseEvent(theEvent, self); - const auto modifiers = QCocoaKeyMapper::fromCocoaModifiers(theEvent.modifierFlags); + const auto modifiers = QAppleKeyMapper::fromCocoaModifiers(theEvent.modifierFlags); auto button = cocoaButton2QtButton(theEvent); if (button == Qt::LeftButton && m_sendUpAsRightButton) button = Qt::RightButton; @@ -678,7 +678,7 @@ // after scrolling in Qt Creator: not taking the phase into account causes // the end of the event stream to be interpreted as font size changes. if (theEvent.momentumPhase == NSEventPhaseNone) - m_currentWheelModifiers = QCocoaKeyMapper::fromCocoaModifiers(theEvent.modifierFlags); + m_currentWheelModifiers = QAppleKeyMapper::fromCocoaModifiers(theEvent.modifierFlags); // "isInverted": natural OS X scrolling, inverted from the Qt/other platform/Jens perspective. bool isInverted = [theEvent isDirectionInvertedFromDevice]; diff --git a/src/plugins/platforms/cocoa/qnsview_tablet.mm b/src/plugins/platforms/cocoa/qnsview_tablet.mm index 804c502775..2b269d038a 100644 --- a/src/plugins/platforms/cocoa/qnsview_tablet.mm +++ b/src/plugins/platforms/cocoa/qnsview_tablet.mm @@ -109,7 +109,7 @@ Q_GLOBAL_STATIC(QCocoaTabletDeviceDataHash, tabletDeviceDataHash) if (rotation > 180.0) rotation -= 360.0; - Qt::KeyboardModifiers keyboardModifiers = QCocoaKeyMapper::fromCocoaModifiers(theEvent.modifierFlags); + Qt::KeyboardModifiers keyboardModifiers = QAppleKeyMapper::fromCocoaModifiers(theEvent.modifierFlags); Qt::MouseButtons buttons = ignoreButtonMapping ? static_cast<Qt::MouseButtons>(static_cast<uint>([theEvent buttonMask])) : m_buttons; qCDebug(lcQpaTablet, "event on tablet %d with tool %d type %d unique ID %lld pos %6.1f, %6.1f root pos %6.1f, %6.1f buttons 0x%x pressure %4.2lf tilt %d, %d rotation %6.2lf", diff --git a/src/plugins/platforms/ios/qiosviewcontroller.h b/src/plugins/platforms/ios/qiosviewcontroller.h index 7af4c83b48..79fe5ae3c5 100644 --- a/src/plugins/platforms/ios/qiosviewcontroller.h +++ b/src/plugins/platforms/ios/qiosviewcontroller.h @@ -50,6 +50,8 @@ QT_END_NAMESPACE - (instancetype)initWithQIOSScreen:(QT_PREPEND_NAMESPACE(QIOSScreen) *)screen; - (void)updateProperties; +- (NSArray*)keyCommands; +- (void)handleShortcut:(UIKeyCommand*)keyCommand; #ifndef Q_OS_TVOS @property (nonatomic, assign) UIInterfaceOrientation lockedOrientation; diff --git a/src/plugins/platforms/ios/qiosviewcontroller.mm b/src/plugins/platforms/ios/qiosviewcontroller.mm index cd4af46ef7..7d994f4394 100644 --- a/src/plugins/platforms/ios/qiosviewcontroller.mm +++ b/src/plugins/platforms/ios/qiosviewcontroller.mm @@ -42,12 +42,14 @@ #include <QtCore/qscopedvaluerollback.h> #include <QtCore/private/qcore_mac_p.h> +#include <QtGui/private/qapplekeymapper_p.h> #include <QtGui/QGuiApplication> #include <QtGui/QWindow> #include <QtGui/QScreen> #include <QtGui/private/qwindow_p.h> +#include <QtGui/private/qguiapplication_p.h> #include "qiosintegration.h" #include "qiosscreen.h" @@ -523,5 +525,36 @@ #endif } +- (NSArray*)keyCommands +{ + // FIXME: If we are on iOS 13.4 or later we can use UIKey instead of doing this + // So it should be safe to remove this entire function and handleShortcut() as + // a result + NSMutableArray<UIKeyCommand *> *keyCommands = nil; + QShortcutMap &shortcutMap = QGuiApplicationPrivate::instance()->shortcutMap; + keyCommands = [[NSMutableArray<UIKeyCommand *> alloc] init]; + const QList<QKeySequence> keys = shortcutMap.keySequences(); + for (const QKeySequence &seq : keys) { + const QString keyString = seq.toString(); + [keyCommands addObject:[UIKeyCommand + keyCommandWithInput:QString(keyString[keyString.length() - 1]).toNSString() + modifierFlags:QAppleKeyMapper::toUIKitModifiers(seq[0].keyboardModifiers()) + action:@selector(handleShortcut:)]]; + } + return keyCommands; +} + +- (void)handleShortcut:(UIKeyCommand *)keyCommand +{ + const QString str = QString::fromNSString([keyCommand input]); + Qt::KeyboardModifiers qtMods = QAppleKeyMapper::fromUIKitModifiers(keyCommand.modifierFlags); + QChar ch = str.isEmpty() ? QChar() : str.at(0); + QShortcutMap &shortcutMap = QGuiApplicationPrivate::instance()->shortcutMap; + QKeyEvent keyEvent(QEvent::ShortcutOverride, Qt::Key(ch.toUpper().unicode()), qtMods, str); + shortcutMap.tryShortcut(&keyEvent); +} + + + @end diff --git a/src/plugins/platforms/ios/quiview.h b/src/plugins/platforms/ios/quiview.h index 1ab9481dd6..6a8e5a7707 100644 --- a/src/plugins/platforms/ios/quiview.h +++ b/src/plugins/platforms/ios/quiview.h @@ -56,6 +56,7 @@ QT_END_NAMESPACE - (instancetype)initWithQIOSWindow:(QT_PREPEND_NAMESPACE(QIOSWindow) *)window; - (void)sendUpdatedExposeEvent; - (BOOL)isActiveWindow; +- (bool)handlePresses:(NSSet<UIPress *> *)presses eventType:(QEvent::Type)type; @property (nonatomic, assign) QT_PREPEND_NAMESPACE(QIOSWindow) *platformWindow; @end diff --git a/src/plugins/platforms/ios/quiview.mm b/src/plugins/platforms/ios/quiview.mm index 4c56e03f42..5ca4d5ccc8 100644 --- a/src/plugins/platforms/ios/quiview.mm +++ b/src/plugins/platforms/ios/quiview.mm @@ -52,6 +52,7 @@ #include <QtGui/qpointingdevice.h> #include <QtGui/private/qguiapplication_p.h> #include <QtGui/private/qwindow_p.h> +#include <QtGui/private/qapplekeymapper_p.h> #include <qpa/qwindowsysteminterface_p.h> Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet") @@ -571,7 +572,7 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet") QWindowSystemInterface::handleTouchCancelEvent(self.platformWindow->window(), ulong(timestamp * 1000), iosIntegration->touchDevice()); } -- (int)mapPressTypeToKey:(UIPress*)press +- (int)mapPressTypeToKey:(UIPress*)press withModifiers:(Qt::KeyboardModifiers)qtModifiers { switch (press.type) { case UIPressTypeUpArrow: return Qt::Key_Up; @@ -582,6 +583,16 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet") case UIPressTypeMenu: return Qt::Key_Menu; case UIPressTypePlayPause: return Qt::Key_MediaTogglePlayPause; } +#if QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_13_4) + if (@available(ios 13.4, *)) { + NSString *charactersIgnoringModifiers = press.key.charactersIgnoringModifiers; + Qt::Key key = QAppleKeyMapper::fromUIKitKey(charactersIgnoringModifiers); + if (key != Qt::Key_unknown) + return key; + return QAppleKeyMapper::fromNSString(qtModifiers, press.key.characters, + charactersIgnoringModifiers); + } +#endif return Qt::Key_unknown; } @@ -593,32 +604,52 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet") bool handled = false; for (UIPress* press in presses) { - int key = [self mapPressTypeToKey:press]; + Qt::KeyboardModifiers qtModifiers = Qt::NoModifier; +#if QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_13_4) + if (@available(ios 13.4, *)) + qtModifiers = QAppleKeyMapper::fromUIKitModifiers(press.key.modifierFlags); +#endif + int key = [self mapPressTypeToKey:press withModifiers:qtModifiers]; if (key == Qt::Key_unknown) continue; - if (QWindowSystemInterface::handleKeyEvent(self.platformWindow->window(), type, key, Qt::NoModifier)) + if (QWindowSystemInterface::handleKeyEvent(self.platformWindow->window(), type, key, qtModifiers)) handled = true; } return handled; } +- (BOOL)handlePresses:(NSSet<UIPress *> *)presses eventType:(QEvent::Type)type +{ + bool handlePress = false; + if (qApp->focusWindow()) { + QInputMethodQueryEvent queryEvent(Qt::ImEnabled); + if (qApp->focusObject() && QCoreApplication::sendEvent(qApp->focusObject(), &queryEvent)) + handlePress = queryEvent.value(Qt::ImEnabled).toBool(); + if (!handlePress && [self processPresses:presses withType:type]) + return true; + } + return false; +} + - (void)pressesBegan:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event { - if (![self processPresses:presses withType:QEvent::KeyPress]) + if (![self handlePresses:presses eventType:QEvent::KeyPress]) [super pressesBegan:presses withEvent:event]; } - (void)pressesChanged:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event { - if (![self processPresses:presses withType:QEvent::KeyPress]) - [super pressesChanged:presses withEvent:event]; + if (![self handlePresses:presses eventType:QEvent::KeyPress]) + [super pressesBegan:presses withEvent:event]; + [super pressesChanged:presses withEvent:event]; } - (void)pressesEnded:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event { - if (![self processPresses:presses withType:QEvent::KeyRelease]) - [super pressesEnded:presses withEvent:event]; + if (![self handlePresses:presses eventType:QEvent::KeyRelease]) + [super pressesBegan:presses withEvent:event]; + [super pressesEnded:presses withEvent:event]; } - (BOOL)canPerformAction:(SEL)action withSender:(id)sender |