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

Commit d8bf942

Browse files
committed
macOS fluttertextinputplugin drops selector called if no client
1 parent 424a963 commit d8bf942

File tree

2 files changed

+52
-2
lines changed

2 files changed

+52
-2
lines changed

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,6 @@ - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
438438
_activeModel->EndComposing();
439439
}
440440
[_textInputContext discardMarkedText];
441-
442441
_clientID = nil;
443442
_inputAction = nil;
444443
_enableDeltaModel = NO;
@@ -777,6 +776,10 @@ - (void)doCommandBySelector:(SEL)selector {
777776
void (*func)(id, SEL, id) = reinterpret_cast<void (*)(id, SEL, id)>(imp);
778777
func(self, selector, nil);
779778
}
779+
if (self.clientID == nil) {
780+
// The macOS may still call selector even if it is no longer a first responder.
781+
return;
782+
}
780783

781784
if (selector == @selector(insertNewline:)) {
782785
// Already handled through text insertion (multiline) or action.

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

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1801,6 +1801,49 @@ - (bool)testSelectorsAreForwardedToFramework {
18011801
return true;
18021802
}
18031803

1804+
- (bool)testSelectorsNotForwardedToFrameworkIfNoClient {
1805+
id engineMock = flutter::testing::CreateMockFlutterEngine(@"");
1806+
id binaryMessengerMock = OCMProtocolMock(@protocol(FlutterBinaryMessenger));
1807+
OCMStub( // NOLINT(google-objc-avoid-throwing-exception)
1808+
[engineMock binaryMessenger])
1809+
.andReturn(binaryMessengerMock);
1810+
// Make sure the selectors are not forwarded to the framework.
1811+
OCMReject([binaryMessengerMock sendOnChannel:@"flutter/textinput" message:[OCMArg any]]);
1812+
FlutterViewController* viewController = [[FlutterViewController alloc] initWithEngine:engineMock
1813+
nibName:@""
1814+
bundle:nil];
1815+
1816+
FlutterTextInputPlugin* plugin =
1817+
[[FlutterTextInputPlugin alloc] initWithViewController:viewController];
1818+
1819+
// Can't run CFRunLoop in default mode because it causes crashes from scheduled
1820+
// sources from other tests.
1821+
NSString* runLoopMode = @"FlutterTestRunLoopMode";
1822+
plugin.customRunLoopMode = runLoopMode;
1823+
1824+
// Ensure both selectors are grouped in one platform channel call.
1825+
[plugin doCommandBySelector:@selector(moveUp:)];
1826+
[plugin doCommandBySelector:@selector(moveRightAndModifySelection:)];
1827+
1828+
// Clear the client before the CFRunLoop is run.
1829+
[plugin handleMethodCall:[FlutterMethodCall methodCallWithMethodName:@"TextInput.clearClient"
1830+
arguments:@[]]
1831+
result:^(id){
1832+
}];
1833+
1834+
__block bool done = false;
1835+
CFRunLoopPerformBlock(CFRunLoopGetMain(), (__bridge CFStringRef)runLoopMode, ^{
1836+
done = true;
1837+
});
1838+
1839+
while (!done) {
1840+
// Each invocation will handle one source.
1841+
CFRunLoopRunInMode((__bridge CFStringRef)runLoopMode, 0, true);
1842+
}
1843+
// At this point the selectors should be dropped; otherwise, OCMReject will throw.
1844+
return true;
1845+
}
1846+
18041847
@end
18051848

18061849
namespace flutter::testing {
@@ -1886,7 +1929,7 @@ - (bool)testSelectorsAreForwardedToFramework {
18861929
ASSERT_TRUE([[FlutterInputPluginTestObjc alloc] testComposingWithDelta]);
18871930
}
18881931

1889-
TEST(FlutterTextInputPluginTest, testComposingWithDeltasWhenSelectionIsActive) {
1932+
TEST(FlutterTextInputPluginTest, TestComposingWithDeltasWhenSelectionIsActive) {
18901933
ASSERT_TRUE([[FlutterInputPluginTestObjc alloc] testComposingWithDeltasWhenSelectionIsActive]);
18911934
}
18921935

@@ -1910,6 +1953,10 @@ - (bool)testSelectorsAreForwardedToFramework {
19101953
ASSERT_TRUE([[FlutterInputPluginTestObjc alloc] testSelectorsAreForwardedToFramework]);
19111954
}
19121955

1956+
TEST(FlutterTextInputPluginTest, TestSelectorsNotForwardedToFrameworkIfNoClient) {
1957+
ASSERT_TRUE([[FlutterInputPluginTestObjc alloc] testSelectorsNotForwardedToFrameworkIfNoClient]);
1958+
}
1959+
19131960
TEST(FlutterTextInputPluginTest, TestInsertNewLine) {
19141961
ASSERT_TRUE([[FlutterInputPluginTestObjc alloc] testInsertNewLine]);
19151962
}

0 commit comments

Comments
 (0)