@@ -62,6 +62,7 @@ - (UIAccessibilityContrast)accessibilityContrast;
6262@interface FlutterViewController (Tests)
6363- (void )surfaceUpdated : (BOOL )appeared ;
6464- (void )performOrientationUpdate : (UIInterfaceOrientationMask)new_preferences ;
65+ - (void )dispatchPresses : (NSSet <UIPress*>*)presses ;
6566@end
6667
6768@implementation FlutterViewControllerTest
@@ -549,4 +550,150 @@ - (void)testNotifyLowMemory {
549550 OCMVerify ([engine notifyLowMemory ]);
550551}
551552
553+ - (void )testValidKeyUpEvent API_AVAILABLE(ios(13.4 )) {
554+ if (@available (iOS 13.4 , *)) {
555+ // noop
556+ } else {
557+ return ;
558+ }
559+
560+ id engine = OCMClassMock ([FlutterEngine class ]);
561+
562+ id keyEventChannel = OCMClassMock ([FlutterBasicMessageChannel class ]);
563+ OCMStub ([engine keyEventChannel ]).andReturn (keyEventChannel);
564+
565+ FlutterViewController* vc = [[FlutterViewController alloc ] initWithEngine: engine
566+ nibName: nil
567+ bundle: nil ];
568+
569+ id testSet = [self fakeUiPressSetForPhase: UIPressPhaseBegan
570+ keyCode: UIKeyboardHIDUsageKeyboardA
571+ modifierFlags: UIKeyModifierShift
572+ characters: @" a"
573+ charactersIgnoringModifiers: @" A" ];
574+
575+ // Exercise behavior under test.
576+ [vc dispatchPresses: testSet];
577+
578+ // Verify behavior.
579+ OCMVerify ([keyEventChannel
580+ sendMessage: [OCMArg checkWithBlock: ^BOOL (id message) {
581+ return [message[@" keymap" ] isEqualToString: @" ios" ] &&
582+ [message[@" type" ] isEqualToString: @" keydown" ] &&
583+ [message[@" keyCode" ] isEqualToNumber: [NSNumber numberWithInt: 4 ]] &&
584+ [message[@" modifiers" ] isEqualToNumber: [NSNumber numberWithInt: 131072 ]] &&
585+ [message[@" characters" ] isEqualToString: @" a" ] &&
586+ [message[@" charactersIgnoringModifiers" ] isEqualToString: @" A" ];
587+ }]]);
588+
589+ // Clean up mocks
590+ [engine stopMocking ];
591+ [keyEventChannel stopMocking ];
592+ }
593+
594+ - (void )testValidKeyDownEvent API_AVAILABLE(ios(13.4 )) {
595+ if (@available (iOS 13.4 , *)) {
596+ // noop
597+ } else {
598+ return ;
599+ }
600+
601+ id engine = OCMClassMock ([FlutterEngine class ]);
602+
603+ id keyEventChannel = OCMClassMock ([FlutterBasicMessageChannel class ]);
604+ OCMStub ([engine keyEventChannel ]).andReturn (keyEventChannel);
605+
606+ FlutterViewController* vc = [[FlutterViewController alloc ] initWithEngine: engine
607+ nibName: nil
608+ bundle: nil ];
609+
610+ id testSet = [self fakeUiPressSetForPhase: UIPressPhaseEnded
611+ keyCode: UIKeyboardHIDUsageKeyboardA
612+ modifierFlags: UIKeyModifierShift
613+ characters: @" a"
614+ charactersIgnoringModifiers: @" A" ];
615+
616+ // Exercise behavior under test.
617+ [vc dispatchPresses: testSet];
618+
619+ // Verify behavior.
620+ OCMVerify ([keyEventChannel
621+ sendMessage: [OCMArg checkWithBlock: ^BOOL (id message) {
622+ return [message[@" keymap" ] isEqualToString: @" ios" ] &&
623+ [message[@" type" ] isEqualToString: @" keyup" ] &&
624+ [message[@" keyCode" ] isEqualToNumber: [NSNumber numberWithInt: 4 ]] &&
625+ [message[@" modifiers" ] isEqualToNumber: [NSNumber numberWithInt: 131072 ]] &&
626+ [message[@" characters" ] isEqualToString: @" a" ] &&
627+ [message[@" charactersIgnoringModifiers" ] isEqualToString: @" A" ];
628+ }]]);
629+
630+ // Clean up mocks
631+ [engine stopMocking ];
632+ [keyEventChannel stopMocking ];
633+ }
634+
635+ - (void )testIgnoredKeyEvents API_AVAILABLE(ios(13.4 )) {
636+ if (@available (iOS 13.4 , *)) {
637+ // noop
638+ } else {
639+ return ;
640+ }
641+
642+ id engine = OCMClassMock ([FlutterEngine class ]);
643+
644+ id keyEventChannel = OCMClassMock ([FlutterBasicMessageChannel class ]);
645+ OCMStub ([engine keyEventChannel ]).andReturn (keyEventChannel);
646+
647+ FlutterViewController* vc = [[FlutterViewController alloc ] initWithEngine: engine
648+ nibName: nil
649+ bundle: nil ];
650+
651+ id emptySet = [NSSet set ];
652+ id ignoredSet = [self fakeUiPressSetForPhase: UIPressPhaseStationary
653+ keyCode: UIKeyboardHIDUsageKeyboardA
654+ modifierFlags: UIKeyModifierShift
655+ characters: @" a"
656+ charactersIgnoringModifiers: @" A" ];
657+
658+ id mockUiPress = OCMClassMock ([UIPress class ]);
659+ OCMStub ([mockUiPress phase ]).andReturn (UIPressPhaseBegan);
660+ id emptyKeySet = [NSSet setWithArray: @[ mockUiPress ]];
661+ // Exercise behavior under test.
662+ [vc dispatchPresses: emptySet];
663+ [vc dispatchPresses: ignoredSet];
664+ [vc dispatchPresses: emptyKeySet];
665+
666+ // Verify behavior.
667+ OCMVerify (never (), [keyEventChannel sendMessage: [OCMArg any ]]);
668+
669+ // Clean up mocks
670+ [engine stopMocking ];
671+ [keyEventChannel stopMocking ];
672+ }
673+
674+ - (NSSet <UIPress*>*)fakeUiPressSetForPhase : (UIPressPhase)phase
675+ keyCode : (UIKeyboardHIDUsage)keyCode
676+ modifierFlags : (UIKeyModifierFlags)modifierFlags
677+ characters : (NSString *)characters
678+ charactersIgnoringModifiers : (NSString *)charactersIgnoringModifiers
679+ API_AVAILABLE(ios(13.4 )) {
680+ if (@available (iOS 13.4 , *)) {
681+ // noop
682+ } else {
683+ return [NSSet set ];
684+ }
685+ id mockUiPress = OCMClassMock ([UIPress class ]);
686+ OCMStub ([mockUiPress phase ]).andReturn (phase);
687+
688+ id mockUiKey = OCMClassMock ([UIKey class ]);
689+ OCMStub ([mockUiKey keyCode ]).andReturn (keyCode);
690+ OCMStub ([mockUiKey modifierFlags ]).andReturn (modifierFlags);
691+ OCMStub ([mockUiKey characters ]).andReturn (characters);
692+ OCMStub ([mockUiKey charactersIgnoringModifiers ]).andReturn (charactersIgnoringModifiers);
693+
694+ OCMStub ([mockUiPress key ]).andReturn (mockUiKey);
695+
696+ return [NSSet setWithArray: @[ mockUiPress ]];
697+ }
698+
552699@end
0 commit comments