diff options
author | Tor Arne Vestbø <tor.arne.vestbo@qt.io> | 2021-08-23 17:03:17 +0200 |
---|---|---|
committer | Tor Arne Vestbø <tor.arne.vestbo@qt.io> | 2021-08-26 14:53:02 +0200 |
commit | 146bc0e6077c5e790d69344a373b7a978f745d31 (patch) | |
tree | f8e296a18a028c565b7fb38f19fbf0e954125de8 /src | |
parent | 137c28d077340d58da00ed419589dd62a6c9f662 (diff) |
macOS: Move replacement range calculations into helper methods
We're going to need this logic for marked text as well.
Pick-to: 6.2
Change-Id: I461024c3df0c4956c794f16d1cb31fc6b0efe4c5
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/plugins/platforms/cocoa/qnsview_complextext.mm | 105 |
1 files changed, 70 insertions, 35 deletions
diff --git a/src/plugins/platforms/cocoa/qnsview_complextext.mm b/src/plugins/platforms/cocoa/qnsview_complextext.mm index 40b8974795..b6f082c515 100644 --- a/src/plugins/platforms/cocoa/qnsview_complextext.mm +++ b/src/plugins/platforms/cocoa/qnsview_complextext.mm @@ -82,50 +82,19 @@ const bool isAttributedString = [text isKindOfClass:NSAttributedString.class]; QString commitString = QString::fromNSString(isAttributedString ? [text string] : text); - const auto markedRange = [self markedRange]; - const auto selectedRange = [self selectedRange]; - - // If the replacement range is not specified we are expected to compute - // the range ourselves, based on the current state of the input context. - if (replacementRange.location == NSNotFound) { - if (markedRange.location != NSNotFound) - replacementRange = markedRange; - else - replacementRange = selectedRange; - } + // Ensure we have a valid replacement range + replacementRange = [self sanitizeReplacementRange:replacementRange]; // Qt's QInputMethodEvent has different semantics for the replacement // range than AppKit does, so we need to sanitize the range first. - long long replaceFrom = replacementRange.location; - long long replaceLength = replacementRange.length; - - // The QInputMethodEvent replacement start is relative to the start - // of the marked text (the location of the preedit string). - if (markedRange.location != NSNotFound) - replaceFrom -= markedRange.location; - else - replaceFrom = 0; - - // The replacement length of QInputMethodEvent already includes - // the selection, as the documentation says that "If the widget - // has selected text, the selected text should get removed." - replaceLength -= selectedRange.length; - - // The replacement length of QInputMethodEvent already includes - // the preedit string, as the documentation says that "When doing - // replacement, the area of the preedit string is ignored". - replaceLength -= markedRange.length; - - // What we're left with is any _additional_ replacement. - // Make sure it's valid before passing it on. - replaceLength = qMax(0ll, replaceLength); + auto [replaceFrom, replaceLength] = [self inputMethodRangeForRange:replacementRange]; if (replaceFrom == NSNotFound) { qCWarning(lcQpaKeys) << "Failed to compute valid replacement range for text insertion"; inputMethodEvent.setCommitString(commitString); } else { qCDebug(lcQpaKeys) << "Replacing from" << replaceFrom << "with length" << replaceLength - << "based on marked range" << markedRange << "and selection" << selectedRange; + << "based on replacement range" << replacementRange; inputMethodEvent.setCommitString(commitString, replaceFrom, replaceLength); } @@ -447,4 +416,70 @@ return NSNotFound; } +// ------------- Helper functions ------------- + +/* + Sanitizes the replacement range, ensuring it's valid. + + If \a range is not valid the range of the current + marked text will be used. + + If there's no marked text the range of the current + selection will be used. + + If there's no selection the range will be {cursorPosition, 0}. +*/ +- (NSRange)sanitizeReplacementRange:(NSRange)range +{ + if (range.location != NSNotFound) + return range; // Use as is + + // If the replacement range is not specified we are expected to compute + // the range ourselves, based on the current state of the input context. + + const auto markedRange = [self markedRange]; + if (markedRange.location != NSNotFound) + return markedRange; + else + return [self selectedRange]; +} + +/* + Computes the QInputMethodEvent commit string range, + based on the NSTextInputClient replacement range. + + The two APIs have different semantics. +*/ +- (std::pair<long long, long long>)inputMethodRangeForRange:(NSRange)range +{ + long long replaceFrom = range.location; + long long replaceLength = range.length; + + const auto markedRange = [self markedRange]; + const auto selectedRange = [self selectedRange]; + + // The QInputMethodEvent replacement start is relative to the start + // of the marked text (the location of the preedit string). + if (markedRange.location != NSNotFound) + replaceFrom -= markedRange.location; + else + replaceFrom = 0; + + // The replacement length of QInputMethodEvent already includes + // the selection, as the documentation says that "If the widget + // has selected text, the selected text should get removed." + replaceLength -= selectedRange.length; + + // The replacement length of QInputMethodEvent already includes + // the preedit string, as the documentation says that "When doing + // replacement, the area of the preedit string is ignored". + replaceLength -= markedRange.length; + + // What we're left with is any _additional_ replacement. + // Make sure it's valid before passing it on. + replaceLength = qMax(0ll, replaceLength); + + return {replaceFrom, replaceLength}; +} + @end |