Fix the Japanese IME problem on macOS reported in the following issue. (#166291)

flutter/engine#57286

Fixes https://github.com/flutter/flutter/issues/160935
This commit is contained in:
YU-KI Hidea 2025-06-21 09:10:21 +09:00 committed by GitHub
parent 37a85d9fdd
commit 453d113161
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 62 additions and 0 deletions

View File

@ -762,6 +762,18 @@ static char markerKey;
size_t extent = std::clamp(location + signedLength, 0L, textLength);
_activeModel->SetSelection(flutter::TextRange(base, extent));
} else if (_activeModel->composing() &&
!(_activeModel->composing_range() == _activeModel->selection())) {
// When confirmed by Japanese IME, string replaces range of composing_range.
// If selection == composing_range there is no problem.
// If selection ! = composing_range the range of selection is only a part of composing_range.
// Since _activeModel->AddText is processed first for selection, the finalization of the
// conversion cannot be processed correctly unless selection == composing_range or
// selection.collapsed(). Since _activeModel->SetSelection fails if (composing_ &&
// !range.collapsed()), selection == composing_range will failed. Therefore, the selection
// cursor should only be placed at the beginning of composing_range.
flutter::TextRange composing_range = _activeModel->composing_range();
_activeModel->SetSelection(flutter::TextRange(composing_range.start()));
}
flutter::TextRange oldSelection = _activeModel->selection();

View File

@ -2027,6 +2027,51 @@ static const FlutterViewIdentifier kViewId = 1;
return true;
}
- (bool)testInsertTextWithCollapsedSelectionInsideComposing {
id engineMock = flutter::testing::CreateMockFlutterEngine(@"");
id binaryMessengerMock = OCMProtocolMock(@protocol(FlutterBinaryMessenger));
OCMStub([engineMock binaryMessenger]).andReturn(binaryMessengerMock);
FlutterViewController* viewController = [[FlutterViewController alloc] initWithEngine:engineMock
nibName:@""
bundle:nil];
FlutterTextInputPluginTestDelegate* delegate =
[[FlutterTextInputPluginTestDelegate alloc] initWithBinaryMessenger:binaryMessengerMock
viewController:viewController];
FlutterTextInputPlugin* plugin = [[FlutterTextInputPlugin alloc] initWithDelegate:delegate];
NSDictionary* setClientConfig = @{
@"viewId" : @(kViewId),
@"inputAction" : @"action",
@"inputType" : @{@"name" : @"text"},
};
[plugin handleMethodCall:[FlutterMethodCall methodCallWithMethodName:@"TextInput.setClient"
arguments:@[ @(1), setClientConfig ]]
result:^(id result){
}];
FlutterMethodCall* call = [FlutterMethodCall methodCallWithMethodName:@"TextInput.setEditingState"
arguments:@{
@"text" : @"今日は家に帰ります",
@"selectionBase" : @(0),
@"selectionExtent" : @(3),
@"composingBase" : @(0),
@"composingExtent" : @(9),
}];
[plugin handleMethodCall:call
result:^(id result){
}];
[plugin insertText:@"今日は家に帰ります" replacementRange:NSMakeRange(NSNotFound, 0)];
NSDictionary* editingState = [plugin editingState];
EXPECT_STREQ([editingState[@"text"] UTF8String], "今日は家に帰ります");
EXPECT_EQ([editingState[@"selectionBase"] intValue], 9);
EXPECT_EQ([editingState[@"selectionExtent"] intValue], 9);
return true;
}
@end
namespace flutter::testing {
@ -2435,4 +2480,9 @@ TEST(FlutterTextInputPluginTest, WorksWithoutViewId) {
ASSERT_TRUE(plugin.currentViewController == viewController);
}
TEST(FlutterTextInputPluginTest, InsertTextWithCollapsedSelectionInsideComposing) {
ASSERT_TRUE(
[[FlutterInputPluginTestObjc alloc] testInsertTextWithCollapsedSelectionInsideComposing]);
}
} // namespace flutter::testing