diff options
author | Andy Shaw <andy.shaw@qt.io> | 2020-12-04 15:04:49 +0100 |
---|---|---|
committer | Andy Shaw <andy.shaw@qt.io> | 2021-01-20 12:29:38 +0100 |
commit | 15576c961047231a49afda9b9ee0159ba132c0ae (patch) | |
tree | d2ff922cd5a3f910471d69380ea12ce99155a212 /src/plugins/platforms/ios | |
parent | a5bb7b3ca510c301baf84e1dd46d5aeeb4986eb2 (diff) |
iOS: Handle keyboard events when using an external keyboard
This enables the two possible approaches for handling external keyboard
events. While support still exists for before 13.4 then both approaches
are needed. This ensures that all external keyboard events are handled
as key events and passed on accordingly. Additionally, this accounts
for possible shortcuts too, therefore a new function is added to
QShortcutMap to aid that.
As a result, code has now moved from QCocoaKeyMapper to be part of the
gui/platforms/darwin part to make it easier to reuse this code
elsewhere.
Fixes: QTBUG-85727
Change-Id: I349af43468b03fd8dcb16adba02669974affe154
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
Diffstat (limited to 'src/plugins/platforms/ios')
-rw-r--r-- | src/plugins/platforms/ios/qiosviewcontroller.h | 2 | ||||
-rw-r--r-- | src/plugins/platforms/ios/qiosviewcontroller.mm | 33 | ||||
-rw-r--r-- | src/plugins/platforms/ios/quiview.h | 1 | ||||
-rw-r--r-- | src/plugins/platforms/ios/quiview.mm | 47 |
4 files changed, 75 insertions, 8 deletions
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 |