Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 51b260f

Browse files
Fix macOS text composing
1 parent ed59191 commit 51b260f

4 files changed

Lines changed: 38 additions & 36 deletions

File tree

shell/platform/common/text_input_model.cc

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,22 @@ void TextInputModel::BeginComposing() {
6969
composing_range_ = TextRange(selection_.start());
7070
}
7171

72-
void TextInputModel::UpdateComposingText(const std::u16string& text) {
72+
void TextInputModel::UpdateComposingText(const std::u16string& text,
73+
TextRange selection) {
7374
// Preserve selection if we get a no-op update to the composing region.
7475
if (text.length() == 0 && composing_range_.collapsed()) {
7576
return;
7677
}
77-
DeleteSelected();
78-
text_.replace(composing_range_.start(), composing_range_.length(), text);
78+
const TextRange& rangeToDelete =
79+
composing_range_.collapsed() ? selection_ : composing_range_;
80+
text_.replace(rangeToDelete.start(), rangeToDelete.length(), text);
7981
composing_range_.set_end(composing_range_.start() + text.length());
80-
selection_ = TextRange(composing_range_.end());
82+
selection_ = TextRange(selection.start() + composing_range_.start(),
83+
selection.extent() + composing_range_.start());
84+
}
85+
86+
void TextInputModel::UpdateComposingText(const std::u16string& text) {
87+
UpdateComposingText(text, TextRange(text.length()));
8188
}
8289

8390
void TextInputModel::UpdateComposingText(const std::string& text) {

shell/platform/common/text_input_model.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,16 @@ class TextInputModel {
5757
// are restricted to the composing range.
5858
void BeginComposing();
5959

60-
// Replaces the composing range with new UTF-16 text.
60+
// Replaces the composing range with new UTF-16 text, and sets the selection.
6161
//
62-
// If a selection of non-zero length exists, it is deleted if the composing
63-
// text is non-empty. The composing range is adjusted to the length of
64-
// |text| and the selection base and offset are set to the end of the
65-
// composing range.
62+
// The given |text| replaces text within the current composing range, or the
63+
// current selection if the text wasn't composing. The composing range is
64+
// adjusted to the length of |text|, and the |selection| describes the new
65+
// selection range, relative to the start of the new composing range.
66+
void UpdateComposingText(const std::u16string& text, TextRange selection);
67+
68+
// Replaces the composing range with new UTF-16 text and sets the selection to
69+
// the end of the composing text.
6670
void UpdateComposingText(const std::u16string& text);
6771

6872
// Replaces the composing range with new UTF-8 text.

shell/platform/darwin/macos/framework/Source/FlutterTextInputPlugin.mm

Lines changed: 17 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,9 @@
6767

6868
#pragma mark - Enums
6969
/**
70-
* The affinity of the current cursor position. If the cursor is at a position representing
71-
* a line break, the cursor may be drawn either at the end of the current line (upstream)
72-
* or at the beginning of the next (downstream).
70+
* The affinity of the current cursor position. If the cursor is at a position
71+
* representing a soft line break, the cursor may be drawn either at the end of
72+
* the current line (upstream) or at the beginning of the next (downstream).
7373
*/
7474
typedef NS_ENUM(NSUInteger, FlutterTextAffinity) {
7575
kFlutterTextAffinityUpstream,
@@ -523,20 +523,19 @@ - (NSDictionary*)editingState {
523523
return nil;
524524
}
525525

526-
NSString* const textAffinity = [self textAffinityString];
527-
528-
int composingBase = _activeModel->composing() ? _activeModel->composing_range().base() : -1;
529-
int composingExtent = _activeModel->composing() ? _activeModel->composing_range().extent() : -1;
530-
531-
return @{
526+
NSDictionary* const dictionary = @{
532527
kSelectionBaseKey : @(_activeModel->selection().base()),
533528
kSelectionExtentKey : @(_activeModel->selection().extent()),
534-
kSelectionAffinityKey : textAffinity,
535-
kSelectionIsDirectionalKey : @NO,
536-
kComposingBaseKey : @(composingBase),
537-
kComposingExtentKey : @(composingExtent),
529+
kSelectionAffinityKey : [self textAffinityString],
538530
kTextKey : [NSString stringWithUTF8String:_activeModel->GetText().c_str()] ?: [NSNull null],
539531
};
532+
if (!_activeModel->composing()) {
533+
return dictionary;
534+
}
535+
NSMutableDictionary* mutableDictionary = [dictionary mutableCopy];
536+
mutableDictionary[kComposingBaseKey] = @(_activeModel->composing_range().base());
537+
mutableDictionary[kComposingExtentKey] = @(_activeModel->composing_range().extent());
538+
return mutableDictionary;
540539
}
541540

542541
- (void)updateEditState {
@@ -852,19 +851,13 @@ - (void)setMarkedText:(id)string
852851

853852
// Input string may be NSString or NSAttributedString.
854853
BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]];
855-
std::string marked_text = isAttributedString ? [[string string] UTF8String] : [string UTF8String];
856-
_activeModel->UpdateComposingText(marked_text);
857-
858-
// Update the selection within the marked text.
859-
long signedLength = static_cast<long>(selectedRange.length);
860-
long location = selectedRange.location + _activeModel->composing_range().base();
861-
long textLength = _activeModel->text_range().end();
862-
863-
size_t base = std::clamp(location, 0L, textLength);
864-
size_t extent = std::clamp(location + signedLength, 0L, textLength);
865-
_activeModel->SetSelection(flutter::TextRange(base, extent));
854+
const NSString* rawString = isAttributedString ? [string string] : string;
855+
_activeModel->UpdateComposingText(
856+
(const char16_t*)[rawString cStringUsingEncoding:NSUTF16StringEncoding],
857+
flutter::TextRange(selectedRange.location, selectedRange.location + selectedRange.length));
866858

867859
if (_enableDeltaModel) {
860+
std::string marked_text = [rawString UTF8String];
868861
[self updateEditStateWithDelta:flutter::TextEditingDelta(textBeforeChange,
869862
selectionBeforeChange.collapsed()
870863
? composingBeforeChange

shell/platform/windows/text_input_plugin.cc

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -197,9 +197,7 @@ void TextInputPlugin::ComposeChangeHook(const std::u16string& text,
197197
std::string text_before_change = active_model_->GetText();
198198
TextRange composing_before_change = active_model_->composing_range();
199199
active_model_->AddText(text);
200-
cursor_pos += active_model_->composing_range().start();
201-
active_model_->UpdateComposingText(text);
202-
active_model_->SetSelection(TextRange(cursor_pos, cursor_pos));
200+
active_model_->UpdateComposingText(text, TextRange(cursor_pos, cursor_pos));
203201
std::string text_after_change = active_model_->GetText();
204202
if (enable_delta_model) {
205203
TextEditingDelta delta = TextEditingDelta(

0 commit comments

Comments
 (0)