5#import "flutter/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h"
6#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterDartProject_Internal.h"
7#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterEngineTestUtils.h"
8#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h"
9#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterTextInputPlugin.h"
10#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterTextInputSemanticsObject.h"
11#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterViewController_Internal.h"
12#import "flutter/shell/platform/darwin/macos/framework/Source/NSView+ClipsToBounds.h"
14#import <OCMock/OCMock.h>
15#import "flutter/testing/testing.h"
18- (void)setPlatformNode:(
flutter::FlutterTextPlatformNode*)node;
23@property(nonatomic, nullable,
copy) NSString* lastUpdatedString;
24@property(nonatomic) NSRange lastUpdatedSelection;
30- (void)updateString:(NSString*)string withSelection:(NSRange)selection {
31 _lastUpdatedString = string;
32 _lastUpdatedSelection = selection;
47 commandQueue:(id<MTLCommandQueue>)commandQueue {
48 return OCMClassMock([NSView
class]);
63 [engineMock binaryMessenger])
64 .andReturn(binaryMessengerMock);
73 NSDictionary* setClientConfig = @{
74 @"inputAction" :
@"action",
75 @"inputType" : @{
@"name" :
@"inputName"},
85 @"selectionBase" : @(0),
86 @"selectionExtent" : @(0),
87 @"composingBase" : @(-1),
88 @"composingExtent" : @(-1),
97 EXPECT_STREQ([editingState[
@"text"] UTF8String],
"Text");
98 EXPECT_STREQ([editingState[
@"selectionAffinity"] UTF8String],
"TextAffinity.upstream");
99 EXPECT_FALSE([editingState[
@"selectionIsDirectional"] boolValue]);
100 EXPECT_EQ([editingState[
@"selectionBase"] intValue], 0);
101 EXPECT_EQ([editingState[
@"selectionExtent"] intValue], 0);
102 EXPECT_EQ([editingState[
@"composingBase"] intValue], -1);
103 EXPECT_EQ([editingState[
@"composingExtent"] intValue], -1);
111 [engineMock binaryMessenger])
112 .andReturn(binaryMessengerMock);
121 NSDictionary* setClientConfig = @{
122 @"inputAction" :
@"action",
123 @"inputType" : @{
@"name" :
@"inputName"},
133 @"selectionBase" : @(4),
134 @"selectionExtent" : @(4),
135 @"composingBase" : @(-1),
136 @"composingExtent" : @(-1),
146 NSDictionary* expectedState = @{
147 @"selectionBase" : @(5),
148 @"selectionExtent" : @(5),
149 @"selectionAffinity" :
@"TextAffinity.upstream",
150 @"selectionIsDirectional" : @(NO),
151 @"composingBase" : @(4),
152 @"composingExtent" : @(10),
153 @"text" :
@"Textmarked",
162 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:updateCall]);
166 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:updateCall]);
177 [engineMock binaryMessenger])
178 .andReturn(binaryMessengerMock);
187 NSDictionary* setClientConfig = @{
188 @"inputAction" :
@"action",
189 @"inputType" : @{
@"name" :
@"inputName"},
199 @"selectionBase" : @(3),
200 @"selectionExtent" : @(3),
201 @"composingBase" : @(-1),
202 @"composingExtent" : @(-1),
212 NSDictionary* expectedState = @{
213 @"selectionBase" : @(2),
214 @"selectionExtent" : @(2),
215 @"selectionAffinity" :
@"TextAffinity.upstream",
216 @"selectionIsDirectional" : @(NO),
217 @"composingBase" : @(1),
218 @"composingExtent" : @(7),
219 @"text" :
@"1marked4",
228 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:updateCall]);
232 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:updateCall]);
243 [engineMock binaryMessenger])
244 .andReturn(binaryMessengerMock);
253 NSDictionary* setClientConfig = @{
254 @"inputAction" :
@"action",
255 @"inputType" : @{
@"name" :
@"inputName"},
265 @"selectionBase" : @(4),
266 @"selectionExtent" : @(4),
267 @"composingBase" : @(2),
268 @"composingExtent" : @(4),
278 @"selectionBase" : @(2),
279 @"selectionExtent" : @(2),
280 @"composingBase" : @(-1),
281 @"composingExtent" : @(-1),
289 EXPECT_STREQ([editingState[
@"text"] UTF8String],
"Te");
290 EXPECT_STREQ([editingState[
@"selectionAffinity"] UTF8String],
"TextAffinity.upstream");
291 EXPECT_FALSE([editingState[
@"selectionIsDirectional"] boolValue]);
292 EXPECT_EQ([editingState[
@"selectionBase"] intValue], 2);
293 EXPECT_EQ([editingState[
@"selectionExtent"] intValue], 2);
294 EXPECT_EQ([editingState[
@"composingBase"] intValue], -1);
295 EXPECT_EQ([editingState[
@"composingExtent"] intValue], -1);
304 [engineMock binaryMessenger])
305 .andReturn(binaryMessengerMock);
313 NSDictionary* setClientConfig = @{
314 @"inputAction" :
@"action",
315 @"inputType" : @{
@"name" :
@"inputName"},
326 @"selectionBase" : @(0),
327 @"selectionExtent" : @(0),
328 @"composingBase" : @(0),
329 @"composingExtent" : @(1),
336 EXPECT_EQ([editingState[
@"composingBase"] intValue], 0);
337 EXPECT_EQ([editingState[
@"composingExtent"] intValue], 1);
347 EXPECT_EQ([editingState[
@"composingBase"] intValue], [editingState[
@"composingExtent"] intValue]);
356 [engineMock binaryMessenger])
357 .andReturn(binaryMessengerMock);
365 NSDictionary* setClientConfig = @{
366 @"inputAction" :
@"action",
367 @"inputType" : @{
@"name" :
@"inputName"},
375 EXPECT_FALSE([plugin isAutomaticTextCompletionEnabled]);
384 [engineMock binaryMessenger])
385 .andReturn(binaryMessengerMock);
393 NSDictionary* setClientConfig = @{
394 @"inputAction" :
@"action",
395 @"inputType" : @{
@"name" :
@"inputName"},
397 @"uniqueIdentifier" :
@"field1",
398 @"hints" : @[ @"name" ],
399 @"editingValue" : @{
@"text" :
@""},
408 EXPECT_TRUE([plugin isAutomaticTextCompletionEnabled]);
411 if (@available(macOS 11.0, *)) {
412 EXPECT_EQ([plugin contentType], nil);
422 [engineMock binaryMessenger])
423 .andReturn(binaryMessengerMock);
431 NSDictionary* setClientConfig = @{
432 @"inputAction" :
@"action",
433 @"inputType" : @{
@"name" :
@"inputName"},
435 @"uniqueIdentifier" :
@"field1",
437 @"editingValue" : @{
@"text" :
@""},
446 EXPECT_TRUE([plugin isAutomaticTextCompletionEnabled]);
455 [engineMock binaryMessenger])
456 .andReturn(binaryMessengerMock);
464 NSDictionary* setClientConfig = @{
465 @"inputAction" :
@"action",
466 @"inputType" : @{
@"name" :
@"inputName"},
467 @"obscureText" : @YES,
469 @"uniqueIdentifier" :
@"field1",
470 @"editingValue" : @{
@"text" :
@""},
479 EXPECT_FALSE([plugin isAutomaticTextCompletionEnabled]);
488 [engineMock binaryMessenger])
489 .andReturn(binaryMessengerMock);
497 NSDictionary* setClientConfig = @{
498 @"inputAction" :
@"action",
499 @"inputType" : @{
@"name" :
@"inputName"},
501 @"uniqueIdentifier" :
@"field1",
502 @"hints" : @[ @"password" ],
503 @"editingValue" : @{
@"text" :
@""},
512 EXPECT_FALSE([plugin isAutomaticTextCompletionEnabled]);
515 if (@available(macOS 11.0, *)) {
516 EXPECT_EQ([plugin contentType], NSTextContentTypePassword);
526 [engineMock binaryMessenger])
527 .andReturn(binaryMessengerMock);
535 NSDictionary* setClientConfig = @{
536 @"inputAction" :
@"action",
537 @"inputType" : @{
@"name" :
@"inputName"},
540 @"inputAction" : @"action",
541 @"inputType" : @{@"name" : @"inputName"},
543 @"uniqueIdentifier" : @"field1",
544 @"hints" : @[ @"password" ],
545 @"editingValue" : @{@"text" : @""},
549 @"inputAction" : @"action",
550 @"inputType" : @{@"name" : @"inputName"},
552 @"uniqueIdentifier" : @"field2",
553 @"hints" : @[ @"name" ],
554 @"editingValue" : @{@"text" : @""},
565 EXPECT_FALSE([plugin isAutomaticTextCompletionEnabled]);
574 [engineMock binaryMessenger])
575 .andReturn(binaryMessengerMock);
583 NSDictionary* setClientConfig = @{
584 @"inputAction" :
@"action",
585 @"inputType" : @{
@"name" :
@"inputName"},
587 @"uniqueIdentifier" :
@"field1",
588 @"hints" : @[ @"name" ],
589 @"editingValue" : @{
@"text" :
@""},
598 EXPECT_FALSE([plugin isAutomaticTextCompletionEnabled]);
601 if (@available(macOS 11.0, *)) {
602 EXPECT_EQ([plugin contentType], NSTextContentTypeUsername);
612 [engineMock binaryMessenger])
613 .andReturn(binaryMessengerMock);
621 NSDictionary* setClientConfig = @{
622 @"inputAction" :
@"action",
623 @"inputType" : @{
@"name" :
@"inputName"},
625 @"uniqueIdentifier" :
@"field1",
626 @"hints" : @[ @"oneTimeCode" ],
627 @"editingValue" : @{
@"text" :
@""},
636 EXPECT_FALSE([plugin isAutomaticTextCompletionEnabled]);
639 if (@available(macOS 11.0, *)) {
640 EXPECT_EQ([plugin contentType], NSTextContentTypeOneTimeCode);
649 [engineMock binaryMessenger])
650 .andReturn(binaryMessengerMock);
657 .andReturn(NSMakeRect(0, 0, 200, 200));
659 id windowMock = OCMClassMock([NSWindow
class]);
662 .andReturn(windowMock);
665 [viewMock convertRect:NSMakeRect(28, 10, 2, 19) toView:nil])
666 .andReturn(NSMakeRect(28, 10, 2, 19));
669 [windowMock convertRectToScreen:NSMakeRect(28, 10, 2, 19)])
670 .andReturn(NSMakeRect(38, 20, 2, 19));
680 @(1.0), @(0.0), @(0.0), @(0.0), @(0.0), @(1.0), @(0.0), @(0.0), @(0.0),
681 @(0.0), @(1.0), @(0.0), @(20.0), @(10.0), @(0.0), @(1.0)
705 [windowMock convertRectToScreen:NSMakeRect(28, 10, 2, 19)]);
710 return NSEqualRects(
rect, NSMakeRect(38, 20, 2, 19));
717 [engineMock binaryMessenger])
718 .andReturn(binaryMessengerMock);
725 .andReturn(NSMakeRect(0, 0, 200, 200));
727 id windowMock = OCMClassMock([NSWindow
class]);
730 .andReturn(windowMock);
741 @(1.0), @(0.0), @(0.0), @(0.0), @(0.0), @(1.0), @(0.0), @(0.0), @(0.0),
742 @(0.0), @(1.0), @(0.0), @(20.0), @(10.0), @(0.0), @(0.0)
764 return NSEqualRects(
rect, CGRectZero);
771 [engineMock binaryMessenger])
772 .andReturn(binaryMessengerMock);
779 .andReturn(NSMakeRect(0, 0, 200, 200));
781 id windowMock = OCMClassMock([NSWindow
class]);
784 .andReturn(windowMock);
787 [viewMock convertRect:NSMakeRect(-18, 6, 3, 3) toView:nil])
788 .andReturn(NSMakeRect(-18, 6, 3, 3));
791 [windowMock convertRectToScreen:NSMakeRect(-18, 6, 3, 3)])
792 .andReturn(NSMakeRect(-18, 6, 3, 3));
805 @(0.0), @(3.0), @(0.0), @(0.0), @(-3.0), @(0.0), @(0.0), @(0.0), @(0.0),
806 @(0.0), @(3.0), @(0.0), @(-6.0), @(3.0), @(9.0), @(1.0)
831 [windowMock convertRectToScreen:NSMakeRect(-18, 6, 3, 3)]);
836 return NSEqualRects(
rect, NSMakeRect(-18, 6, 3, 3));
843 [engineMock binaryMessenger])
844 .andReturn(binaryMessengerMock);
853 NSDictionary* setClientConfig = @{
854 @"inputAction" :
@"action",
855 @"enableDeltaModel" :
@"true",
856 @"inputType" : @{
@"name" :
@"inputName"},
866 @"selectionBase" : @(0),
867 @"selectionExtent" : @(0),
868 @"composingBase" : @(-1),
869 @"composingExtent" : @(-1),
878 EXPECT_STREQ([editingState[
@"text"] UTF8String],
"Text");
879 EXPECT_STREQ([editingState[
@"selectionAffinity"] UTF8String],
"TextAffinity.upstream");
880 EXPECT_FALSE([editingState[
@"selectionIsDirectional"] boolValue]);
881 EXPECT_EQ([editingState[
@"selectionBase"] intValue], 0);
882 EXPECT_EQ([editingState[
@"selectionExtent"] intValue], 0);
883 EXPECT_EQ([editingState[
@"composingBase"] intValue], -1);
884 EXPECT_EQ([editingState[
@"composingExtent"] intValue], -1);
892 [engineMock binaryMessenger])
893 .andReturn(binaryMessengerMock);
902 NSDictionary* setClientConfig = @{
903 @"inputAction" :
@"action",
904 @"enableDeltaModel" :
@"true",
905 @"inputType" : @{
@"name" :
@"inputName"},
911 [plugin insertText:@"text to insert"];
913 NSDictionary* deltaToFramework = @{
915 @"deltaText" :
@"text to insert",
916 @"deltaStart" : @(0),
918 @"selectionBase" : @(14),
919 @"selectionExtent" : @(14),
920 @"selectionAffinity" :
@"TextAffinity.upstream",
921 @"selectionIsDirectional" : @(
false),
922 @"composingBase" : @(-1),
923 @"composingExtent" : @(-1),
925 NSDictionary* expectedState = @{
926 @"deltas" : @[ deltaToFramework ],
936 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:updateCall]);
941 [plugin setMarkedText:@"marked text" selectedRange:NSMakeRange(0, 1)];
943 deltaToFramework = @{
944 @"oldText" :
@"text to insert",
945 @"deltaText" :
@"marked text",
946 @"deltaStart" : @(14),
948 @"selectionBase" : @(14),
949 @"selectionExtent" : @(15),
950 @"selectionAffinity" :
@"TextAffinity.upstream",
951 @"selectionIsDirectional" : @(
false),
952 @"composingBase" : @(14),
953 @"composingExtent" : @(25),
956 @"deltas" : @[ deltaToFramework ],
966 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:updateCall]);
973 deltaToFramework = @{
974 @"oldText" :
@"text to insertmarked text",
976 @"deltaStart" : @(-1),
978 @"selectionBase" : @(25),
979 @"selectionExtent" : @(25),
980 @"selectionAffinity" :
@"TextAffinity.upstream",
981 @"selectionIsDirectional" : @(
false),
982 @"composingBase" : @(-1),
983 @"composingExtent" : @(-1),
986 @"deltas" : @[ deltaToFramework ],
996 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:updateCall]);
1007 [engineMock binaryMessenger])
1008 .andReturn(binaryMessengerMock);
1017 NSDictionary* setClientConfig = @{
1018 @"inputAction" :
@"action",
1019 @"enableDeltaModel" :
@"true",
1020 @"inputType" : @{
@"name" :
@"inputName"},
1026 [plugin setMarkedText:@"m" selectedRange:NSMakeRange(0, 1)];
1028 NSDictionary* deltaToFramework = @{
1030 @"deltaText" :
@"m",
1031 @"deltaStart" : @(0),
1033 @"selectionBase" : @(0),
1034 @"selectionExtent" : @(1),
1035 @"selectionAffinity" :
@"TextAffinity.upstream",
1036 @"selectionIsDirectional" : @(
false),
1037 @"composingBase" : @(0),
1038 @"composingExtent" : @(1),
1040 NSDictionary* expectedState = @{
1041 @"deltas" : @[ deltaToFramework ],
1051 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:updateCall]);
1056 [plugin setMarkedText:@"ma" selectedRange:NSMakeRange(0, 1)];
1058 deltaToFramework = @{
1060 @"deltaText" :
@"ma",
1061 @"deltaStart" : @(0),
1063 @"selectionBase" : @(0),
1064 @"selectionExtent" : @(1),
1065 @"selectionAffinity" :
@"TextAffinity.upstream",
1066 @"selectionIsDirectional" : @(
false),
1067 @"composingBase" : @(0),
1068 @"composingExtent" : @(2),
1071 @"deltas" : @[ deltaToFramework ],
1081 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:updateCall]);
1086 [plugin setMarkedText:@"mar" selectedRange:NSMakeRange(0, 1)];
1088 deltaToFramework = @{
1090 @"deltaText" :
@"mar",
1091 @"deltaStart" : @(0),
1093 @"selectionBase" : @(0),
1094 @"selectionExtent" : @(1),
1095 @"selectionAffinity" :
@"TextAffinity.upstream",
1096 @"selectionIsDirectional" : @(
false),
1097 @"composingBase" : @(0),
1098 @"composingExtent" : @(3),
1101 @"deltas" : @[ deltaToFramework ],
1111 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:updateCall]);
1116 [plugin setMarkedText:@"mark" selectedRange:NSMakeRange(0, 1)];
1118 deltaToFramework = @{
1119 @"oldText" :
@"mar",
1120 @"deltaText" :
@"mark",
1121 @"deltaStart" : @(0),
1123 @"selectionBase" : @(0),
1124 @"selectionExtent" : @(1),
1125 @"selectionAffinity" :
@"TextAffinity.upstream",
1126 @"selectionIsDirectional" : @(
false),
1127 @"composingBase" : @(0),
1128 @"composingExtent" : @(4),
1131 @"deltas" : @[ deltaToFramework ],
1141 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:updateCall]);
1146 [plugin setMarkedText:@"marke" selectedRange:NSMakeRange(0, 1)];
1148 deltaToFramework = @{
1149 @"oldText" :
@"mark",
1150 @"deltaText" :
@"marke",
1151 @"deltaStart" : @(0),
1153 @"selectionBase" : @(0),
1154 @"selectionExtent" : @(1),
1155 @"selectionAffinity" :
@"TextAffinity.upstream",
1156 @"selectionIsDirectional" : @(
false),
1157 @"composingBase" : @(0),
1158 @"composingExtent" : @(5),
1161 @"deltas" : @[ deltaToFramework ],
1171 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:updateCall]);
1176 [plugin setMarkedText:@"marked" selectedRange:NSMakeRange(0, 1)];
1178 deltaToFramework = @{
1179 @"oldText" :
@"marke",
1180 @"deltaText" :
@"marked",
1181 @"deltaStart" : @(0),
1183 @"selectionBase" : @(0),
1184 @"selectionExtent" : @(1),
1185 @"selectionAffinity" :
@"TextAffinity.upstream",
1186 @"selectionIsDirectional" : @(
false),
1187 @"composingBase" : @(0),
1188 @"composingExtent" : @(6),
1191 @"deltas" : @[ deltaToFramework ],
1201 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:updateCall]);
1208 deltaToFramework = @{
1209 @"oldText" :
@"marked",
1211 @"deltaStart" : @(-1),
1212 @"deltaEnd" : @(-1),
1213 @"selectionBase" : @(6),
1214 @"selectionExtent" : @(6),
1215 @"selectionAffinity" :
@"TextAffinity.upstream",
1216 @"selectionIsDirectional" : @(
false),
1217 @"composingBase" : @(-1),
1218 @"composingExtent" : @(-1),
1221 @"deltas" : @[ deltaToFramework ],
1231 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:updateCall]);
1242 [engineMock binaryMessenger])
1243 .andReturn(binaryMessengerMock);
1252 NSDictionary* setClientConfig = @{
1253 @"inputAction" :
@"action",
1254 @"enableDeltaModel" :
@"true",
1255 @"inputType" : @{
@"name" :
@"inputName"},
1265 @"selectionBase" : @(0),
1266 @"selectionExtent" : @(4),
1267 @"composingBase" : @(-1),
1268 @"composingExtent" : @(-1),
1278 NSDictionary* deltaToFramework = @{
1279 @"oldText" :
@"Text",
1280 @"deltaText" :
@"~",
1281 @"deltaStart" : @(0),
1283 @"selectionBase" : @(1),
1284 @"selectionExtent" : @(1),
1285 @"selectionAffinity" :
@"TextAffinity.upstream",
1286 @"selectionIsDirectional" : @(
false),
1287 @"composingBase" : @(0),
1288 @"composingExtent" : @(1),
1290 NSDictionary* expectedState = @{
1291 @"deltas" : @[ deltaToFramework ],
1301 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:updateCall]);
1309 __block NSEvent* eventBeingDispatchedByKeyboardManager = nil;
1311 OCMStub([viewControllerMock isDispatchingKeyEvent:[OCMArg
any]])
1312 .andDo(^(NSInvocation* invocation) {
1314 [invocation getArgument:(void*)&event atIndex:2];
1315 BOOL result =
event == eventBeingDispatchedByKeyboardManager;
1316 [invocation setReturnValue:&result];
1319 NSEvent*
event = [NSEvent keyEventWithType:NSEventTypeKeyDown
1320 location:NSZeroPoint
1326 charactersIgnoringModifiers:@""
1333 OCMExpect([viewControllerMock keyDown:
event]);
1336 if (![plugin performKeyEquivalent:
event]) {
1342 [viewControllerMock keyDown:
event]);
1349 eventBeingDispatchedByKeyboardManager =
event;
1351 OCMReject([viewControllerMock keyDown:
event]);
1355 if ([plugin performKeyEquivalent:
event]) {
1369 [engineMock binaryMessenger])
1370 .andReturn(binaryMessengerMock);
1371 OCMStub([[engineMock ignoringNonObjectArgs] sendKeyEvent:
FlutterKeyEvent {}
1375 NSTextInputContext* textInputContext = OCMClassMock([NSTextInputContext
class]);
1376 OCMStub([textInputContext handleEvent:[OCMArg
any]]).andReturn(YES);
1387 NSDictionary* setClientConfig = @{
1388 @"inputAction" :
@"action",
1389 @"enableDeltaModel" :
@"true",
1390 @"inputType" : @{
@"name" :
@"inputName"},
1408 NSEvent*
event = [NSEvent keyEventWithType:NSEventTypeKeyDown
1409 location:NSZeroPoint
1410 modifierFlags:0xa00100
1414 characters:@"\uF702"
1415 charactersIgnoringModifiers:@"\uF702"
1422 if ([plugin handleKeyEvent:
event] !=
true) {
1427 event = [NSEvent keyEventWithType:NSEventTypeKeyDown
1428 location:NSZeroPoint
1429 modifierFlags:0x40101
1433 characters:@"\uF702"
1434 charactersIgnoringModifiers:@"\uF702"
1441 if ([plugin handleKeyEvent:
event] !=
false) {
1452 [engineMock binaryMessenger])
1453 .andReturn(binaryMessengerMock);
1462 NSDictionary* setClientConfig = @{
1463 @"inputAction" :
@"action",
1464 @"enableDeltaModel" :
@"true",
1465 @"inputType" : @{
@"name" :
@"inputName"},
1478 NSEvent*
event = [NSEvent keyEventWithType:NSEventTypeKeyDown
1479 location:NSZeroPoint
1480 modifierFlags:0x40101
1485 charactersIgnoringModifiers:@"h"
1494 if ([plugin handleKeyEvent:
event] !=
true) {
1499 event = [NSEvent keyEventWithType:NSEventTypeKeyDown
1500 location:NSZeroPoint
1501 modifierFlags:0x100108
1506 charactersIgnoringModifiers:@"w"
1515 if ([plugin handleKeyEvent:
event] !=
false) {
1526 [engineMock binaryMessenger])
1527 .andReturn(binaryMessengerMock);
1528 OCMStub([[engineMock ignoringNonObjectArgs] sendKeyEvent:
FlutterKeyEvent {}
1539 NSDictionary* setClientConfig = @{
1540 @"inputType" : @{
@"name" :
@"TextInputType.multiline"},
1541 @"inputAction" :
@"TextInputAction.newline",
1551 @"selectionBase" : @(4),
1552 @"selectionExtent" : @(4),
1553 @"composingBase" : @(-1),
1554 @"composingExtent" : @(-1),
1563 EXPECT_STREQ([editingState[
@"text"] UTF8String],
"Text");
1564 EXPECT_STREQ([editingState[
@"selectionAffinity"] UTF8String],
"TextAffinity.upstream");
1565 EXPECT_FALSE([editingState[
@"selectionIsDirectional"] boolValue]);
1566 EXPECT_EQ([editingState[
@"selectionBase"] intValue], 4);
1567 EXPECT_EQ([editingState[
@"selectionExtent"] intValue], 4);
1568 EXPECT_EQ([editingState[
@"composingBase"] intValue], -1);
1569 EXPECT_EQ([editingState[
@"composingExtent"] intValue], -1);
1575 EXPECT_STREQ([editingState[
@"text"] UTF8String],
"Text\n");
1576 EXPECT_STREQ([editingState[
@"selectionAffinity"] UTF8String],
"TextAffinity.upstream");
1577 EXPECT_FALSE([editingState[
@"selectionIsDirectional"] boolValue]);
1578 EXPECT_EQ([editingState[
@"selectionBase"] intValue], 5);
1579 EXPECT_EQ([editingState[
@"selectionExtent"] intValue], 5);
1580 EXPECT_EQ([editingState[
@"composingBase"] intValue], -1);
1581 EXPECT_EQ([editingState[
@"composingExtent"] intValue], -1);
1590 [engineMock binaryMessenger])
1591 .andReturn(binaryMessengerMock);
1592 OCMStub([[engineMock ignoringNonObjectArgs] sendKeyEvent:
FlutterKeyEvent {}
1603 NSDictionary* setClientConfig = @{
1604 @"inputType" : @{
@"name" :
@"TextInputType.multiline"},
1605 @"inputAction" :
@"TextInputAction.send",
1615 @"selectionBase" : @(4),
1616 @"selectionExtent" : @(4),
1617 @"composingBase" : @(-1),
1618 @"composingExtent" : @(-1),
1621 NSDictionary* expectedState = @{
1622 @"selectionBase" : @(4),
1623 @"selectionExtent" : @(4),
1624 @"selectionAffinity" :
@"TextAffinity.upstream",
1625 @"selectionIsDirectional" : @(NO),
1626 @"composingBase" : @(-1),
1627 @"composingExtent" : @(-1),
1637 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:updateCall]);
1648 arguments:@[ @(1), @"TextInputAction.send" ]]];
1653 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:performActionCall]);
1658 NSDictionary* updatedState = @{
1659 @"selectionBase" : @(5),
1660 @"selectionExtent" : @(5),
1661 @"selectionAffinity" :
@"TextAffinity.upstream",
1662 @"selectionIsDirectional" : @(NO),
1663 @"composingBase" : @(-1),
1664 @"composingExtent" : @(-1),
1665 @"text" :
@"Text\n",
1676 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:updateCall]);
1689 [engineMock binaryMessenger])
1690 .andReturn(binaryMessengerMock);
1699 NSDictionary* setClientConfig = @{
1700 @"inputAction" :
@"action",
1701 @"enableDeltaModel" :
@"true",
1702 @"inputType" : @{
@"name" :
@"inputName"},
1708 [plugin insertText:@"text to insert"];
1710 NSDictionary* deltaToFramework = @{
1712 @"deltaText" :
@"text to insert",
1713 @"deltaStart" : @(0),
1715 @"selectionBase" : @(14),
1716 @"selectionExtent" : @(14),
1717 @"selectionAffinity" :
@"TextAffinity.upstream",
1718 @"selectionIsDirectional" : @(
false),
1719 @"composingBase" : @(-1),
1720 @"composingExtent" : @(-1),
1722 NSDictionary* expectedState = @{
1723 @"deltas" : @[ deltaToFramework ],
1733 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:updateCall]);
1738 bool localTextAndSelectionUpdated = [plugin.string isEqualToString:@"text to insert"] &&
1739 NSEqualRanges(plugin.selectedRange, NSMakeRange(14, 0));
1741 return localTextAndSelectionUpdated;
1748 [engineMock binaryMessenger])
1749 .andReturn(binaryMessengerMock);
1758 NSDictionary* setClientConfig = @{
1759 @"inputAction" :
@"action",
1760 @"enableDeltaModel" :
@"true",
1761 @"inputType" : @{
@"name" :
@"inputName"},
1770 NSString* runLoopMode =
@"FlutterTestRunLoopMode";
1777 __block
bool done =
false;
1778 CFRunLoopPerformBlock(CFRunLoopGetMain(), (__bridge CFStringRef)runLoopMode, ^{
1784 CFRunLoopRunInMode((__bridge CFStringRef)runLoopMode, 0,
true);
1791 @(1), @[ @"moveUp:", @"moveRightAndModifySelection:" ]
1796 [binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:performSelectorCall]);
1808 [engineMock binaryMessenger])
1809 .andReturn(binaryMessengerMock);
1811 OCMReject([binaryMessengerMock sendOnChannel:
@"flutter/textinput" message:[OCMArg
any]]);
1821 NSString* runLoopMode =
@"FlutterTestRunLoopMode";
1828 __block
bool done =
false;
1829 CFRunLoopPerformBlock(CFRunLoopGetMain(), (__bridge CFStringRef)runLoopMode, ^{
1834 CFRunLoopRunInMode((__bridge CFStringRef)runLoopMode, 0,
true);
1849 initWithAssetsPath:fixtures
1850 ICUDataPath:[fixtures stringByAppendingString:@"/icudtl.dat"]];
1851 return [[
FlutterEngine alloc] initWithName:@"test" project:project allowHeadlessExecution:true];
1897 testAutocompleteDisabledWhenAutofillGroupIncludesPassword]);
1910 testFirstRectForCharacterRangeWithEsotericAffineTransform]);
1966 [viewController loadView];
1968 NSWindow*
window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 800, 600)
1969 styleMask:NSBorderlessWindowMask
1970 backing:NSBackingStoreBuffered
1974 engine.semanticsEnabled = YES;
1981 node_data.
SetValue(
"initial text");
1989 fieldEditor:viewController.textInputPlugin];
1990 [viewController.view addSubview:mockTextField];
1993 NSDictionary* setClientConfig = @{
1994 @"inputAction" :
@"action",
1995 @"inputType" : @{
@"name" :
@"inputName"},
2002 [viewController.textInputPlugin handleMethodCall:methodCall result:result];
2004 NSDictionary* arguments = @{
2005 @"text" :
@"new text",
2006 @"selectionBase" : @(1),
2007 @"selectionExtent" : @(2),
2008 @"composingBase" : @(-1),
2009 @"composingExtent" : @(-1),
2013 [viewController.textInputPlugin handleMethodCall:methodCall result:result];
2023 [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
2031 [viewController loadView];
2033 NSWindow*
window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 800, 600)
2034 styleMask:NSBorderlessWindowMask
2035 backing:NSBackingStoreBuffered
2039 engine.semanticsEnabled = YES;
2046 node_data.
SetValue(
"initial text");
2052 EXPECT_EQ([textField becomeFirstResponder], YES);
2054 [engine setViewController:nil];
2057 EXPECT_EQ([textField becomeFirstResponder], NO);
2065 [viewController loadView];
2067 NSWindow*
window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 800, 600)
2068 styleMask:NSBorderlessWindowMask
2069 backing:NSBackingStoreBuffered
2076 [viewController.textInputPlugin
2084 [viewController.textInputPlugin
2098 [viewController loadView];
2100 NSWindow*
window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 800, 600)
2101 styleMask:NSBorderlessWindowMask
2102 backing:NSBackingStoreBuffered
2108 [window makeFirstResponder:viewController.flutterView];
2110 [viewController.textInputPlugin
2119 [viewController.textInputPlugin
2132 [engineMock binaryMessenger])
2133 .andReturn(binaryMessengerMock);
2142 ASSERT_TRUE(NSIsEmptyRect(plugin.frame));
2143 ASSERT_TRUE(plugin.clipsToBounds);
static void done(const char *config, const char *src, const char *srcOptions, const char *name)
void(^ FlutterResult)(id _Nullable result)
static void copy(void *dst, const uint8_t *src, int width, int bpp, int deltaSrc, int offset, const SkPMColor ctable[])
The ax platform node for a text field.
gfx::NativeViewAccessible GetNativeViewAccessible() override
void SetData(const AXNodeData &src)
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
instancetype sharedInstance()
instancetype methodCallWithMethodName:arguments:(NSString *method,[arguments] id _Nullable arguments)
NSRange lastUpdatedSelection
NSString * lastUpdatedString
void setPlatformNode:(flutter::FlutterTextPlatformNode *node)
NSDictionary * editingState()
NSString * customRunLoopMode
NSRect firstRectForCharacterRange:actualRange:(NSRange range, [actualRange] NSRangePointer actualRange)
NSTextInputContext * textInputContext
void handleMethodCall:result:(FlutterMethodCall *call,[result] FlutterResult result)
BOOL performKeyEquivalent:(NSEvent *event)
void setMarkedText:selectedRange:replacementRange:(id string, [selectedRange] NSRange selectedRange, [replacementRange] NSRange replacementRange)
void doCommandBySelector:(SEL selector)
std::weak_ptr< flutter::AccessibilityBridgeMac > accessibilityBridge()
FlutterTextInputPlugin * textInputPlugin
FlutterView * flutterView
BOOL acceptsFirstResponder()
FlutterViewController * viewController
Optional< SkRect > bounds
sk_sp< SkBlender > blender SkRect rect
const char * GetFixturesPath()
Returns the directory containing the test fixture for the target if this target has fixtures configur...
TEST(FlutterTextInputPluginTest, HasZeroSizeAndClipsToBounds)
id CreateMockFlutterEngine(NSString *pasteboardString)
SIT bool any(const Vec< 1, T > &x)
void SetValue(const std::string &value)
#define EXPECT_TRUE(handle)