5 #import <Foundation/Foundation.h>
6 #import <OCMock/OCMock.h>
7 #import <XCTest/XCTest.h>
8 #include <_types/_uint64_t.h>
14 #include "flutter/shell/platform/embedder/embedder.h"
15 #include "flutter/shell/platform/embedder/test_utils/key_codes.g.h"
17 using namespace flutter::testing::keycodes;
22 #define XCTAssertStrEqual(value, expected) \
23 XCTAssertTrue(strcmp(value, expected) == 0, \
24 @"String \"%s\" not equal to the expected value of \"%s\"", value, expected)
28 @property(nonatomic) FlutterKeyEvent* data;
29 @property(nonatomic) FlutterKeyEventCallback callback;
30 @property(nonatomic) _VoidPtr userData;
31 - (nonnull instancetype)initWithEvent:(const FlutterKeyEvent*)event
32 callback:(nullable FlutterKeyEventCallback)callback
33 userData:(nullable _VoidPtr)userData;
35 - (void)respond:(BOOL)handled;
39 - (instancetype)initWithEvent:(const FlutterKeyEvent*)event
40 callback:(nullable FlutterKeyEventCallback)callback
41 userData:(nullable _VoidPtr)userData {
43 _data =
new FlutterKeyEvent(*event);
44 if (event->character !=
nullptr) {
45 size_t len = strlen(event->character);
46 char* character =
new char[len + 1];
47 strlcpy(character, event->character, len + 1);
48 _data->character = character;
56 return _callback != nil;
59 - (void)respond:(BOOL)handled {
62 @"Improper call to `respond` that does not have a callback.");
63 _callback(handled, _userData);
67 if (_data->character !=
nullptr) {
68 delete[] _data->character;
76 constexpr UIKeyboardHIDUsage kKeyCodeUndefined = (UIKeyboardHIDUsage)0x03;
78 constexpr UIKeyboardHIDUsage kKeyCodeKeyA = (UIKeyboardHIDUsage)0x04;
80 constexpr UIKeyboardHIDUsage kKeyCodePeriod = (UIKeyboardHIDUsage)0x37;
82 constexpr UIKeyboardHIDUsage kKeyCodeKeyW = (UIKeyboardHIDUsage)0x1a;
84 constexpr UIKeyboardHIDUsage kKeyCodeShiftLeft = (UIKeyboardHIDUsage)0xe1;
86 constexpr UIKeyboardHIDUsage kKeyCodeShiftRight = (UIKeyboardHIDUsage)0xe5;
88 constexpr UIKeyboardHIDUsage kKeyCodeNumpad1 = (UIKeyboardHIDUsage)0x59;
90 constexpr UIKeyboardHIDUsage kKeyCodeCapsLock = (UIKeyboardHIDUsage)0x39;
92 constexpr UIKeyboardHIDUsage kKeyCodeF1 = (UIKeyboardHIDUsage)0x3a;
94 constexpr UIKeyboardHIDUsage kKeyCodeCommandLeft = (UIKeyboardHIDUsage)0xe3;
96 constexpr UIKeyboardHIDUsage kKeyCodeAltRight = (UIKeyboardHIDUsage)0xe6;
98 constexpr UIKeyboardHIDUsage kKeyCodeEject = (UIKeyboardHIDUsage)0xb8;
100 constexpr uint64_t kPhysicalKeyUndefined = 0x00070003;
102 constexpr uint64_t kLogicalKeyUndefined = 0x1300000003;
104 constexpr uint64_t kModifierFlagNone = 0x0;
106 typedef
void (^ResponseCallback)(
bool handled);
116 if (@available(iOS 13.4, *)) {
118 XCTSkip(
@"Required API not present for test.");
129 __block NSMutableArray<TestKeyEvent*>* events = [[NSMutableArray<TestKeyEvent*> alloc] init];
130 __block BOOL last_handled = TRUE;
131 FlutterKeyEvent* event;
134 initWithSendEvent:^(const FlutterKeyEvent& event, _Nullable FlutterKeyEventCallback callback,
135 _Nullable _VoidPtr user_data) {
136 [events addObject:[[
TestKeyEvent alloc] initWithEvent:&event
138 userData:user_data]];
141 last_handled = FALSE;
142 [responder
handlePress:keyDownEvent(kKeyCodeKeyA, kModifierFlagNone, 123.0f, "a", "a")
144 last_handled = handled;
147 XCTAssertEqual([events count], 1u);
148 event = [events lastObject].data;
149 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
150 XCTAssertEqual(event->timestamp, 123000000.0f);
151 XCTAssertEqual(event->physical, kPhysicalKeyA);
152 XCTAssertEqual(event->logical, kLogicalKeyA);
154 XCTAssertEqual(event->synthesized,
false);
156 XCTAssertEqual(last_handled, FALSE);
157 XCTAssert([[events lastObject] hasCallback]);
158 [[events lastObject] respond:TRUE];
159 XCTAssertEqual(last_handled, TRUE);
161 [events removeAllObjects];
164 [responder
handlePress:keyUpEvent(kKeyCodeKeyA, kModifierFlagNone, 123.0f)
166 last_handled = handled;
169 XCTAssertEqual([events count], 1u);
170 event = [events lastObject].data;
171 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
172 XCTAssertEqual(event->timestamp, 123000000.0f);
173 XCTAssertEqual(event->physical, kPhysicalKeyA);
174 XCTAssertEqual(event->logical, kLogicalKeyA);
175 XCTAssertEqual(event->character,
nullptr);
176 XCTAssertEqual(event->synthesized,
false);
178 XCTAssertEqual(last_handled, TRUE);
179 XCTAssert([[events lastObject] hasCallback]);
180 [[events lastObject] respond:FALSE];
181 XCTAssertEqual(last_handled, FALSE);
183 [events removeAllObjects];
187 __block NSMutableArray<TestKeyEvent*>* events = [[NSMutableArray<TestKeyEvent*> alloc] init];
188 __block BOOL last_handled = TRUE;
189 FlutterKeyEvent* event;
192 initWithSendEvent:^(const FlutterKeyEvent& event, _Nullable FlutterKeyEventCallback callback,
193 _Nullable _VoidPtr user_data) {
194 [events addObject:[[
TestKeyEvent alloc] initWithEvent:&event
196 userData:user_data]];
199 last_handled = FALSE;
202 [responder
handlePress:keyDownEvent(kKeyCodeEject, kModifierFlagNone, 123.0f)
204 last_handled = handled;
207 XCTAssertEqual([events count], 1u);
208 event = [events lastObject].data;
209 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
210 XCTAssertEqual(event->physical, kKeyCodeEject |
kIosPlane);
211 XCTAssertEqual(event->logical, kKeyCodeEject |
kIosPlane);
212 XCTAssertEqual(event->character,
nullptr);
213 XCTAssertEqual(event->synthesized,
false);
215 XCTAssertEqual(last_handled, FALSE);
216 XCTAssert([[events lastObject] hasCallback]);
217 [[events lastObject] respond:TRUE];
218 XCTAssertEqual(last_handled, TRUE);
220 [events removeAllObjects];
223 [responder
handlePress:keyUpEvent(kKeyCodeEject, kModifierFlagNone, 123.0f)
225 last_handled = handled;
228 XCTAssertEqual([events count], 1u);
229 event = [events lastObject].data;
230 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
231 XCTAssertEqual(event->physical, kKeyCodeEject |
kIosPlane);
232 XCTAssertEqual(event->logical, kKeyCodeEject |
kIosPlane);
233 XCTAssertEqual(event->character,
nullptr);
234 XCTAssertEqual(event->synthesized,
false);
236 XCTAssertEqual(last_handled, TRUE);
237 XCTAssert([[events lastObject] hasCallback]);
238 [[events lastObject] respond:FALSE];
239 XCTAssertEqual(last_handled, FALSE);
241 [events removeAllObjects];
245 __block NSMutableArray<TestKeyEvent*>* events = [[NSMutableArray<TestKeyEvent*> alloc] init];
246 FlutterKeyEvent* event;
249 initWithSendEvent:^(const FlutterKeyEvent& event, _Nullable FlutterKeyEventCallback callback,
250 _Nullable _VoidPtr user_data) {
251 [events addObject:[[
TestKeyEvent alloc] initWithEvent:&event
253 userData:user_data]];
258 [responder
handlePress:keyDownEvent(kKeyCodeAltRight, kModifierFlagAltAny, 123.0f)
262 XCTAssertEqual([events count], 1u);
263 event = [events lastObject].data;
264 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
265 XCTAssertEqual(event->physical, kPhysicalAltRight);
266 XCTAssertEqual(event->logical, kLogicalAltRight);
267 XCTAssertEqual(event->character,
nullptr);
268 XCTAssertEqual(event->synthesized,
false);
270 [events removeAllObjects];
273 [responder
handlePress:keyDownEvent(kKeyCodeKeyW, kModifierFlagAltAny, 123.0f, "â ˆ‘", "w")
277 XCTAssertEqual([events count], 1u);
278 event = [events lastObject].data;
279 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
280 XCTAssertEqual(event->physical, kPhysicalKeyW);
281 XCTAssertEqual(event->logical, kLogicalKeyW);
283 XCTAssertEqual(event->synthesized,
false);
285 [events removeAllObjects];
289 [responder
handlePress:keyUpEvent(kKeyCodeAltRight, kModifierFlagAltAny, 123.0f)
293 XCTAssertEqual([events count], 1u);
294 event = [events lastObject].data;
295 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
296 XCTAssertEqual(event->physical, kPhysicalAltRight);
297 XCTAssertEqual(event->logical, kLogicalAltRight);
298 XCTAssertEqual(event->character,
nullptr);
299 XCTAssertEqual(event->synthesized,
false);
301 [events removeAllObjects];
308 [responder
handlePress:keyUpEvent(kKeyCodeKeyW, kModifierFlagAltAny, 123.0f)
312 XCTAssertEqual([events count], 1u);
313 event = [events lastObject].data;
314 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
315 XCTAssertEqual(event->physical, kPhysicalKeyW);
316 XCTAssertEqual(event->logical, kLogicalKeyW);
317 XCTAssertEqual(event->character,
nullptr);
318 XCTAssertEqual(event->synthesized,
false);
320 [events removeAllObjects];
324 [responder
handlePress:keyDownEvent(kKeyCodeKeyA, kModifierFlagNone, 123.0f, "Ã ¥", "a")
328 XCTAssertEqual([events count], 1u);
329 event = [events lastObject].data;
330 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
331 XCTAssertEqual(event->physical, kPhysicalKeyA);
332 XCTAssertEqual(event->logical, kLogicalKeyA);
334 XCTAssertEqual(event->synthesized,
false);
337 - (void)testIgnoreDuplicateDownEvent
API_AVAILABLE(ios(13.4)) {
338 __block NSMutableArray<TestKeyEvent*>* events = [[NSMutableArray<TestKeyEvent*> alloc] init];
339 __block BOOL last_handled = TRUE;
340 FlutterKeyEvent* event;
343 initWithSendEvent:^(const FlutterKeyEvent& event, _Nullable FlutterKeyEventCallback callback,
344 _Nullable _VoidPtr user_data) {
345 [events addObject:[[
TestKeyEvent alloc] initWithEvent:&event
347 userData:user_data]];
350 last_handled = FALSE;
351 [responder
handlePress:keyDownEvent(kKeyCodeKeyA, kModifierFlagNone, 123.0f, "a", "a")
353 last_handled = handled;
356 XCTAssertEqual([events count], 1u);
357 event = [events lastObject].data;
358 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
359 XCTAssertEqual(event->physical, kPhysicalKeyA);
360 XCTAssertEqual(event->logical, kLogicalKeyA);
362 XCTAssertEqual(event->synthesized,
false);
363 XCTAssertEqual(last_handled, FALSE);
364 [[events lastObject] respond:TRUE];
365 XCTAssertEqual(last_handled, TRUE);
367 [events removeAllObjects];
369 last_handled = FALSE;
370 [responder
handlePress:keyDownEvent(kKeyCodeKeyA, kModifierFlagNone, 123.0f, "a", "a")
372 last_handled = handled;
375 XCTAssertEqual([events count], 1u);
376 event = [events lastObject].data;
377 XCTAssertEqual(event->physical, 0ull);
378 XCTAssertEqual(event->logical, 0ull);
379 XCTAssertEqual(event->synthesized,
false);
380 XCTAssertFalse([[events lastObject] hasCallback]);
381 XCTAssertEqual(last_handled, TRUE);
383 [events removeAllObjects];
385 last_handled = FALSE;
386 [responder
handlePress:keyUpEvent(kKeyCodeKeyA, kModifierFlagNone, 123.0f)
388 last_handled = handled;
391 XCTAssertEqual([events count], 1u);
392 event = [events lastObject].data;
393 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
394 XCTAssertEqual(event->physical, kPhysicalKeyA);
395 XCTAssertEqual(event->logical, kLogicalKeyA);
396 XCTAssertEqual(event->character,
nullptr);
397 XCTAssertEqual(event->synthesized,
false);
398 XCTAssertEqual(last_handled, FALSE);
399 [[events lastObject] respond:TRUE];
400 XCTAssertEqual(last_handled, TRUE);
402 [events removeAllObjects];
406 __block NSMutableArray<TestKeyEvent*>* events = [[NSMutableArray<TestKeyEvent*> alloc] init];
407 __block BOOL last_handled = TRUE;
408 FlutterKeyEvent* event;
411 initWithSendEvent:^(const FlutterKeyEvent& event, _Nullable FlutterKeyEventCallback callback,
412 _Nullable _VoidPtr user_data) {
413 [events addObject:[[
TestKeyEvent alloc] initWithEvent:&event
415 userData:user_data]];
418 last_handled = FALSE;
419 [responder
handlePress:keyUpEvent(kKeyCodeKeyA, kModifierFlagNone, 123.0f)
421 last_handled = handled;
424 XCTAssertEqual([events count], 1u);
425 event = [events lastObject].data;
426 XCTAssertEqual(event->physical, 0ull);
427 XCTAssertEqual(event->logical, 0ull);
428 XCTAssertEqual(event->synthesized,
false);
429 XCTAssertFalse([[events lastObject] hasCallback]);
430 XCTAssertEqual(last_handled, TRUE);
432 [events removeAllObjects];
439 - (void)testToggleModifiersDuringKeyTap
API_AVAILABLE(ios(13.4)) {
440 __block NSMutableArray<TestKeyEvent*>* events = [[NSMutableArray<TestKeyEvent*> alloc] init];
441 FlutterKeyEvent* event;
444 initWithSendEvent:^(const FlutterKeyEvent& event, _Nullable FlutterKeyEventCallback callback,
445 _Nullable _VoidPtr user_data) {
446 [events addObject:[[
TestKeyEvent alloc] initWithEvent:&event
448 userData:user_data]];
451 [responder
handlePress:keyDownEvent(kKeyCodeShiftRight, kModifierFlagShiftAny, 123.0f)
455 XCTAssertEqual([events count], 1u);
457 event = [events lastObject].data;
458 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
459 XCTAssertEqual(event->timestamp, 123000000.0f);
460 XCTAssertEqual(event->physical, kPhysicalShiftRight);
461 XCTAssertEqual(event->logical, kLogicalShiftRight);
462 XCTAssertEqual(event->character,
nullptr);
463 XCTAssertEqual(event->synthesized,
false);
464 [[events lastObject] respond:TRUE];
466 [events removeAllObjects];
468 [responder
handlePress:keyDownEvent(kKeyCodeKeyA, kModifierFlagShiftAny, 123.0f, "A", "A")
472 XCTAssertEqual([events count], 1u);
473 event = [events lastObject].data;
474 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
475 XCTAssertEqual(event->physical, kPhysicalKeyA);
476 XCTAssertEqual(event->logical, kLogicalKeyA);
478 XCTAssertEqual(event->synthesized,
false);
479 [[events lastObject] respond:TRUE];
481 [events removeAllObjects];
483 [responder
handlePress:keyUpEvent(kKeyCodeShiftRight, kModifierFlagNone, 123.0f)
487 XCTAssertEqual([events count], 1u);
488 event = [events lastObject].data;
489 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
490 XCTAssertEqual(event->physical, kPhysicalShiftRight);
491 XCTAssertEqual(event->logical, kLogicalShiftRight);
492 XCTAssertEqual(event->character,
nullptr);
493 XCTAssertEqual(event->synthesized,
false);
494 [[events lastObject] respond:TRUE];
496 [events removeAllObjects];
498 [responder
handlePress:keyUpEvent(kKeyCodeKeyA, kModifierFlagNone, 123.0f)
502 XCTAssertEqual([events count], 1u);
503 event = [events lastObject].data;
504 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
505 XCTAssertEqual(event->physical, kPhysicalKeyA);
506 XCTAssertEqual(event->logical, kLogicalKeyA);
507 XCTAssertEqual(event->character,
nullptr);
508 XCTAssertEqual(event->synthesized,
false);
509 [[events lastObject] respond:TRUE];
511 [events removeAllObjects];
520 __block NSMutableArray<TestKeyEvent*>* events = [[NSMutableArray<TestKeyEvent*> alloc] init];
521 FlutterKeyEvent* event;
522 __block BOOL last_handled = TRUE;
523 id keyEventCallback = ^(BOOL handled) {
524 last_handled = handled;
528 initWithSendEvent:^(const FlutterKeyEvent& event, _Nullable FlutterKeyEventCallback callback,
529 _Nullable _VoidPtr user_data) {
530 [events addObject:[[
TestKeyEvent alloc] initWithEvent:&event
532 userData:user_data]];
540 [responder
handlePress:keyDownEvent(kKeyCodeNumpad1, kModifierFlagNumPadKey, 123.0, "1", "1")
543 XCTAssertEqual([events count], 1u);
544 event = [events lastObject].data;
545 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
546 XCTAssertEqual(event->physical, kPhysicalNumpad1);
547 XCTAssertEqual(event->logical, kLogicalNumpad1);
549 XCTAssertEqual(event->synthesized,
false);
550 [[events lastObject] respond:TRUE];
552 [events removeAllObjects];
556 [responder
handlePress:keyDownEvent(kKeyCodeUndefined, kModifierFlagNone, 123.0)
559 XCTAssertEqual([events count], 1u);
560 event = [events lastObject].data;
561 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
562 XCTAssertEqual(event->physical, kPhysicalKeyUndefined);
563 XCTAssertEqual(event->logical, kLogicalKeyUndefined);
564 XCTAssertEqual(event->character,
nullptr);
565 XCTAssertEqual(event->synthesized,
false);
566 [[events lastObject] respond:TRUE];
568 [events removeAllObjects];
572 [responder
handlePress:keyDownEvent(kKeyCodeF1, kModifierFlagNone, 123.0f, "\\^P", "\\^P")
575 XCTAssertEqual([events count], 1u);
576 event = [events lastObject].data;
577 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
578 XCTAssertEqual(event->physical, kPhysicalF1);
579 XCTAssertEqual(event->logical, kLogicalF1);
580 XCTAssertEqual(event->character,
nullptr);
581 XCTAssertEqual(event->synthesized,
false);
582 [[events lastObject] respond:TRUE];
584 [events removeAllObjects];
588 [responder
handlePress:keyDownEvent(kKeyCodeKeyA, kModifierFlagNone, 123.0f, "a", "a")
591 XCTAssertEqual([events count], 1u);
592 event = [events lastObject].data;
593 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
594 XCTAssertEqual(event->physical, kPhysicalKeyA);
595 XCTAssertEqual(event->logical, kLogicalKeyA);
597 XCTAssertEqual(event->synthesized,
false);
598 [[events lastObject] respond:TRUE];
600 [events removeAllObjects];
604 [responder
handlePress:keyDownEvent(kKeyCodeShiftLeft, kModifierFlagShiftAny, 123.0f)
607 XCTAssertEqual([events count], 1u);
608 event = [events lastObject].data;
609 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
610 XCTAssertEqual(event->physical, kPhysicalShiftLeft);
611 XCTAssertEqual(event->logical, kLogicalShiftLeft);
612 XCTAssertEqual(event->character,
nullptr);
613 XCTAssertEqual(event->synthesized,
false);
615 [events removeAllObjects];
619 [responder
handlePress:keyUpEvent(kKeyCodeNumpad1, kModifierFlagNumPadKey, 123.0f)
622 XCTAssertEqual([events count], 2u);
626 event = [events firstObject].data;
627 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
628 XCTAssertEqual(event->physical, kPhysicalShiftLeft);
629 XCTAssertEqual(event->logical, kLogicalShiftLeft);
630 XCTAssertEqual(event->character,
nullptr);
631 XCTAssertEqual(event->synthesized,
true);
633 event = [events lastObject].data;
634 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
635 XCTAssertEqual(event->physical, kPhysicalNumpad1);
636 XCTAssertEqual(event->logical, kLogicalNumpad1);
637 XCTAssertEqual(event->character,
nullptr);
638 XCTAssertEqual(event->synthesized,
false);
639 [[events lastObject] respond:TRUE];
641 [events removeAllObjects];
645 [responder
handlePress:keyUpEvent(kKeyCodeF1, kModifierFlagNone, 123.0f)
648 XCTAssertEqual([events count], 1u);
649 event = [events lastObject].data;
650 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
651 XCTAssertEqual(event->physical, kPhysicalF1);
652 XCTAssertEqual(event->logical, kLogicalF1);
653 XCTAssertEqual(event->character,
nullptr);
654 XCTAssertEqual(event->synthesized,
false);
655 [[events lastObject] respond:TRUE];
657 [events removeAllObjects];
661 [responder
handlePress:keyUpEvent(kKeyCodeUndefined, kModifierFlagNone, 123.0)
664 XCTAssertEqual([events count], 1u);
665 event = [events lastObject].data;
666 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
667 XCTAssertEqual(event->physical, kPhysicalKeyUndefined);
668 XCTAssertEqual(event->logical, kLogicalKeyUndefined);
669 XCTAssertEqual(event->synthesized,
false);
670 [[events lastObject] respond:TRUE];
672 [events removeAllObjects];
676 [responder
handlePress:keyUpEvent(kKeyCodeKeyA, kModifierFlagNone, 123.0f)
679 XCTAssertEqual([events count], 1u);
680 event = [events lastObject].data;
681 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
682 XCTAssertEqual(event->physical, kPhysicalKeyA);
683 XCTAssertEqual(event->logical, kLogicalKeyA);
684 XCTAssertEqual(event->character,
nullptr);
685 XCTAssertEqual(event->synthesized,
false);
686 [[events lastObject] respond:TRUE];
688 [events removeAllObjects];
692 [responder
handlePress:keyUpEvent(kKeyCodeShiftLeft, kModifierFlagShiftAny, 123.0f)
695 XCTAssertEqual([events count], 1u);
696 event = [events lastObject].data;
697 XCTAssertEqual(event->physical, 0ull);
698 XCTAssertEqual(event->logical, 0ull);
699 XCTAssertEqual(event->synthesized,
false);
700 XCTAssertFalse([[events lastObject] hasCallback]);
701 XCTAssertEqual(last_handled, TRUE);
703 [events removeAllObjects];
706 - (void)testIdentifyLeftAndRightModifiers
API_AVAILABLE(ios(13.4)) {
707 __block NSMutableArray<TestKeyEvent*>* events = [[NSMutableArray<TestKeyEvent*> alloc] init];
708 FlutterKeyEvent* event;
711 initWithSendEvent:^(const FlutterKeyEvent& event, _Nullable FlutterKeyEventCallback callback,
712 _Nullable _VoidPtr user_data) {
713 [events addObject:[[
TestKeyEvent alloc] initWithEvent:&event
715 userData:user_data]];
718 [responder
handlePress:keyDownEvent(kKeyCodeShiftLeft, kModifierFlagShiftAny, 123.0f)
722 XCTAssertEqual([events count], 1u);
723 event = [events lastObject].data;
724 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
725 XCTAssertEqual(event->physical, kPhysicalShiftLeft);
726 XCTAssertEqual(event->logical, kLogicalShiftLeft);
727 XCTAssertEqual(event->character,
nullptr);
728 XCTAssertEqual(event->synthesized,
false);
729 [[events lastObject] respond:TRUE];
731 [events removeAllObjects];
733 [responder
handlePress:keyDownEvent(kKeyCodeShiftRight, kModifierFlagShiftAny, 123.0f)
737 XCTAssertEqual([events count], 1u);
738 event = [events lastObject].data;
739 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
740 XCTAssertEqual(event->physical, kPhysicalShiftRight);
741 XCTAssertEqual(event->logical, kLogicalShiftRight);
742 XCTAssertEqual(event->character,
nullptr);
743 XCTAssertEqual(event->synthesized,
false);
744 [[events lastObject] respond:TRUE];
746 [events removeAllObjects];
748 [responder
handlePress:keyUpEvent(kKeyCodeShiftLeft, kModifierFlagShiftAny, 123.0f)
752 XCTAssertEqual([events count], 1u);
753 event = [events lastObject].data;
754 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
755 XCTAssertEqual(event->physical, kPhysicalShiftLeft);
756 XCTAssertEqual(event->logical, kLogicalShiftLeft);
757 XCTAssertEqual(event->character,
nullptr);
758 XCTAssertEqual(event->synthesized,
false);
759 [[events lastObject] respond:TRUE];
761 [events removeAllObjects];
763 [responder
handlePress:keyUpEvent(kKeyCodeShiftRight, kModifierFlagShiftAny, 123.0f)
767 XCTAssertEqual([events count], 1u);
768 event = [events lastObject].data;
769 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
770 XCTAssertEqual(event->physical, kPhysicalShiftRight);
771 XCTAssertEqual(event->logical, kLogicalShiftRight);
772 XCTAssertEqual(event->character,
nullptr);
773 XCTAssertEqual(event->synthesized,
false);
774 [[events lastObject] respond:TRUE];
776 [events removeAllObjects];
780 - (void)testSynchronizeCapsLockStateOnCapsLock
API_AVAILABLE(ios(13.4)) {
781 __block NSMutableArray<TestKeyEvent*>* events = [[NSMutableArray<TestKeyEvent*> alloc] init];
782 __block BOOL last_handled = TRUE;
783 id keyEventCallback = ^(BOOL handled) {
784 last_handled = handled;
786 FlutterKeyEvent* event;
789 initWithSendEvent:^(const FlutterKeyEvent& event, _Nullable FlutterKeyEventCallback callback,
790 _Nullable _VoidPtr user_data) {
791 [events addObject:[[
TestKeyEvent alloc] initWithEvent:&event
793 userData:user_data]];
796 last_handled = FALSE;
797 [responder
handlePress:keyDownEvent(kKeyCodeKeyA, kModifierFlagCapsLock, 123.0f, "A", "A")
800 XCTAssertEqual([events count], 3u);
802 event = events[0].data;
803 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
804 XCTAssertEqual(event->physical, kPhysicalCapsLock);
805 XCTAssertEqual(event->logical, kLogicalCapsLock);
806 XCTAssertEqual(event->character,
nullptr);
807 XCTAssertEqual(event->synthesized,
true);
808 XCTAssertFalse([events[0] hasCallback]);
810 event = events[1].data;
811 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
812 XCTAssertEqual(event->physical, kPhysicalCapsLock);
813 XCTAssertEqual(event->logical, kLogicalCapsLock);
814 XCTAssertEqual(event->character,
nullptr);
815 XCTAssertEqual(event->synthesized,
true);
816 XCTAssertFalse([events[1] hasCallback]);
818 event = events[2].data;
819 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
820 XCTAssertEqual(event->physical, kPhysicalKeyA);
821 XCTAssertEqual(event->logical, kLogicalKeyA);
823 XCTAssertEqual(event->synthesized,
false);
824 XCTAssert([events[2] hasCallback]);
826 XCTAssertEqual(last_handled, FALSE);
827 [[events lastObject] respond:TRUE];
828 XCTAssertEqual(last_handled, TRUE);
830 [events removeAllObjects];
833 [responder
handlePress:keyUpEvent(kKeyCodeKeyA, kModifierFlagCapsLock, 123.0f)
835 XCTAssertEqual([events count], 1u);
836 event = [events lastObject].data;
837 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
838 XCTAssertEqual(event->physical, kPhysicalKeyA);
839 XCTAssertEqual(event->logical, kLogicalKeyA);
840 XCTAssertEqual(event->synthesized,
false);
842 [events removeAllObjects];
846 last_handled = FALSE;
847 [responder
handlePress:keyDownEvent(kKeyCodeCapsLock, kModifierFlagCapsLock, 123.0f)
850 XCTAssertEqual([events count], 1u);
851 event = [events firstObject].data;
852 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
853 XCTAssertEqual(event->physical, kPhysicalCapsLock);
854 XCTAssertEqual(event->logical, kLogicalCapsLock);
855 XCTAssertEqual(event->character,
nullptr);
856 XCTAssertEqual(event->synthesized,
false);
857 XCTAssert([[events firstObject] hasCallback]);
859 [events removeAllObjects];
865 last_handled = FALSE;
866 [responder
handlePress:keyUpEvent(kKeyCodeCapsLock, kModifierFlagCapsLock, 123.0f)
869 XCTAssertEqual([events count], 1u);
870 event = [events firstObject].data;
871 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
872 XCTAssertEqual(event->physical, kPhysicalCapsLock);
873 XCTAssertEqual(event->logical, kLogicalCapsLock);
874 XCTAssertEqual(event->character,
nullptr);
875 XCTAssertEqual(event->synthesized,
false);
876 XCTAssert([[events firstObject] hasCallback]);
878 [events removeAllObjects];
880 last_handled = FALSE;
881 [responder
handlePress:keyDownEvent(kKeyCodeKeyA, kModifierFlagNone, 123.0f, "a", "a")
886 XCTAssertEqual([events count], 1u);
887 event = [events lastObject].data;
888 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
889 XCTAssertEqual(event->physical, kPhysicalKeyA);
890 XCTAssertEqual(event->logical, kLogicalKeyA);
892 XCTAssertEqual(event->synthesized,
false);
893 XCTAssert([[events firstObject] hasCallback]);
897 - (void)testSynchronizeCapsLockStateOnNormalKey
API_AVAILABLE(ios(13.4)) {
898 __block NSMutableArray<TestKeyEvent*>* events = [[NSMutableArray<TestKeyEvent*> alloc] init];
899 __block BOOL last_handled = TRUE;
900 id keyEventCallback = ^(BOOL handled) {
901 last_handled = handled;
903 FlutterKeyEvent* event;
906 initWithSendEvent:^(const FlutterKeyEvent& event, _Nullable FlutterKeyEventCallback callback,
907 _Nullable _VoidPtr user_data) {
908 [events addObject:[[
TestKeyEvent alloc] initWithEvent:&event
910 userData:user_data]];
913 last_handled = FALSE;
914 [responder
handlePress:keyDownEvent(kKeyCodeKeyA, kModifierFlagCapsLock, 123.0f, "A", "a")
917 XCTAssertEqual([events count], 3u);
919 event = events[0].data;
920 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
921 XCTAssertEqual(event->physical, kPhysicalCapsLock);
922 XCTAssertEqual(event->logical, kLogicalCapsLock);
923 XCTAssertEqual(event->character,
nullptr);
924 XCTAssertEqual(event->synthesized,
true);
925 XCTAssertFalse([events[0] hasCallback]);
927 event = events[1].data;
928 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
929 XCTAssertEqual(event->physical, kPhysicalCapsLock);
930 XCTAssertEqual(event->logical, kLogicalCapsLock);
931 XCTAssertEqual(event->character,
nullptr);
932 XCTAssertEqual(event->synthesized,
true);
933 XCTAssertFalse([events[1] hasCallback]);
935 event = events[2].data;
936 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
937 XCTAssertEqual(event->physical, kPhysicalKeyA);
938 XCTAssertEqual(event->logical, kLogicalKeyA);
940 XCTAssertEqual(event->synthesized,
false);
941 XCTAssert([events[2] hasCallback]);
943 XCTAssertEqual(last_handled, FALSE);
944 [[events lastObject] respond:TRUE];
945 XCTAssertEqual(last_handled, TRUE);
947 [events removeAllObjects];
952 __block NSMutableArray<TestKeyEvent*>* events = [[NSMutableArray<TestKeyEvent*> alloc] init];
953 id keyEventCallback = ^(BOOL handled) {
955 FlutterKeyEvent* event;
958 initWithSendEvent:^(const FlutterKeyEvent& event, _Nullable FlutterKeyEventCallback callback,
959 _Nullable _VoidPtr user_data) {
960 [events addObject:[[
TestKeyEvent alloc] initWithEvent:&event callback:nil userData:nil]];
961 callback(true, user_data);
965 [responder
handlePress:keyDownEvent(kKeyCodeCommandLeft, kModifierFlagMetaAny, 123.0f, "", "")
967 XCTAssertEqual([events count], 1u);
968 event = events[0].data;
969 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
970 XCTAssertEqual(event->physical, kPhysicalMetaLeft);
971 XCTAssertEqual(event->logical, kLogicalMetaLeft);
972 XCTAssertEqual(event->character,
nullptr);
973 XCTAssertEqual(event->synthesized,
false);
974 [events removeAllObjects];
977 [responder
handlePress:keyDownEvent(kKeyCodePeriod, kModifierFlagMetaAny, 123.0f,
978 "UIKeyInputEscape", "UIKeyInputEscape")
980 XCTAssertEqual([events count], 1u);
981 event = events[0].data;
982 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
983 XCTAssertEqual(event->physical, kPhysicalPeriod);
984 XCTAssertEqual(event->logical, kLogicalEscape);
985 XCTAssertEqual(event->character,
nullptr);
986 XCTAssertEqual(event->synthesized,
false);
987 [events removeAllObjects];
990 [responder
handlePress:keyUpEvent(kKeyCodePeriod, kModifierFlagMetaAny, 123.0f,
991 "UIKeyInputEscape", "UIKeyInputEscape")
993 XCTAssertEqual([events count], 1u);
994 event = events[0].data;
995 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
996 XCTAssertEqual(event->physical, kPhysicalPeriod);
997 XCTAssertEqual(event->logical, kLogicalEscape);
998 XCTAssertEqual(event->character,
nullptr);
999 XCTAssertEqual(event->synthesized,
false);
1000 [events removeAllObjects];
1003 [responder
handlePress:keyUpEvent(kKeyCodeCommandLeft, kModifierFlagMetaAny, 123.0f, "", "")
1005 XCTAssertEqual([events count], 1u);
1006 event = events[0].data;
1007 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
1008 XCTAssertEqual(event->physical, kPhysicalMetaLeft);
1009 XCTAssertEqual(event->logical, kLogicalMetaLeft);
1010 XCTAssertEqual(event->character,
nullptr);
1011 XCTAssertEqual(event->synthesized,
false);
1012 [events removeAllObjects];