diff options
Diffstat (limited to 'src/plugins/platforms/cocoa/qnsview_complextext.mm')
-rw-r--r-- | src/plugins/platforms/cocoa/qnsview_complextext.mm | 84 |
1 files changed, 61 insertions, 23 deletions
diff --git a/src/plugins/platforms/cocoa/qnsview_complextext.mm b/src/plugins/platforms/cocoa/qnsview_complextext.mm index 7c50ec7ece..d7f8f4baf0 100644 --- a/src/plugins/platforms/cocoa/qnsview_complextext.mm +++ b/src/plugins/platforms/cocoa/qnsview_complextext.mm @@ -7,6 +7,17 @@ // ------------- Text insertion ------------- +- (QObject*)focusObject +{ + // The text input system may still hold a reference to our QNSView, + // even after QCocoaWindow has been destructed, delivering text input + // events to us, so we need to guard for this situation explicitly. + if (!m_platformWindow) + return nullptr; + + return m_platformWindow->window()->focusObject(); +} + /* Inserts the given text, potentially replacing existing text. @@ -52,8 +63,7 @@ } } - QObject *focusObject = m_platformWindow->window()->focusObject(); - if (queryInputMethod(focusObject)) { + if (queryInputMethod(self.focusObject)) { QInputMethodEvent inputMethodEvent; const bool isAttributedString = [text isKindOfClass:NSAttributedString.class]; @@ -75,7 +85,7 @@ inputMethodEvent.setCommitString(commitString, replaceFrom, replaceLength); } - QCoreApplication::sendEvent(focusObject, &inputMethodEvent); + QCoreApplication::sendEvent(self.focusObject, &inputMethodEvent); } m_composingText.clear(); @@ -86,6 +96,9 @@ { Q_UNUSED(sender); + if (!m_platformWindow) + return; + // Depending on the input method, pressing enter may // result in simply dismissing the input method editor, // without confirming the composition. In other cases @@ -117,8 +130,8 @@ newlineEvent.key = isEnter ? Qt::Key_Enter : Qt::Key_Return; newlineEvent.text = isEnter ? QLatin1Char(kEnterCharCode) : QLatin1Char(kReturnCharCode); - newlineEvent.nativeVirtualKey = isEnter ? kVK_ANSI_KeypadEnter - : kVK_Return; + newlineEvent.nativeVirtualKey = isEnter ? quint32(kVK_ANSI_KeypadEnter) + : quint32(kVK_Return); qCDebug(lcQpaKeys) << "Inserting newline via" << newlineEvent; newlineEvent.sendWindowSystemEvent(m_platformWindow->window()); @@ -242,7 +255,7 @@ // Update the composition, now that we've computed the replacement range m_composingText = preeditString; - if (QObject *focusObject = m_platformWindow->window()->focusObject()) { + if (QObject *focusObject = self.focusObject) { m_composingFocusObject = focusObject; if (queryInputMethod(focusObject)) { QInputMethodEvent event(preeditString, preeditAttributes); @@ -284,8 +297,7 @@ */ - (NSRange)markedRange { - QObject *focusObject = m_platformWindow->window()->focusObject(); - if (auto queryResult = queryInputMethod(focusObject, Qt::ImAbsolutePosition)) { + if (auto queryResult = queryInputMethod(self.focusObject, Qt::ImAbsolutePosition)) { int absoluteCursorPosition = queryResult.value(Qt::ImAbsolutePosition).toInt(); // The cursor position as reflected by Qt::ImAbsolutePosition is not @@ -320,7 +332,7 @@ << "for focus object" << m_composingFocusObject; if (!m_composingText.isEmpty()) { - QObject *focusObject = m_platformWindow->window()->focusObject(); + QObject *focusObject = self.focusObject; if (queryInputMethod(focusObject)) { QInputMethodEvent e; e.setCommitString(m_composingText); @@ -370,14 +382,16 @@ if (![self tryToPerform:selector with:self]) { m_sendKeyEvent = true; - // The text input system determined that the key event was not - // meant for text insertion, and instead asked us to treat it - // as a (possibly noop) command. This typically happens for key - // events with either ⌘ or ⌃, function keys such as F1-F35, - // arrow keys, etc. We reflect that when sending the key event - // later on, by removing the text from the event, so that the - // event does not result in text insertion on the client side. - m_sendKeyEventWithoutText = true; + if (![NSStringFromSelector(selector) hasPrefix:@"insert"]) { + // The text input system determined that the key event was not + // meant for text insertion, and instead asked us to treat it + // as a (possibly noop) command. This typically happens for key + // events with either ⌘ or ⌃, function keys such as F1-F35, + // arrow keys, etc. We reflect that when sending the key event + // later on, by removing the text from the event, so that the + // event does not result in text insertion on the client side. + m_sendKeyEventWithoutText = true; + } } } @@ -391,8 +405,7 @@ */ - (NSRange)selectedRange { - QObject *focusObject = m_platformWindow->window()->focusObject(); - if (auto queryResult = queryInputMethod(focusObject, + if (auto queryResult = queryInputMethod(self.focusObject, Qt::ImCursorPosition | Qt::ImAbsolutePosition | Qt::ImAnchorPosition)) { // Unfortunately the Qt::InputMethodQuery values are all relative @@ -439,8 +452,7 @@ */ - (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)range actualRange:(NSRangePointer)actualRange { - QObject *focusObject = m_platformWindow->window()->focusObject(); - if (auto queryResult = queryInputMethod(focusObject, + if (auto queryResult = queryInputMethod(self.focusObject, Qt::ImAbsolutePosition | Qt::ImTextBeforeCursor | Qt::ImTextAfterCursor)) { const int absoluteCursorPosition = queryResult.value(Qt::ImAbsolutePosition).toInt(); const QString textBeforeCursor = queryResult.value(Qt::ImTextBeforeCursor).toString(); @@ -476,8 +488,8 @@ Q_UNUSED(range); Q_UNUSED(actualRange); - QWindow *window = m_platformWindow->window(); - if (queryInputMethod(window->focusObject())) { + QWindow *window = m_platformWindow ? m_platformWindow->window() : nullptr; + if (window && queryInputMethod(window->focusObject())) { QRect cursorRect = qApp->inputMethod()->cursorRectangle().toRect(); cursorRect.moveBottomLeft(window->mapToGlobal(cursorRect.bottomLeft())); return QCocoaScreen::mapToNative(cursorRect); @@ -493,6 +505,32 @@ return NSNotFound; } +/* + Returns the window level of the text input. + + This allows the input method to place its input panel + above the text input. +*/ +- (NSInteger)windowLevel +{ + // The default level assumed by input methods is NSFloatingWindowLevel, + // but our NSWindow level could be higher than that for many reasons, + // including being set via QWindow::setFlags() or directly on the + // NSWindow, or because we're embedded into a native view hierarchy. + // Return the actual window level to account for this. + auto level = m_platformWindow ? m_platformWindow->nativeWindow().level + : NSNormalWindowLevel; + + // The logic above only covers our own window though. In some cases, + // such as when a completer is active, the text input has a lower + // window level than another window that's also visible, and we don't + // want the input panel to be sandwiched between these two windows. + // Account for this by explicitly using NSPopUpMenuWindowLevel as + // the minimum window level, which corresponds to the highest level + // one can get via QWindow::setFlags(), except for Qt::ToolTip. + return qMax(level, NSPopUpMenuWindowLevel); +} + // ------------- Helper functions ------------- /* |