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)
void* _Nullable userData;
31 - (nonnull instancetype)initWithEvent:(const FlutterKeyEvent*)event
32 callback:(nullable FlutterKeyEventCallback)callback
33 userData:(
void* _Nullable)userData;
35 - (void)respond:(BOOL)handled;
39 - (instancetype)initWithEvent:(const FlutterKeyEvent*)event
40 callback:(nullable FlutterKeyEventCallback)callback
41 userData:(
void* _Nullable)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 void* _Nullable 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 XCTAssertNotEqual(event,
nullptr);
150 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
151 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
152 XCTAssertEqual(event->timestamp, 123000000.0f);
153 XCTAssertEqual(event->physical, kPhysicalKeyA);
154 XCTAssertEqual(event->logical, kLogicalKeyA);
156 XCTAssertEqual(event->synthesized,
false);
158 XCTAssertEqual(last_handled, FALSE);
159 XCTAssert([[events lastObject] hasCallback]);
160 [[events lastObject] respond:TRUE];
161 XCTAssertEqual(last_handled, TRUE);
163 [events removeAllObjects];
166 [responder
handlePress:keyUpEvent(kKeyCodeKeyA, kModifierFlagNone, 123.0f)
168 last_handled = handled;
171 XCTAssertEqual([events count], 1u);
172 event = [events lastObject].data;
173 XCTAssertNotEqual(event,
nullptr);
174 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
175 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
176 XCTAssertEqual(event->timestamp, 123000000.0f);
177 XCTAssertEqual(event->physical, kPhysicalKeyA);
178 XCTAssertEqual(event->logical, kLogicalKeyA);
179 XCTAssertEqual(event->character,
nullptr);
180 XCTAssertEqual(event->synthesized,
false);
182 XCTAssertEqual(last_handled, TRUE);
183 XCTAssert([[events lastObject] hasCallback]);
184 [[events lastObject] respond:FALSE];
185 XCTAssertEqual(last_handled, FALSE);
187 [events removeAllObjects];
191 __block NSMutableArray<TestKeyEvent*>* events = [[NSMutableArray<TestKeyEvent*> alloc] init];
192 __block BOOL last_handled = TRUE;
193 FlutterKeyEvent* event;
196 initWithSendEvent:^(const FlutterKeyEvent& event, _Nullable FlutterKeyEventCallback callback,
197 void* _Nullable user_data) {
198 [events addObject:[[
TestKeyEvent alloc] initWithEvent:&event
200 userData:user_data]];
203 last_handled = FALSE;
206 [responder
handlePress:keyDownEvent(kKeyCodeEject, kModifierFlagNone, 123.0f)
208 last_handled = handled;
211 XCTAssertEqual([events count], 1u);
212 event = [events lastObject].data;
213 XCTAssertNotEqual(event,
nullptr);
214 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
215 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
216 XCTAssertEqual(event->physical, kKeyCodeEject |
kIosPlane);
217 XCTAssertEqual(event->logical, kKeyCodeEject |
kIosPlane);
218 XCTAssertEqual(event->character,
nullptr);
219 XCTAssertEqual(event->synthesized,
false);
221 XCTAssertEqual(last_handled, FALSE);
222 XCTAssert([[events lastObject] hasCallback]);
223 [[events lastObject] respond:TRUE];
224 XCTAssertEqual(last_handled, TRUE);
226 [events removeAllObjects];
229 [responder
handlePress:keyUpEvent(kKeyCodeEject, kModifierFlagNone, 123.0f)
231 last_handled = handled;
234 XCTAssertEqual([events count], 1u);
235 event = [events lastObject].data;
236 XCTAssertNotEqual(event,
nullptr);
237 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
238 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
239 XCTAssertEqual(event->physical, kKeyCodeEject |
kIosPlane);
240 XCTAssertEqual(event->logical, kKeyCodeEject |
kIosPlane);
241 XCTAssertEqual(event->character,
nullptr);
242 XCTAssertEqual(event->synthesized,
false);
244 XCTAssertEqual(last_handled, TRUE);
245 XCTAssert([[events lastObject] hasCallback]);
246 [[events lastObject] respond:FALSE];
247 XCTAssertEqual(last_handled, FALSE);
249 [events removeAllObjects];
253 __block NSMutableArray<TestKeyEvent*>* events = [[NSMutableArray<TestKeyEvent*> alloc] init];
254 FlutterKeyEvent* event;
257 initWithSendEvent:^(const FlutterKeyEvent& event, _Nullable FlutterKeyEventCallback callback,
258 void* _Nullable user_data) {
259 [events addObject:[[
TestKeyEvent alloc] initWithEvent:&event
261 userData:user_data]];
266 [responder
handlePress:keyDownEvent(kKeyCodeAltRight, kModifierFlagAltAny, 123.0f)
270 XCTAssertEqual([events count], 1u);
271 event = [events lastObject].data;
272 XCTAssertNotEqual(event,
nullptr);
273 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
274 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
275 XCTAssertEqual(event->physical, kPhysicalAltRight);
276 XCTAssertEqual(event->logical, kLogicalAltRight);
277 XCTAssertEqual(event->character,
nullptr);
278 XCTAssertEqual(event->synthesized,
false);
280 [events removeAllObjects];
283 [responder
handlePress:keyDownEvent(kKeyCodeKeyW, kModifierFlagAltAny, 123.0f, "â ˆ‘", "w")
287 XCTAssertEqual([events count], 1u);
288 event = [events lastObject].data;
289 XCTAssertNotEqual(event,
nullptr);
290 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
291 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
292 XCTAssertEqual(event->physical, kPhysicalKeyW);
293 XCTAssertEqual(event->logical, kLogicalKeyW);
295 XCTAssertEqual(event->synthesized,
false);
297 [events removeAllObjects];
301 [responder
handlePress:keyUpEvent(kKeyCodeAltRight, kModifierFlagAltAny, 123.0f)
305 XCTAssertEqual([events count], 1u);
306 event = [events lastObject].data;
307 XCTAssertNotEqual(event,
nullptr);
308 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
309 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
310 XCTAssertEqual(event->physical, kPhysicalAltRight);
311 XCTAssertEqual(event->logical, kLogicalAltRight);
312 XCTAssertEqual(event->character,
nullptr);
313 XCTAssertEqual(event->synthesized,
false);
315 [events removeAllObjects];
322 [responder
handlePress:keyUpEvent(kKeyCodeKeyW, kModifierFlagAltAny, 123.0f)
326 XCTAssertEqual([events count], 1u);
327 event = [events lastObject].data;
328 XCTAssertNotEqual(event,
nullptr);
329 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
330 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
331 XCTAssertEqual(event->physical, kPhysicalKeyW);
332 XCTAssertEqual(event->logical, kLogicalKeyW);
333 XCTAssertEqual(event->character,
nullptr);
334 XCTAssertEqual(event->synthesized,
false);
336 [events removeAllObjects];
340 [responder
handlePress:keyDownEvent(kKeyCodeKeyA, kModifierFlagNone, 123.0f, "Ã ¥", "a")
344 XCTAssertEqual([events count], 1u);
345 event = [events lastObject].data;
346 XCTAssertNotEqual(event,
nullptr);
347 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
348 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
349 XCTAssertEqual(event->physical, kPhysicalKeyA);
350 XCTAssertEqual(event->logical, kLogicalKeyA);
352 XCTAssertEqual(event->synthesized,
false);
355 - (void)testIgnoreDuplicateDownEvent
API_AVAILABLE(ios(13.4)) {
356 __block NSMutableArray<TestKeyEvent*>* events = [[NSMutableArray<TestKeyEvent*> alloc] init];
357 __block BOOL last_handled = TRUE;
358 FlutterKeyEvent* event;
361 initWithSendEvent:^(const FlutterKeyEvent& event, _Nullable FlutterKeyEventCallback callback,
362 void* _Nullable user_data) {
363 [events addObject:[[
TestKeyEvent alloc] initWithEvent:&event
365 userData:user_data]];
368 last_handled = FALSE;
369 [responder
handlePress:keyDownEvent(kKeyCodeKeyA, kModifierFlagNone, 123.0f, "a", "a")
371 last_handled = handled;
374 XCTAssertEqual([events count], 1u);
375 event = [events lastObject].data;
376 XCTAssertNotEqual(event,
nullptr);
377 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
378 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
379 XCTAssertEqual(event->physical, kPhysicalKeyA);
380 XCTAssertEqual(event->logical, kLogicalKeyA);
382 XCTAssertEqual(event->synthesized,
false);
383 XCTAssertEqual(last_handled, FALSE);
384 [[events lastObject] respond:TRUE];
385 XCTAssertEqual(last_handled, TRUE);
387 [events removeAllObjects];
389 last_handled = FALSE;
390 [responder
handlePress:keyDownEvent(kKeyCodeKeyA, kModifierFlagNone, 123.0f, "a", "a")
392 last_handled = handled;
395 XCTAssertEqual([events count], 1u);
396 event = [events lastObject].data;
397 XCTAssertNotEqual(event,
nullptr);
398 XCTAssertEqual(event->physical, 0ull);
399 XCTAssertEqual(event->logical, 0ull);
400 XCTAssertEqual(event->synthesized,
false);
401 XCTAssertFalse([[events lastObject] hasCallback]);
402 XCTAssertEqual(last_handled, TRUE);
404 [events removeAllObjects];
406 last_handled = FALSE;
407 [responder
handlePress:keyUpEvent(kKeyCodeKeyA, kModifierFlagNone, 123.0f)
409 last_handled = handled;
412 XCTAssertEqual([events count], 1u);
413 event = [events lastObject].data;
414 XCTAssertNotEqual(event,
nullptr);
415 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
416 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
417 XCTAssertEqual(event->physical, kPhysicalKeyA);
418 XCTAssertEqual(event->logical, kLogicalKeyA);
419 XCTAssertEqual(event->character,
nullptr);
420 XCTAssertEqual(event->synthesized,
false);
421 XCTAssertEqual(last_handled, FALSE);
422 [[events lastObject] respond:TRUE];
423 XCTAssertEqual(last_handled, TRUE);
425 [events removeAllObjects];
429 __block NSMutableArray<TestKeyEvent*>* events = [[NSMutableArray<TestKeyEvent*> alloc] init];
430 __block BOOL last_handled = TRUE;
431 FlutterKeyEvent* event;
434 initWithSendEvent:^(const FlutterKeyEvent& event, _Nullable FlutterKeyEventCallback callback,
435 void* _Nullable user_data) {
436 [events addObject:[[
TestKeyEvent alloc] initWithEvent:&event
438 userData:user_data]];
441 last_handled = FALSE;
442 [responder
handlePress:keyUpEvent(kKeyCodeKeyA, kModifierFlagNone, 123.0f)
444 last_handled = handled;
447 XCTAssertEqual([events count], 1u);
448 event = [events lastObject].data;
449 XCTAssertNotEqual(event,
nullptr);
450 XCTAssertEqual(event->physical, 0ull);
451 XCTAssertEqual(event->logical, 0ull);
452 XCTAssertEqual(event->synthesized,
false);
453 XCTAssertFalse([[events lastObject] hasCallback]);
454 XCTAssertEqual(last_handled, TRUE);
456 [events removeAllObjects];
463 - (void)testToggleModifiersDuringKeyTap
API_AVAILABLE(ios(13.4)) {
464 __block NSMutableArray<TestKeyEvent*>* events = [[NSMutableArray<TestKeyEvent*> alloc] init];
465 FlutterKeyEvent* event;
468 initWithSendEvent:^(const FlutterKeyEvent& event, _Nullable FlutterKeyEventCallback callback,
469 void* _Nullable user_data) {
470 [events addObject:[[
TestKeyEvent alloc] initWithEvent:&event
472 userData:user_data]];
475 [responder
handlePress:keyDownEvent(kKeyCodeShiftRight, kModifierFlagShiftAny, 123.0f)
479 XCTAssertEqual([events count], 1u);
481 event = [events lastObject].data;
482 XCTAssertNotEqual(event,
nullptr);
483 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
484 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
485 XCTAssertEqual(event->timestamp, 123000000.0f);
486 XCTAssertEqual(event->physical, kPhysicalShiftRight);
487 XCTAssertEqual(event->logical, kLogicalShiftRight);
488 XCTAssertEqual(event->character,
nullptr);
489 XCTAssertEqual(event->synthesized,
false);
490 [[events lastObject] respond:TRUE];
492 [events removeAllObjects];
494 [responder
handlePress:keyDownEvent(kKeyCodeKeyA, kModifierFlagShiftAny, 123.0f, "A", "A")
498 XCTAssertEqual([events count], 1u);
499 event = [events lastObject].data;
500 XCTAssertNotEqual(event,
nullptr);
501 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
502 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
503 XCTAssertEqual(event->physical, kPhysicalKeyA);
504 XCTAssertEqual(event->logical, kLogicalKeyA);
506 XCTAssertEqual(event->synthesized,
false);
507 [[events lastObject] respond:TRUE];
509 [events removeAllObjects];
511 [responder
handlePress:keyUpEvent(kKeyCodeShiftRight, kModifierFlagNone, 123.0f)
515 XCTAssertEqual([events count], 1u);
516 event = [events lastObject].data;
517 XCTAssertNotEqual(event,
nullptr);
518 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
519 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
520 XCTAssertEqual(event->physical, kPhysicalShiftRight);
521 XCTAssertEqual(event->logical, kLogicalShiftRight);
522 XCTAssertEqual(event->character,
nullptr);
523 XCTAssertEqual(event->synthesized,
false);
524 [[events lastObject] respond:TRUE];
526 [events removeAllObjects];
528 [responder
handlePress:keyUpEvent(kKeyCodeKeyA, kModifierFlagNone, 123.0f)
532 XCTAssertEqual([events count], 1u);
533 event = [events lastObject].data;
534 XCTAssertNotEqual(event,
nullptr);
535 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
536 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
537 XCTAssertEqual(event->physical, kPhysicalKeyA);
538 XCTAssertEqual(event->logical, kLogicalKeyA);
539 XCTAssertEqual(event->character,
nullptr);
540 XCTAssertEqual(event->synthesized,
false);
541 [[events lastObject] respond:TRUE];
543 [events removeAllObjects];
552 __block NSMutableArray<TestKeyEvent*>* events = [[NSMutableArray<TestKeyEvent*> alloc] init];
553 FlutterKeyEvent* event;
554 __block BOOL last_handled = TRUE;
555 id keyEventCallback = ^(BOOL handled) {
556 last_handled = handled;
560 initWithSendEvent:^(const FlutterKeyEvent& event, _Nullable FlutterKeyEventCallback callback,
561 void* _Nullable user_data) {
562 [events addObject:[[
TestKeyEvent alloc] initWithEvent:&event
564 userData:user_data]];
572 [responder
handlePress:keyDownEvent(kKeyCodeNumpad1, kModifierFlagNumPadKey, 123.0, "1", "1")
575 XCTAssertEqual([events count], 1u);
576 event = [events lastObject].data;
577 XCTAssertNotEqual(event,
nullptr);
578 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
579 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
580 XCTAssertEqual(event->physical, kPhysicalNumpad1);
581 XCTAssertEqual(event->logical, kLogicalNumpad1);
583 XCTAssertEqual(event->synthesized,
false);
584 [[events lastObject] respond:TRUE];
586 [events removeAllObjects];
590 [responder
handlePress:keyDownEvent(kKeyCodeUndefined, kModifierFlagNone, 123.0)
593 XCTAssertEqual([events count], 1u);
594 event = [events lastObject].data;
595 XCTAssertNotEqual(event,
nullptr);
596 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
597 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
598 XCTAssertEqual(event->physical, kPhysicalKeyUndefined);
599 XCTAssertEqual(event->logical, kLogicalKeyUndefined);
600 XCTAssertEqual(event->character,
nullptr);
601 XCTAssertEqual(event->synthesized,
false);
602 [[events lastObject] respond:TRUE];
604 [events removeAllObjects];
608 [responder
handlePress:keyDownEvent(kKeyCodeF1, kModifierFlagNone, 123.0f, "\\^P", "\\^P")
611 XCTAssertEqual([events count], 1u);
612 event = [events lastObject].data;
613 XCTAssertNotEqual(event,
nullptr);
614 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
615 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
616 XCTAssertEqual(event->physical, kPhysicalF1);
617 XCTAssertEqual(event->logical, kLogicalF1);
618 XCTAssertEqual(event->character,
nullptr);
619 XCTAssertEqual(event->synthesized,
false);
620 [[events lastObject] respond:TRUE];
622 [events removeAllObjects];
626 [responder
handlePress:keyDownEvent(kKeyCodeKeyA, kModifierFlagNone, 123.0f, "a", "a")
629 XCTAssertEqual([events count], 1u);
630 event = [events lastObject].data;
631 XCTAssertNotEqual(event,
nullptr);
632 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
633 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
634 XCTAssertEqual(event->physical, kPhysicalKeyA);
635 XCTAssertEqual(event->logical, kLogicalKeyA);
637 XCTAssertEqual(event->synthesized,
false);
638 [[events lastObject] respond:TRUE];
640 [events removeAllObjects];
644 [responder
handlePress:keyDownEvent(kKeyCodeShiftLeft, kModifierFlagShiftAny, 123.0f)
647 XCTAssertEqual([events count], 1u);
648 event = [events lastObject].data;
649 XCTAssertNotEqual(event,
nullptr);
650 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
651 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
652 XCTAssertEqual(event->physical, kPhysicalShiftLeft);
653 XCTAssertEqual(event->logical, kLogicalShiftLeft);
654 XCTAssertEqual(event->character,
nullptr);
655 XCTAssertEqual(event->synthesized,
false);
657 [events removeAllObjects];
661 [responder
handlePress:keyUpEvent(kKeyCodeNumpad1, kModifierFlagNumPadKey, 123.0f)
664 XCTAssertEqual([events count], 2u);
668 event = [events firstObject].data;
669 XCTAssertNotEqual(event,
nullptr);
670 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
671 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
672 XCTAssertEqual(event->physical, kPhysicalShiftLeft);
673 XCTAssertEqual(event->logical, kLogicalShiftLeft);
674 XCTAssertEqual(event->character,
nullptr);
675 XCTAssertEqual(event->synthesized,
true);
677 event = [events lastObject].data;
678 XCTAssertNotEqual(event,
nullptr);
679 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
680 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
681 XCTAssertEqual(event->physical, kPhysicalNumpad1);
682 XCTAssertEqual(event->logical, kLogicalNumpad1);
683 XCTAssertEqual(event->character,
nullptr);
684 XCTAssertEqual(event->synthesized,
false);
685 [[events lastObject] respond:TRUE];
687 [events removeAllObjects];
691 [responder
handlePress:keyUpEvent(kKeyCodeF1, kModifierFlagNone, 123.0f)
694 XCTAssertEqual([events count], 1u);
695 event = [events lastObject].data;
696 XCTAssertNotEqual(event,
nullptr);
697 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
698 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
699 XCTAssertEqual(event->physical, kPhysicalF1);
700 XCTAssertEqual(event->logical, kLogicalF1);
701 XCTAssertEqual(event->character,
nullptr);
702 XCTAssertEqual(event->synthesized,
false);
703 [[events lastObject] respond:TRUE];
705 [events removeAllObjects];
709 [responder
handlePress:keyUpEvent(kKeyCodeUndefined, kModifierFlagNone, 123.0)
712 XCTAssertEqual([events count], 1u);
713 event = [events lastObject].data;
714 XCTAssertNotEqual(event,
nullptr);
715 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
716 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
717 XCTAssertEqual(event->physical, kPhysicalKeyUndefined);
718 XCTAssertEqual(event->logical, kLogicalKeyUndefined);
719 XCTAssertEqual(event->synthesized,
false);
720 [[events lastObject] respond:TRUE];
722 [events removeAllObjects];
726 [responder
handlePress:keyUpEvent(kKeyCodeKeyA, kModifierFlagNone, 123.0f)
729 XCTAssertEqual([events count], 1u);
730 event = [events lastObject].data;
731 XCTAssertNotEqual(event,
nullptr);
732 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
733 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
734 XCTAssertEqual(event->physical, kPhysicalKeyA);
735 XCTAssertEqual(event->logical, kLogicalKeyA);
736 XCTAssertEqual(event->character,
nullptr);
737 XCTAssertEqual(event->synthesized,
false);
738 [[events lastObject] respond:TRUE];
740 [events removeAllObjects];
744 [responder
handlePress:keyUpEvent(kKeyCodeShiftLeft, kModifierFlagShiftAny, 123.0f)
747 XCTAssertEqual([events count], 1u);
748 event = [events lastObject].data;
749 XCTAssertNotEqual(event,
nullptr);
750 XCTAssertEqual(event->physical, 0ull);
751 XCTAssertEqual(event->logical, 0ull);
752 XCTAssertEqual(event->synthesized,
false);
753 XCTAssertFalse([[events lastObject] hasCallback]);
754 XCTAssertEqual(last_handled, TRUE);
756 [events removeAllObjects];
759 - (void)testIdentifyLeftAndRightModifiers
API_AVAILABLE(ios(13.4)) {
760 __block NSMutableArray<TestKeyEvent*>* events = [[NSMutableArray<TestKeyEvent*> alloc] init];
761 FlutterKeyEvent* event;
764 initWithSendEvent:^(const FlutterKeyEvent& event, _Nullable FlutterKeyEventCallback callback,
765 void* _Nullable user_data) {
766 [events addObject:[[
TestKeyEvent alloc] initWithEvent:&event
768 userData:user_data]];
771 [responder
handlePress:keyDownEvent(kKeyCodeShiftLeft, kModifierFlagShiftAny, 123.0f)
775 XCTAssertEqual([events count], 1u);
776 event = [events lastObject].data;
777 XCTAssertNotEqual(event,
nullptr);
778 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
779 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
780 XCTAssertEqual(event->physical, kPhysicalShiftLeft);
781 XCTAssertEqual(event->logical, kLogicalShiftLeft);
782 XCTAssertEqual(event->character,
nullptr);
783 XCTAssertEqual(event->synthesized,
false);
784 [[events lastObject] respond:TRUE];
786 [events removeAllObjects];
788 [responder
handlePress:keyDownEvent(kKeyCodeShiftRight, kModifierFlagShiftAny, 123.0f)
792 XCTAssertEqual([events count], 1u);
793 event = [events lastObject].data;
794 XCTAssertNotEqual(event,
nullptr);
795 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
796 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
797 XCTAssertEqual(event->physical, kPhysicalShiftRight);
798 XCTAssertEqual(event->logical, kLogicalShiftRight);
799 XCTAssertEqual(event->character,
nullptr);
800 XCTAssertEqual(event->synthesized,
false);
801 [[events lastObject] respond:TRUE];
803 [events removeAllObjects];
805 [responder
handlePress:keyUpEvent(kKeyCodeShiftLeft, kModifierFlagShiftAny, 123.0f)
809 XCTAssertEqual([events count], 1u);
810 event = [events lastObject].data;
811 XCTAssertNotEqual(event,
nullptr);
812 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
813 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
814 XCTAssertEqual(event->physical, kPhysicalShiftLeft);
815 XCTAssertEqual(event->logical, kLogicalShiftLeft);
816 XCTAssertEqual(event->character,
nullptr);
817 XCTAssertEqual(event->synthesized,
false);
818 [[events lastObject] respond:TRUE];
820 [events removeAllObjects];
822 [responder
handlePress:keyUpEvent(kKeyCodeShiftRight, kModifierFlagShiftAny, 123.0f)
826 XCTAssertEqual([events count], 1u);
827 event = [events lastObject].data;
828 XCTAssertNotEqual(event,
nullptr);
829 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
830 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
831 XCTAssertEqual(event->physical, kPhysicalShiftRight);
832 XCTAssertEqual(event->logical, kLogicalShiftRight);
833 XCTAssertEqual(event->character,
nullptr);
834 XCTAssertEqual(event->synthesized,
false);
835 [[events lastObject] respond:TRUE];
837 [events removeAllObjects];
841 - (void)testSynchronizeCapsLockStateOnCapsLock
API_AVAILABLE(ios(13.4)) {
842 __block NSMutableArray<TestKeyEvent*>* events = [[NSMutableArray<TestKeyEvent*> alloc] init];
843 __block BOOL last_handled = TRUE;
844 id keyEventCallback = ^(BOOL handled) {
845 last_handled = handled;
847 FlutterKeyEvent* event;
850 initWithSendEvent:^(const FlutterKeyEvent& event, _Nullable FlutterKeyEventCallback callback,
851 void* _Nullable user_data) {
852 [events addObject:[[
TestKeyEvent alloc] initWithEvent:&event
854 userData:user_data]];
857 last_handled = FALSE;
858 [responder
handlePress:keyDownEvent(kKeyCodeKeyA, kModifierFlagCapsLock, 123.0f, "A", "A")
861 XCTAssertEqual([events count], 3u);
863 event = events[0].data;
864 XCTAssertNotEqual(event,
nullptr);
865 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
866 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
867 XCTAssertEqual(event->physical, kPhysicalCapsLock);
868 XCTAssertEqual(event->logical, kLogicalCapsLock);
869 XCTAssertEqual(event->character,
nullptr);
870 XCTAssertEqual(event->synthesized,
true);
871 XCTAssertFalse([events[0] hasCallback]);
873 event = events[1].data;
874 XCTAssertNotEqual(event,
nullptr);
875 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
876 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
877 XCTAssertEqual(event->physical, kPhysicalCapsLock);
878 XCTAssertEqual(event->logical, kLogicalCapsLock);
879 XCTAssertEqual(event->character,
nullptr);
880 XCTAssertEqual(event->synthesized,
true);
881 XCTAssertFalse([events[1] hasCallback]);
883 event = events[2].data;
884 XCTAssertNotEqual(event,
nullptr);
885 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
886 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
887 XCTAssertEqual(event->physical, kPhysicalKeyA);
888 XCTAssertEqual(event->logical, kLogicalKeyA);
890 XCTAssertEqual(event->synthesized,
false);
891 XCTAssert([events[2] hasCallback]);
893 XCTAssertEqual(last_handled, FALSE);
894 [[events lastObject] respond:TRUE];
895 XCTAssertEqual(last_handled, TRUE);
897 [events removeAllObjects];
900 [responder
handlePress:keyUpEvent(kKeyCodeKeyA, kModifierFlagCapsLock, 123.0f)
902 XCTAssertEqual([events count], 1u);
903 event = [events lastObject].data;
904 XCTAssertNotEqual(event,
nullptr);
905 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
906 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
907 XCTAssertEqual(event->physical, kPhysicalKeyA);
908 XCTAssertEqual(event->logical, kLogicalKeyA);
909 XCTAssertEqual(event->synthesized,
false);
911 [events removeAllObjects];
915 last_handled = FALSE;
916 [responder
handlePress:keyDownEvent(kKeyCodeCapsLock, kModifierFlagCapsLock, 123.0f)
919 XCTAssertEqual([events count], 1u);
920 event = [events firstObject].data;
921 XCTAssertNotEqual(event,
nullptr);
922 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
923 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
924 XCTAssertEqual(event->physical, kPhysicalCapsLock);
925 XCTAssertEqual(event->logical, kLogicalCapsLock);
926 XCTAssertEqual(event->character,
nullptr);
927 XCTAssertEqual(event->synthesized,
false);
928 XCTAssert([[events firstObject] hasCallback]);
930 [events removeAllObjects];
936 last_handled = FALSE;
937 [responder
handlePress:keyUpEvent(kKeyCodeCapsLock, kModifierFlagCapsLock, 123.0f)
940 XCTAssertEqual([events count], 1u);
941 event = [events firstObject].data;
942 XCTAssertNotEqual(event,
nullptr);
943 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
944 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
945 XCTAssertEqual(event->physical, kPhysicalCapsLock);
946 XCTAssertEqual(event->logical, kLogicalCapsLock);
947 XCTAssertEqual(event->character,
nullptr);
948 XCTAssertEqual(event->synthesized,
false);
949 XCTAssert([[events firstObject] hasCallback]);
951 [events removeAllObjects];
953 last_handled = FALSE;
954 [responder
handlePress:keyDownEvent(kKeyCodeKeyA, kModifierFlagNone, 123.0f, "a", "a")
959 XCTAssertEqual([events count], 1u);
960 event = [events lastObject].data;
961 XCTAssertNotEqual(event,
nullptr);
962 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
963 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
964 XCTAssertEqual(event->physical, kPhysicalKeyA);
965 XCTAssertEqual(event->logical, kLogicalKeyA);
967 XCTAssertEqual(event->synthesized,
false);
968 XCTAssert([[events firstObject] hasCallback]);
972 - (void)testSynchronizeCapsLockStateOnNormalKey
API_AVAILABLE(ios(13.4)) {
973 __block NSMutableArray<TestKeyEvent*>* events = [[NSMutableArray<TestKeyEvent*> alloc] init];
974 __block BOOL last_handled = TRUE;
975 id keyEventCallback = ^(BOOL handled) {
976 last_handled = handled;
978 FlutterKeyEvent* event;
981 initWithSendEvent:^(const FlutterKeyEvent& event, _Nullable FlutterKeyEventCallback callback,
982 void* _Nullable user_data) {
983 [events addObject:[[
TestKeyEvent alloc] initWithEvent:&event
985 userData:user_data]];
988 last_handled = FALSE;
989 [responder
handlePress:keyDownEvent(kKeyCodeKeyA, kModifierFlagCapsLock, 123.0f, "A", "a")
992 XCTAssertEqual([events count], 3u);
994 event = events[0].data;
995 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
996 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
997 XCTAssertEqual(event->physical, kPhysicalCapsLock);
998 XCTAssertEqual(event->logical, kLogicalCapsLock);
999 XCTAssertEqual(event->character,
nullptr);
1000 XCTAssertEqual(event->synthesized,
true);
1001 XCTAssertFalse([events[0] hasCallback]);
1003 event = events[1].data;
1004 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
1005 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
1006 XCTAssertEqual(event->physical, kPhysicalCapsLock);
1007 XCTAssertEqual(event->logical, kLogicalCapsLock);
1008 XCTAssertEqual(event->character,
nullptr);
1009 XCTAssertEqual(event->synthesized,
true);
1010 XCTAssertFalse([events[1] hasCallback]);
1012 event = events[2].data;
1013 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
1014 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
1015 XCTAssertEqual(event->physical, kPhysicalKeyA);
1016 XCTAssertEqual(event->logical, kLogicalKeyA);
1018 XCTAssertEqual(event->synthesized,
false);
1019 XCTAssert([events[2] hasCallback]);
1021 XCTAssertEqual(last_handled, FALSE);
1022 [[events lastObject] respond:TRUE];
1023 XCTAssertEqual(last_handled, TRUE);
1025 [events removeAllObjects];
1030 __block NSMutableArray<TestKeyEvent*>* events = [[NSMutableArray<TestKeyEvent*> alloc] init];
1031 id keyEventCallback = ^(BOOL handled) {
1033 FlutterKeyEvent* event;
1036 initWithSendEvent:^(const FlutterKeyEvent& event, _Nullable FlutterKeyEventCallback callback,
1037 void* _Nullable user_data) {
1038 [events addObject:[[
TestKeyEvent alloc] initWithEvent:&event callback:nil userData:nil]];
1039 callback(true, user_data);
1043 [responder
handlePress:keyDownEvent(kKeyCodeCommandLeft, kModifierFlagMetaAny, 123.0f, "", "")
1045 XCTAssertEqual([events count], 1u);
1046 event = events[0].data;
1047 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
1048 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
1049 XCTAssertEqual(event->physical, kPhysicalMetaLeft);
1050 XCTAssertEqual(event->logical, kLogicalMetaLeft);
1051 XCTAssertEqual(event->character,
nullptr);
1052 XCTAssertEqual(event->synthesized,
false);
1053 [events removeAllObjects];
1056 [responder
handlePress:keyDownEvent(kKeyCodePeriod, kModifierFlagMetaAny, 123.0f,
1057 "UIKeyInputEscape", "UIKeyInputEscape")
1059 XCTAssertEqual([events count], 1u);
1060 event = events[0].data;
1061 XCTAssertEqual(event->type, kFlutterKeyEventTypeDown);
1062 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
1063 XCTAssertEqual(event->physical, kPhysicalPeriod);
1064 XCTAssertEqual(event->logical, kLogicalEscape);
1065 XCTAssertEqual(event->character,
nullptr);
1066 XCTAssertEqual(event->synthesized,
false);
1067 [events removeAllObjects];
1070 [responder
handlePress:keyUpEvent(kKeyCodePeriod, kModifierFlagMetaAny, 123.0f,
1071 "UIKeyInputEscape", "UIKeyInputEscape")
1073 XCTAssertEqual([events count], 1u);
1074 event = events[0].data;
1075 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
1076 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
1077 XCTAssertEqual(event->physical, kPhysicalPeriod);
1078 XCTAssertEqual(event->logical, kLogicalEscape);
1079 XCTAssertEqual(event->character,
nullptr);
1080 XCTAssertEqual(event->synthesized,
false);
1081 [events removeAllObjects];
1084 [responder
handlePress:keyUpEvent(kKeyCodeCommandLeft, kModifierFlagMetaAny, 123.0f, "", "")
1086 XCTAssertEqual([events count], 1u);
1087 event = events[0].data;
1088 XCTAssertEqual(event->type, kFlutterKeyEventTypeUp);
1089 XCTAssertEqual(event->device_type, kFlutterKeyEventDeviceTypeKeyboard);
1090 XCTAssertEqual(event->physical, kPhysicalMetaLeft);
1091 XCTAssertEqual(event->logical, kLogicalMetaLeft);
1092 XCTAssertEqual(event->character,
nullptr);
1093 XCTAssertEqual(event->synthesized,
false);
1094 [events removeAllObjects];