diff options
Diffstat (limited to 'src/plugins/platforms/cocoa/qnsview_keys.mm')
-rw-r--r-- | src/plugins/platforms/cocoa/qnsview_keys.mm | 79 |
1 files changed, 66 insertions, 13 deletions
diff --git a/src/plugins/platforms/cocoa/qnsview_keys.mm b/src/plugins/platforms/cocoa/qnsview_keys.mm index 068635e20d..abee622e65 100644 --- a/src/plugins/platforms/cocoa/qnsview_keys.mm +++ b/src/plugins/platforms/cocoa/qnsview_keys.mm @@ -3,8 +3,63 @@ // This file is included from qnsview.mm, and only used to organize the code +/* + Determines if the text represents one of the "special keys" on macOS + + As a legacy from OpenStep, macOS reserves the range 0xF700-0xF8FF of the + Unicode private use area for representing function keys on the keyboard: + + http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/CORPCHAR.TXT + + https://developer.apple.com/documentation/appkit/nsevent/specialkey + + These code points are not supposed to have any glyphs associated with them, + but since we can't guarantee that the system doesn't have a font that does + provide glyphs for this range (Arial Unicode MS e.g.) we need to filter + the text of our key events up front. +*/ +static bool isSpecialKey(const QString &text) +{ + if (text.length() != 1) + return false; + + const char16_t unicode = text.at(0).unicode(); + if (unicode >= 0xF700 && unicode <= 0xF8FF) + return true; + + return false; +} + +static bool sendAsShortcut(const KeyEvent &keyEvent, QWindow *window) +{ + KeyEvent shortcutEvent = keyEvent; + shortcutEvent.type = QEvent::Shortcut; + qCDebug(lcQpaKeys) << "Trying potential shortcuts in" << window + << "for" << shortcutEvent; + + if (shortcutEvent.sendWindowSystemEvent(window)) { + qCDebug(lcQpaKeys) << "Found matching shortcut; will not send as key event"; + return true; + } + qCDebug(lcQpaKeys) << "No matching shortcuts; continuing with key event delivery"; + return false; +} + @implementation QNSView (Keys) +- (bool)performKeyEquivalent:(NSEvent *)nsevent +{ + // Implemented to handle shortcuts for modified Tab keys, which are + // handled by Cocoa and not delivered to your keyDown implementation. + if (nsevent.type == NSEventTypeKeyDown && m_composingText.isEmpty()) { + const bool ctrlDown = [nsevent modifierFlags] & NSEventModifierFlagControl; + const bool isTabKey = nsevent.keyCode == kVK_Tab; + if (ctrlDown && isTabKey && sendAsShortcut(KeyEvent(nsevent), [self topLevelWindow])) + return YES; + } + return NO; +} + - (bool)handleKeyEvent:(NSEvent *)nsevent { qCDebug(lcQpaKeys) << "Handling" << nsevent; @@ -20,20 +75,13 @@ // otherwise by doCommandBySelector. m_sendKeyEventWithoutText = false; + bool didInterpretKeyEvent = false; + if (keyEvent.type == QEvent::KeyPress) { if (m_composingText.isEmpty()) { - KeyEvent shortcutEvent = keyEvent; - shortcutEvent.type = QEvent::Shortcut; - qCDebug(lcQpaKeys) << "Trying potential shortcuts in" << window - << "for" << shortcutEvent; - - if (shortcutEvent.sendWindowSystemEvent(window)) { - qCDebug(lcQpaKeys) << "Found matching shortcut; will not send as key event"; + if (sendAsShortcut(keyEvent, window)) return true; - } else { - qCDebug(lcQpaKeys) << "No matching shortcuts; continuing with key event delivery"; - } } QObject *focusObject = m_platformWindow ? m_platformWindow->window()->focusObject() : nullptr; @@ -65,8 +113,12 @@ qCDebug(lcQpaKeys) << "Interpreting key event for focus object" << focusObject; m_currentlyInterpretedKeyEvent = nsevent; - [self interpretKeyEvents:@[nsevent]]; + if (![self.inputContext handleEvent:nsevent]) { + qCDebug(lcQpaKeys) << "Input context did not consume event"; + m_sendKeyEvent = true; + } m_currentlyInterpretedKeyEvent = 0; + didInterpretKeyEvent = true; // If the last key we sent was dead, then pass the next // key to the IM as well to complete composition. @@ -79,8 +131,9 @@ bool accepted = true; if (m_sendKeyEvent && m_composingText.isEmpty()) { - KeyEvent keyEvent(nsevent); - if (m_sendKeyEventWithoutText) + // Trust text input system on whether to send the event with text or not, + // or otherwise apply heuristics to filter out private use symbols. + if (didInterpretKeyEvent ? m_sendKeyEventWithoutText : isSpecialKey(keyEvent.text)) keyEvent.text = {}; qCDebug(lcQpaKeys) << "Sending as" << keyEvent; accepted = keyEvent.sendWindowSystemEvent(window); |