summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms
diff options
context:
space:
mode:
authorTor Arne Vestbø <tor.arne.vestbo@qt.io>2021-08-27 15:55:39 +0200
committerTor Arne Vestbø <tor.arne.vestbo@qt.io>2021-08-27 22:41:06 +0200
commit3de396590cb41ddf05f91dfb1d2db8c1fe34ff56 (patch)
treedad32fb77b5c3b1b3efd343a8c4368b598e61b2d /src/plugins/platforms
parent9e1875483ceaf907226f84cd6a58ab59f7f16f80 (diff)
macOS: Correctly implement attributedSubstringForProposedRange
The substring range refers to the entire text of the focus object, not just the selection. As there is no way to pull out the entire text via input method queries we do the best we can via ImTextBeforeCursor and ImTextAfterCursor. Returning the correct substring enables input method features such as backtracking into already committed text with the Hiragana IM, as well as the Keyboard Viewer's 'Current Text' toolbar. Pick-to: 6.2 Change-Id: I53286ef1e8e7c5fba37858dda7317ae74d95b528 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
Diffstat (limited to 'src/plugins/platforms')
-rw-r--r--src/plugins/platforms/cocoa/qnsview_complextext.mm42
1 files changed, 36 insertions, 6 deletions
diff --git a/src/plugins/platforms/cocoa/qnsview_complextext.mm b/src/plugins/platforms/cocoa/qnsview_complextext.mm
index 3fcc0f23fa..05c0418ee7 100644
--- a/src/plugins/platforms/cocoa/qnsview_complextext.mm
+++ b/src/plugins/platforms/cocoa/qnsview_complextext.mm
@@ -435,17 +435,47 @@
}
}
+/*
+ Returns an attributed string derived from the given range
+ in the underlying focus object's text storage.
+
+ Input methods may call this with a proposed range that is
+ out of bounds. For example, the InkWell text input service
+ may ask for the contents of the text input client that extends
+ beyond the document's range. To remedy this we always compute
+ the intersection between the proposed range and the available
+ text.
+
+ If the intersection is completely outside of the available text
+ this method returns nil.
+*/
- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)range actualRange:(NSRangePointer)actualRange
{
- Q_UNUSED(actualRange);
-
QObject *focusObject = m_platformWindow->window()->focusObject();
- if (auto queryResult = queryInputMethod(focusObject, Qt::ImCurrentSelection)) {
- QString selectedText = queryResult.value(Qt::ImCurrentSelection).toString();
- if (selectedText.isEmpty())
+ if (auto queryResult = queryInputMethod(focusObject,
+ Qt::ImAbsolutePosition | Qt::ImTextBeforeCursor | Qt::ImTextAfterCursor)) {
+ const int absoluteCursorPosition = queryResult.value(Qt::ImAbsolutePosition).toInt();
+ const QString textBeforeCursor = queryResult.value(Qt::ImTextBeforeCursor).toString();
+ const QString textAfterCursor = queryResult.value(Qt::ImTextAfterCursor).toString();
+
+ // The documentation doesn't say whether the marked text should be included
+ // in the available text, but observing NSTextView shows that this is the
+ // case, so we follow suit.
+ const QString availableText = textBeforeCursor + m_composingText + textAfterCursor;
+ const NSRange availableRange = NSMakeRange(absoluteCursorPosition - textBeforeCursor.length(),
+ availableText.length());
+
+ const NSRange intersectedRange = NSIntersectionRange(range, availableRange);
+ if (actualRange)
+ *actualRange = intersectedRange;
+
+ if (!intersectedRange.length)
return nil;
- NSString *substring = QStringView(selectedText).mid(range.location, range.length).toNSString();
+ NSString *substring = QStringView(availableText).mid(
+ intersectedRange.location - availableRange.location,
+ intersectedRange.length).toNSString();
+
return [[[NSAttributedString alloc] initWithString:substring] autorelease];
} else {