Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
keyboard_unittests.cc File Reference

Go to the source code of this file.

Namespaces

namespace  flutter
 
namespace  flutter::testing
 

Macros

#define EXPECT_CALL_IS_EVENT(_key_call, _type, _physical, _logical, _character, _synthesized)
 
#define EXPECT_CALL_IS_TEXT(_key_call, u16_string)
 
#define EXPECT_CALL_IS_TEXT_METHOD_CALL(_key_call, json_string)
 

Functions

 flutter::testing::TEST_F (KeyboardTest, LowerCaseAHandled)
 
 flutter::testing::TEST_F (KeyboardTest, LowerCaseAUnhandled)
 
 flutter::testing::TEST_F (KeyboardTest, ArrowLeftHandled)
 
 flutter::testing::TEST_F (KeyboardTest, ArrowLeftUnhandled)
 
 flutter::testing::TEST_F (KeyboardTest, ShiftLeftUnhandled)
 
 flutter::testing::TEST_F (KeyboardTest, ShiftRightUnhandled)
 
 flutter::testing::TEST_F (KeyboardTest, CtrlLeftUnhandled)
 
 flutter::testing::TEST_F (KeyboardTest, CtrlRightUnhandled)
 
 flutter::testing::TEST_F (KeyboardTest, AltLeftUnhandled)
 
 flutter::testing::TEST_F (KeyboardTest, AltRightUnhandled)
 
 flutter::testing::TEST_F (KeyboardTest, MetaLeftUnhandled)
 
 flutter::testing::TEST_F (KeyboardTest, MetaRightUnhandled)
 
 flutter::testing::TEST_F (KeyboardTest, RepeatA)
 
 flutter::testing::TEST_F (KeyboardTest, RestartClearsKeyboardState)
 
 flutter::testing::TEST_F (KeyboardTest, FreshKeyDownAfterMissedUpIsDelivered)
 
 flutter::testing::TEST_F (KeyboardTest, ShiftLeftKeyA)
 
 flutter::testing::TEST_F (KeyboardTest, CtrlLeftKeyA)
 
 flutter::testing::TEST_F (KeyboardTest, CtrlLeftDigit1)
 
 flutter::testing::TEST_F (KeyboardTest, Digit1OnFrenchLayout)
 
 flutter::testing::TEST_F (KeyboardTest, AltGrModifiedKey)
 
 flutter::testing::TEST_F (KeyboardTest, AltGrTwice)
 
 flutter::testing::TEST_F (KeyboardTest, DeadKeyThatCombines)
 
 flutter::testing::TEST_F (KeyboardTest, DeadKeyWithoutDeadMaskThatCombines)
 
 flutter::testing::TEST_F (KeyboardTest, DeadKeyThatDoesNotCombine)
 
 flutter::testing::TEST_F (KeyboardTest, DeadKeyTwiceThenLetter)
 
 flutter::testing::TEST_F (KeyboardTest, MultibyteCharacter)
 
 flutter::testing::TEST_F (KeyboardTest, SynthesizeModifiers)
 
 flutter::testing::TEST_F (KeyboardTest, ImeExtendedEventsAreIgnored)
 
 flutter::testing::TEST_F (KeyboardTest, UpOnlyImeEventsAreCorrectlyHandled)
 
 flutter::testing::TEST_F (KeyboardTest, SlowFrameworkResponse)
 
 flutter::testing::TEST_F (KeyboardTest, SlowFrameworkResponseForIdenticalEvents)
 
 flutter::testing::TEST_F (KeyboardTest, TextInputSubmit)
 
 flutter::testing::TEST_F (KeyboardTest, VietnameseTelexAddDiacriticWithFastResponse)
 
void flutter::testing::VietnameseTelexAddDiacriticWithSlowResponse (WindowsTestContext &context, bool backspace_response)
 
 flutter::testing::TEST_F (KeyboardTest, VietnameseTelexAddDiacriticWithSlowFalseResponse)
 
 flutter::testing::TEST_F (KeyboardTest, VietnameseTelexAddDiacriticWithSlowTrueResponse)
 
 flutter::testing::TEST_F (KeyboardTest, DoubleCapsLock)
 

Macro Definition Documentation

◆ EXPECT_CALL_IS_EVENT

#define EXPECT_CALL_IS_EVENT (   _key_call,
  _type,
  _physical,
  _logical,
  _character,
  _synthesized 
)
Value:
EXPECT_EQ(_key_call.type, KeyCall::kKeyCallOnKey); \
EXPECT_EVENT_EQUALS(_key_call.key_event, _type, _physical, _logical, \
_character, _synthesized);

Definition at line 558 of file keyboard_unittests.cc.

571 {
572 KeyboardTester tester{GetContext()};
573 tester.Responding(true);
574
575 // US Keyboard layout
576
577 // Press A
578 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
580 kWmResultZero),
581 WmCharInfo{'a', kScanCodeKeyA, kNotExtended, kWasUp}.Build(
582 kWmResultZero)});
583
584 EXPECT_EQ(tester.key_calls.size(), 1);
586 kPhysicalKeyA, kLogicalKeyA, "a", kNotSynthesized);
587 tester.clear_key_calls();
588 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
589
590 // Release A
591 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
593 kWmResultZero)});
594
595 EXPECT_EQ(tester.key_calls.size(), 1);
596 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
597 kPhysicalKeyA, kLogicalKeyA, "", kNotSynthesized);
598 tester.clear_key_calls();
599 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
600}
601
602TEST_F(KeyboardTest, LowerCaseAUnhandled) {
603 KeyboardTester tester{GetContext()};
604 tester.Responding(false);
605
606 // US Keyboard layout
607
608 // Press A
609 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
611 kWmResultZero),
612 WmCharInfo{'a', kScanCodeKeyA, kNotExtended, kWasUp}.Build(
613 kWmResultZero)});
614
615 EXPECT_EQ(tester.key_calls.size(), 2);
617 kPhysicalKeyA, kLogicalKeyA, "a", kNotSynthesized);
618 EXPECT_CALL_IS_TEXT(tester.key_calls[1], u"a");
619 tester.clear_key_calls();
620 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
621
622 // Release A
623 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
625 kWmResultZero)});
626
627 EXPECT_EQ(tester.key_calls.size(), 1);
628 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
629 kPhysicalKeyA, kLogicalKeyA, "", kNotSynthesized);
630 tester.clear_key_calls();
631 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
632}
633
634TEST_F(KeyboardTest, ArrowLeftHandled) {
635 KeyboardTester tester{GetContext()};
636 tester.Responding(true);
637
638 // US Keyboard layout
639
640 // Press ArrowLeft
641 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
642 WmKeyDownInfo{VK_LEFT, kScanCodeArrowLeft, kExtended, kWasUp}.Build(
643 kWmResultZero)});
644
645 EXPECT_EQ(tester.key_calls.size(), 1);
647 kPhysicalArrowLeft, kLogicalArrowLeft, "",
648 kNotSynthesized);
649 tester.clear_key_calls();
650 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
651
652 // Release ArrowLeft
653 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
654 WmKeyUpInfo{VK_LEFT, kScanCodeArrowLeft, kExtended}.Build(
655 kWmResultZero)});
656
657 EXPECT_EQ(tester.key_calls.size(), 1);
658 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
659 kPhysicalArrowLeft, kLogicalArrowLeft, "",
660 kNotSynthesized);
661 tester.clear_key_calls();
662 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
663}
664
665TEST_F(KeyboardTest, ArrowLeftUnhandled) {
666 KeyboardTester tester{GetContext()};
667 tester.Responding(false);
668
669 // US Keyboard layout
670
671 // Press ArrowLeft
672 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
673 WmKeyDownInfo{VK_LEFT, kScanCodeArrowLeft, kExtended, kWasUp}.Build(
674 kWmResultZero)});
675
676 EXPECT_EQ(tester.key_calls.size(), 1);
678 kPhysicalArrowLeft, kLogicalArrowLeft, "",
679 kNotSynthesized);
680 tester.clear_key_calls();
681 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
682
683 // Release ArrowLeft
684 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
685 WmKeyUpInfo{VK_LEFT, kScanCodeArrowLeft, kExtended}.Build(
686 kWmResultZero)});
687
688 EXPECT_EQ(tester.key_calls.size(), 1);
689 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
690 kPhysicalArrowLeft, kLogicalArrowLeft, "",
691 kNotSynthesized);
692 tester.clear_key_calls();
693 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
694}
695
696TEST_F(KeyboardTest, ShiftLeftUnhandled) {
697 KeyboardTester tester{GetContext()};
698 tester.Responding(false);
699
700 // US Keyboard layout
701
702 // Press ShiftLeft
703 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
704 KeyStateChange{VK_LSHIFT, true, false},
706 kWmResultZero)});
707
708 EXPECT_EQ(tester.key_calls.size(), 1);
710 kPhysicalShiftLeft, kLogicalShiftLeft, "",
711 kNotSynthesized);
712 tester.clear_key_calls();
713 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
714
715 // Hold ShiftLeft
716 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
718 kWmResultZero)});
719
720 EXPECT_EQ(tester.key_calls.size(), 1);
722 kPhysicalShiftLeft, kLogicalShiftLeft, "",
723 kNotSynthesized);
724 tester.clear_key_calls();
725 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
726
727 // Release ShiftLeft
728 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
729 KeyStateChange{VK_LSHIFT, false, true},
731 kWmResultZero)});
732
733 EXPECT_EQ(tester.key_calls.size(), 1);
734 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
735 kPhysicalShiftLeft, kLogicalShiftLeft, "",
736 kNotSynthesized);
737 tester.clear_key_calls();
738 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
739}
740
741TEST_F(KeyboardTest, ShiftRightUnhandled) {
742 KeyboardTester tester{GetContext()};
743 tester.Responding(false);
744
745 // US Keyboard layout
746
747 // Press ShiftRight
748 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
749 KeyStateChange{VK_RSHIFT, true, false},
751 kWmResultZero)});
752
753 EXPECT_EQ(tester.key_calls.size(), 1);
755 kPhysicalShiftRight, kLogicalShiftRight, "",
756 kNotSynthesized);
757 tester.clear_key_calls();
758 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
759
760 // Release ShiftRight
761 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
762 KeyStateChange{VK_RSHIFT, false, true},
764 kWmResultZero)});
765
766 EXPECT_EQ(tester.key_calls.size(), 1);
767 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
768 kPhysicalShiftRight, kLogicalShiftRight, "",
769 kNotSynthesized);
770 tester.clear_key_calls();
771 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
772}
773
774TEST_F(KeyboardTest, CtrlLeftUnhandled) {
775 KeyboardTester tester{GetContext()};
776 tester.Responding(false);
777
778 // US Keyboard layout
779
780 // Press CtrlLeft
781 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
782 KeyStateChange{VK_LCONTROL, true, false},
783 WmKeyDownInfo{VK_CONTROL, kScanCodeControl, kNotExtended, kWasUp}.Build(
784 kWmResultZero)});
785
786 EXPECT_EQ(tester.key_calls.size(), 1);
788 kPhysicalControlLeft, kLogicalControlLeft, "",
789 kNotSynthesized);
790 tester.clear_key_calls();
791 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
792
793 // Release CtrlLeft
794 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
795 KeyStateChange{VK_LCONTROL, false, true},
796 WmKeyUpInfo{VK_SHIFT, kScanCodeControl, kNotExtended}.Build(
797 kWmResultZero)});
798
799 EXPECT_EQ(tester.key_calls.size(), 1);
800 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
801 kPhysicalControlLeft, kLogicalControlLeft, "",
802 kNotSynthesized);
803 tester.clear_key_calls();
804 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
805}
806
807TEST_F(KeyboardTest, CtrlRightUnhandled) {
808 KeyboardTester tester{GetContext()};
809 tester.Responding(false);
810
811 // US Keyboard layout
812
813 // Press CtrlRight
814 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
815 KeyStateChange{VK_RCONTROL, true, false},
816 WmKeyDownInfo{VK_CONTROL, kScanCodeControl, kExtended, kWasUp}.Build(
817 kWmResultZero)});
818
819 EXPECT_EQ(tester.key_calls.size(), 1);
821 kPhysicalControlRight, kLogicalControlRight, "",
822 kNotSynthesized);
823 tester.clear_key_calls();
824 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
825
826 // Release CtrlRight
827 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
828 KeyStateChange{VK_RCONTROL, false, true},
829 WmKeyUpInfo{VK_CONTROL, kScanCodeControl, kExtended}.Build(
830 kWmResultZero)});
831
832 EXPECT_EQ(tester.key_calls.size(), 1);
833 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
834 kPhysicalControlRight, kLogicalControlRight, "",
835 kNotSynthesized);
836 tester.clear_key_calls();
837 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
838}
839
840TEST_F(KeyboardTest, AltLeftUnhandled) {
841 KeyboardTester tester{GetContext()};
842 tester.Responding(false);
843
844 // US Keyboard layout
845
846 // Press AltLeft. AltLeft is a SysKeyDown event.
847 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
848 KeyStateChange{VK_LMENU, true, false},
849 WmSysKeyDownInfo{VK_MENU, kScanCodeAlt, kNotExtended, kWasUp}.Build(
850 kWmResultDefault)}); // Always pass to the default WndProc.
851
852 EXPECT_EQ(tester.key_calls.size(), 1);
854 kPhysicalAltLeft, kLogicalAltLeft, "", kNotSynthesized);
855 tester.clear_key_calls();
856 // Don't redispatch sys messages.
857 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
858
859 // Release AltLeft. AltLeft is a SysKeyUp event.
860 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
861 KeyStateChange{VK_LMENU, false, true},
862 WmSysKeyUpInfo{VK_MENU, kScanCodeAlt, kNotExtended}.Build(
863 kWmResultDefault)}); // Always pass to the default WndProc.
864
865 EXPECT_EQ(tester.key_calls.size(), 1);
866 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
867 kPhysicalAltLeft, kLogicalAltLeft, "", kNotSynthesized);
868 tester.clear_key_calls();
869 // Don't redispatch sys messages.
870 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
871}
872
873TEST_F(KeyboardTest, AltRightUnhandled) {
874 KeyboardTester tester{GetContext()};
875 tester.Responding(false);
876
877 // US Keyboard layout
878
879 // Press AltRight. AltRight is a SysKeyDown event.
880 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
881 KeyStateChange{VK_RMENU, true, false},
882 WmSysKeyDownInfo{VK_MENU, kScanCodeAlt, kExtended, kWasUp}.Build(
883 kWmResultDefault)}); // Always pass to the default WndProc.
884
885 EXPECT_EQ(tester.key_calls.size(), 1);
887 kPhysicalAltRight, kLogicalAltRight, "",
888 kNotSynthesized);
889 tester.clear_key_calls();
890 // Don't redispatch sys messages.
891 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
892
893 // Release AltRight. AltRight is a SysKeyUp event.
894 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
895 KeyStateChange{VK_RMENU, false, true},
896 WmSysKeyUpInfo{VK_MENU, kScanCodeAlt, kExtended}.Build(
897 kWmResultDefault)}); // Always pass to the default WndProc.
898
899 EXPECT_EQ(tester.key_calls.size(), 1);
900 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
901 kPhysicalAltRight, kLogicalAltRight, "",
902 kNotSynthesized);
903 tester.clear_key_calls();
904 // Don't redispatch sys messages.
905 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
906}
907
908TEST_F(KeyboardTest, MetaLeftUnhandled) {
909 KeyboardTester tester{GetContext()};
910 tester.Responding(false);
911
912 // US Keyboard layout
913
914 // Press MetaLeft
915 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
916 KeyStateChange{VK_LWIN, true, false},
917 WmKeyDownInfo{VK_LWIN, kScanCodeMetaLeft, kExtended, kWasUp}.Build(
918 kWmResultZero)});
919
920 EXPECT_EQ(tester.key_calls.size(), 1);
922 kPhysicalMetaLeft, kLogicalMetaLeft, "",
923 kNotSynthesized);
924 tester.clear_key_calls();
925 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
926
927 // Release MetaLeft
928 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
929 KeyStateChange{VK_LWIN, false, true},
930 WmKeyUpInfo{VK_LWIN, kScanCodeMetaLeft, kExtended}.Build(kWmResultZero)});
931
932 EXPECT_EQ(tester.key_calls.size(), 1);
933 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
934 kPhysicalMetaLeft, kLogicalMetaLeft, "",
935 kNotSynthesized);
936 tester.clear_key_calls();
937 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
938}
939
940TEST_F(KeyboardTest, MetaRightUnhandled) {
941 KeyboardTester tester{GetContext()};
942 tester.Responding(false);
943
944 // US Keyboard layout
945
946 // Press MetaRight
947 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
948 KeyStateChange{VK_RWIN, true, false},
949 WmKeyDownInfo{VK_RWIN, kScanCodeMetaRight, kExtended, kWasUp}.Build(
950 kWmResultZero)});
951
952 EXPECT_EQ(tester.key_calls.size(), 1);
954 kPhysicalMetaRight, kLogicalMetaRight, "",
955 kNotSynthesized);
956 tester.clear_key_calls();
957 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
958
959 // Release MetaRight
960 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
961 KeyStateChange{VK_RWIN, false, true},
962 WmKeyUpInfo{VK_RWIN, kScanCodeMetaRight, kExtended}.Build(
963 kWmResultZero)});
964
965 EXPECT_EQ(tester.key_calls.size(), 1);
966 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
967 kPhysicalMetaRight, kLogicalMetaRight, "",
968 kNotSynthesized);
969 tester.clear_key_calls();
970 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
971}
972
973// Press and hold A. This should generate a repeat event.
974TEST_F(KeyboardTest, RepeatA) {
975 KeyboardTester tester{GetContext()};
976 tester.Responding(true);
977
978 // Press A
979 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
981 kWmResultZero),
982 WmCharInfo{'a', kScanCodeKeyA, kNotExtended, kWasUp}.Build(
983 kWmResultZero)});
984
985 // Hold A
986 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
988 kWmResultZero),
989 WmCharInfo{'a', kScanCodeKeyA, kNotExtended, kWasDown}.Build(
990 kWmResultZero)});
991
992 EXPECT_EQ(tester.key_calls.size(), 2);
994 kPhysicalKeyA, kLogicalKeyA, "a", kNotSynthesized);
996 kPhysicalKeyA, kLogicalKeyA, "a", kNotSynthesized);
997 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
998}
999
1000// Press A, hot restart the engine, and hold A.
1001// This should reset the keyboard's state and generate
1002// two separate key down events.
1003TEST_F(KeyboardTest, RestartClearsKeyboardState) {
1004 KeyboardTester tester{GetContext()};
1005 tester.Responding(true);
1006
1007 // Press A
1008 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1010 kWmResultZero),
1011 WmCharInfo{'a', kScanCodeKeyA, kNotExtended, kWasUp}.Build(
1012 kWmResultZero)});
1013
1014 // Reset the keyboard's state.
1015 tester.ResetKeyboard();
1016
1017 // Hold A. Notice the message declares the key is already down, however, the
1018 // the keyboard does not send a repeat event as its state was reset.
1019 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1021 kWmResultZero),
1022 WmCharInfo{'a', kScanCodeKeyA, kNotExtended, kWasDown}.Build(
1023 kWmResultZero)});
1024
1025 EXPECT_EQ(tester.key_calls.size(), 2);
1027 kPhysicalKeyA, kLogicalKeyA, "a", kNotSynthesized);
1029 kPhysicalKeyA, kLogicalKeyA, "a", kNotSynthesized);
1030 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
1031}
1032
1033// Press Enter, lose focus before the up event arrives, and press Enter again
1034// once focus returns. The second down event should not be dropped.
1035TEST_F(KeyboardTest, FreshKeyDownAfterMissedUpIsDelivered) {
1036 KeyboardTester tester{GetContext()};
1037 tester.Responding(true);
1038
1039 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1040 WmKeyDownInfo{VK_RETURN, kScanCodeEnter, kNotExtended, kWasUp}.Build(
1041 kWmResultZero)});
1042
1043 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1044 WmKeyDownInfo{VK_RETURN, kScanCodeEnter, kNotExtended, kWasUp}.Build(
1045 kWmResultZero)});
1046
1047 ASSERT_EQ(tester.key_calls.size(), 3u);
1049 kPhysicalEnter, kLogicalEnter, "", kNotSynthesized);
1050 EXPECT_CALL_IS_EVENT(tester.key_calls[1], kFlutterKeyEventTypeUp,
1051 kPhysicalEnter, kLogicalEnter, "", kSynthesized);
1053 kPhysicalEnter, kLogicalEnter, "", kNotSynthesized);
1054 tester.clear_key_calls();
1055
1056 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1057 WmKeyUpInfo{VK_RETURN, kScanCodeEnter, kNotExtended}.Build(
1058 kWmResultZero)});
1059
1060 ASSERT_EQ(tester.key_calls.size(), 1u);
1061 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
1062 kPhysicalEnter, kLogicalEnter, "", kNotSynthesized);
1063 tester.clear_key_calls();
1064 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0u);
1065}
1066
1067// Press Shift-A. This is special because Win32 gives 'A' as character for the
1068// KeyA press.
1069TEST_F(KeyboardTest, ShiftLeftKeyA) {
1070 KeyboardTester tester{GetContext()};
1071 tester.Responding(false);
1072
1073 // US Keyboard layout
1074
1075 // Press ShiftLeft
1076 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1077 KeyStateChange{VK_LSHIFT, true, true},
1079 kWmResultZero)});
1080
1081 EXPECT_EQ(tester.key_calls.size(), 1);
1083 kPhysicalShiftLeft, kLogicalShiftLeft, "",
1084 kNotSynthesized);
1085 tester.clear_key_calls();
1086 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1087
1088 // Press A
1089 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1091 kWmResultZero),
1092 WmCharInfo{'A', kScanCodeKeyA, kNotExtended, kWasUp}.Build(
1093 kWmResultZero)});
1094
1095 EXPECT_EQ(tester.key_calls.size(), 2);
1097 kPhysicalKeyA, kLogicalKeyA, "A", kNotSynthesized);
1098 EXPECT_CALL_IS_TEXT(tester.key_calls[1], u"A");
1099 tester.clear_key_calls();
1100 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1101
1102 // Release ShiftLeft
1103 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1104 KeyStateChange{VK_LSHIFT, false, true},
1106 kWmResultZero)});
1107
1108 EXPECT_EQ(tester.key_calls.size(), 1);
1109 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
1110 kPhysicalShiftLeft, kLogicalShiftLeft, "",
1111 kNotSynthesized);
1112 tester.clear_key_calls();
1113 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1114
1115 // Release A
1116 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1118 kWmResultZero)});
1119
1120 EXPECT_EQ(tester.key_calls.size(), 1);
1121 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
1122 kPhysicalKeyA, kLogicalKeyA, "", kNotSynthesized);
1123 tester.clear_key_calls();
1124 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1125}
1126
1127// Press Ctrl-A. This is special because Win32 gives 0x01 as character for the
1128// KeyA press.
1129TEST_F(KeyboardTest, CtrlLeftKeyA) {
1130 KeyboardTester tester{GetContext()};
1131 tester.Responding(false);
1132
1133 // US Keyboard layout
1134
1135 // Press ControlLeft
1136 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1137 KeyStateChange{VK_LCONTROL, true, true},
1138 WmKeyDownInfo{VK_CONTROL, kScanCodeControl, kNotExtended, kWasUp}.Build(
1139 kWmResultZero)});
1140
1141 EXPECT_EQ(tester.key_calls.size(), 1);
1143 kPhysicalControlLeft, kLogicalControlLeft, "",
1144 kNotSynthesized);
1145 tester.clear_key_calls();
1146 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1147
1148 // Press A
1149 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1151 kWmResultZero),
1152 WmCharInfo{0x01, kScanCodeKeyA, kNotExtended, kWasUp}.Build(
1153 kWmResultZero)});
1154
1155 EXPECT_EQ(tester.key_calls.size(), 1);
1157 kPhysicalKeyA, kLogicalKeyA, "", kNotSynthesized);
1158 tester.clear_key_calls();
1159 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1160
1161 // Release A
1162 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1164 kWmResultZero)});
1165
1166 EXPECT_EQ(tester.key_calls.size(), 1);
1167 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
1168 kPhysicalKeyA, kLogicalKeyA, "", kNotSynthesized);
1169 tester.clear_key_calls();
1170 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1171
1172 // Release ControlLeft
1173 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1174 KeyStateChange{VK_LCONTROL, false, true},
1175 WmKeyUpInfo{VK_CONTROL, kScanCodeControl, kNotExtended}.Build(
1176 kWmResultZero)});
1177
1178 EXPECT_EQ(tester.key_calls.size(), 1);
1179 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
1180 kPhysicalControlLeft, kLogicalControlLeft, "",
1181 kNotSynthesized);
1182 tester.clear_key_calls();
1183 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1184}
1185
1186// Press Ctrl-1. This is special because it yields no WM_CHAR for the 1.
1187TEST_F(KeyboardTest, CtrlLeftDigit1) {
1188 KeyboardTester tester{GetContext()};
1189 tester.Responding(false);
1190
1191 // US Keyboard layout
1192
1193 // Press ControlLeft
1194 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1195 KeyStateChange{VK_LCONTROL, true, true},
1196 WmKeyDownInfo{VK_CONTROL, kScanCodeControl, kNotExtended, kWasUp}.Build(
1197 kWmResultZero)});
1198
1199 EXPECT_EQ(tester.key_calls.size(), 1);
1201 kPhysicalControlLeft, kLogicalControlLeft, "",
1202 kNotSynthesized);
1203 tester.clear_key_calls();
1204 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1205
1206 // Press 1
1207 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1208 WmKeyDownInfo{kVirtualDigit1, kScanCodeDigit1, kNotExtended, kWasUp}
1209 .Build(kWmResultZero)});
1210
1211 EXPECT_EQ(tester.key_calls.size(), 1);
1213 kPhysicalDigit1, kLogicalDigit1, "", kNotSynthesized);
1214 tester.clear_key_calls();
1215 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1216
1217 // Release 1
1218 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1219 WmKeyUpInfo{kVirtualDigit1, kScanCodeDigit1, kNotExtended}.Build(
1220 kWmResultZero)});
1221
1222 EXPECT_EQ(tester.key_calls.size(), 1);
1223 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
1224 kPhysicalDigit1, kLogicalDigit1, "", kNotSynthesized);
1225 tester.clear_key_calls();
1226 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1227
1228 // Release ControlLeft
1229 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1230 KeyStateChange{VK_LCONTROL, false, true},
1231 WmKeyUpInfo{VK_CONTROL, kScanCodeControl, kNotExtended}.Build(
1232 kWmResultZero)});
1233
1234 EXPECT_EQ(tester.key_calls.size(), 1);
1235 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
1236 kPhysicalControlLeft, kLogicalControlLeft, "",
1237 kNotSynthesized);
1238 tester.clear_key_calls();
1239 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1240}
1241
1242// Press 1 on a French keyboard. This is special because it yields WM_CHAR
1243// with char_code '&'.
1244TEST_F(KeyboardTest, Digit1OnFrenchLayout) {
1245 KeyboardTester tester{GetContext()};
1246 tester.Responding(false);
1247
1248 tester.SetLayout(LayoutFrench);
1249
1250 // Press 1
1251 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1252 WmKeyDownInfo{kVirtualDigit1, kScanCodeDigit1, kNotExtended, kWasUp}
1253 .Build(kWmResultZero),
1254 WmCharInfo{'&', kScanCodeDigit1, kNotExtended, kWasUp}.Build(
1255 kWmResultZero)});
1256
1257 EXPECT_EQ(tester.key_calls.size(), 2);
1259 kPhysicalDigit1, kLogicalDigit1, "&", kNotSynthesized);
1260 EXPECT_CALL_IS_TEXT(tester.key_calls[1], u"&");
1261 tester.clear_key_calls();
1262 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1263
1264 // Release 1
1265 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1266 WmKeyUpInfo{kVirtualDigit1, kScanCodeDigit1, kNotExtended}.Build(
1267 kWmResultZero)});
1268
1269 EXPECT_EQ(tester.key_calls.size(), 1);
1270 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
1271 kPhysicalDigit1, kLogicalDigit1, "", kNotSynthesized);
1272 tester.clear_key_calls();
1273 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1274}
1275
1276// This tests AltGr-Q on a German keyboard, which should print '@'.
1277TEST_F(KeyboardTest, AltGrModifiedKey) {
1278 KeyboardTester tester{GetContext()};
1279 tester.Responding(false);
1280
1281 // German Keyboard layout
1282
1283 // Press AltGr, which Win32 precedes with a ContrlLeft down.
1284 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1285 KeyStateChange{VK_LCONTROL, true, true},
1286 WmKeyDownInfo{VK_LCONTROL, kScanCodeControl, kNotExtended, kWasUp}.Build(
1287 kWmResultZero),
1288 KeyStateChange{VK_RMENU, true, true},
1289 WmKeyDownInfo{VK_MENU, kScanCodeAlt, kExtended, kWasUp}.Build(
1290 kWmResultZero)});
1291
1292 EXPECT_EQ(tester.key_calls.size(), 2);
1294 kPhysicalControlLeft, kLogicalControlLeft, "",
1295 kNotSynthesized);
1297 kPhysicalAltRight, kLogicalAltRight, "",
1298 kNotSynthesized);
1299 tester.clear_key_calls();
1300 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1301
1302 // Press Q
1303 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1304 WmKeyDownInfo{kVirtualKeyQ, kScanCodeKeyQ, kNotExtended, kWasUp}.Build(
1305 kWmResultZero),
1306 WmCharInfo{'@', kScanCodeKeyQ, kNotExtended, kWasUp}.Build(
1307 kWmResultZero)});
1308
1309 EXPECT_EQ(tester.key_calls.size(), 2);
1311 kPhysicalKeyQ, kLogicalKeyQ, "@", kNotSynthesized);
1312 EXPECT_CALL_IS_TEXT(tester.key_calls[1], u"@");
1313 tester.clear_key_calls();
1314 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1315
1316 // Release Q
1317 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1318 WmKeyUpInfo{kVirtualKeyQ, kScanCodeKeyQ, kNotExtended}.Build(
1319 kWmResultZero)});
1320
1321 EXPECT_EQ(tester.key_calls.size(), 1);
1322 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
1323 kPhysicalKeyQ, kLogicalKeyQ, "", kNotSynthesized);
1324 tester.clear_key_calls();
1325 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1326
1327 // Release AltGr. Win32 doesn't dispatch ControlLeft up. Instead Flutter will
1328 // forge one. The AltGr is a system key, therefore will be handled by Win32's
1329 // default WndProc.
1330 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1331 KeyStateChange{VK_LCONTROL, false, true},
1332 ExpectForgedMessage{
1333 WmKeyUpInfo{VK_CONTROL, kScanCodeControl, kNotExtended}.Build(
1334 kWmResultZero)},
1335 KeyStateChange{VK_RMENU, false, true},
1336 WmSysKeyUpInfo{VK_MENU, kScanCodeAlt, kExtended}.Build(
1337 kWmResultDefault)});
1338
1339 EXPECT_EQ(tester.key_calls.size(), 2);
1340 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
1341 kPhysicalControlLeft, kLogicalControlLeft, "",
1342 kNotSynthesized);
1343 EXPECT_CALL_IS_EVENT(tester.key_calls[1], kFlutterKeyEventTypeUp,
1344 kPhysicalAltRight, kLogicalAltRight, "",
1345 kNotSynthesized);
1346 tester.clear_key_calls();
1347 // The sys key up must not be redispatched. The forged ControlLeft up will.
1348 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1349}
1350
1351// Test the following two key sequences at the same time:
1352//
1353// 1. Tap AltGr, then tap AltGr.
1354// 2. Tap AltGr, hold CtrlLeft, tap AltGr, release CtrlLeft.
1355//
1356// The two sequences are indistinguishable until the very end when a CtrlLeft
1357// up event might or might not follow.
1358//
1359// Sequence 1: CtrlLeft down, AltRight down, AltRight up
1360// Sequence 2: CtrlLeft down, AltRight down, AltRight up, CtrlLeft up
1361//
1362// This is because pressing AltGr alone causes Win32 to send a fake "CtrlLeft
1363// down" event first (see |IsKeyDownAltRight| for detailed explanation).
1364TEST_F(KeyboardTest, AltGrTwice) {
1365 KeyboardTester tester{GetContext()};
1366 tester.Responding(false);
1367
1368 // 1. AltGr down.
1369
1370 // The key down event causes a ControlLeft down and a AltRight (extended
1371 // AltLeft) down.
1372 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1373 KeyStateChange{VK_LCONTROL, true, true},
1374 WmKeyDownInfo{VK_CONTROL, kScanCodeControl, kNotExtended, kWasUp}.Build(
1375 kWmResultZero),
1376 KeyStateChange{VK_RMENU, true, true},
1377 WmKeyDownInfo{VK_MENU, kScanCodeAlt, kExtended, kWasUp}.Build(
1378 kWmResultZero)});
1379
1380 EXPECT_EQ(tester.key_calls.size(), 2);
1382 kPhysicalControlLeft, kLogicalControlLeft, "",
1383 kNotSynthesized);
1385 kPhysicalAltRight, kLogicalAltRight, "",
1386 kNotSynthesized);
1387 tester.clear_key_calls();
1388 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1389
1390 // 2. AltGr up.
1391
1392 // The key up event only causes a AltRight (extended AltLeft) up.
1393 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1394 KeyStateChange{VK_LCONTROL, false, true},
1395 ExpectForgedMessage{
1396 WmKeyUpInfo{VK_CONTROL, kScanCodeControl, kNotExtended}.Build(
1397 kWmResultZero)},
1398 KeyStateChange{VK_RMENU, false, true},
1399 WmSysKeyUpInfo{VK_MENU, kScanCodeAlt, kExtended}.Build(
1400 kWmResultDefault)});
1401 EXPECT_EQ(tester.key_calls.size(), 2);
1402 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
1403 kPhysicalControlLeft, kLogicalControlLeft, "",
1404 kNotSynthesized);
1405 EXPECT_CALL_IS_EVENT(tester.key_calls[1], kFlutterKeyEventTypeUp,
1406 kPhysicalAltRight, kLogicalAltRight, "",
1407 kNotSynthesized);
1408 tester.clear_key_calls();
1409 // The sys key up must not be redispatched. The forged ControlLeft up will.
1410 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1411
1412 // 3. AltGr down (or: ControlLeft down then AltRight down.)
1413
1414 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1415 KeyStateChange{VK_LCONTROL, true, false},
1416 WmKeyDownInfo{VK_CONTROL, kScanCodeControl, kNotExtended, kWasUp}.Build(
1417 kWmResultZero),
1418 KeyStateChange{VK_RMENU, true, true},
1419 WmKeyDownInfo{VK_MENU, kScanCodeAlt, kExtended, kWasUp}.Build(
1420 kWmResultZero)});
1421
1422 EXPECT_EQ(tester.key_calls.size(), 2);
1424 kPhysicalControlLeft, kLogicalControlLeft, "",
1425 kNotSynthesized);
1427 kPhysicalAltRight, kLogicalAltRight, "",
1428 kNotSynthesized);
1429 tester.clear_key_calls();
1430 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1431
1432 // 4. AltGr up.
1433
1434 // The key up event only causes a AltRight (extended AltLeft) up.
1435 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1436 KeyStateChange{VK_LCONTROL, false, false},
1437 ExpectForgedMessage{
1438 WmKeyUpInfo{VK_CONTROL, kScanCodeControl, kNotExtended}.Build(
1439 kWmResultZero)},
1440 KeyStateChange{VK_RMENU, false, false},
1441 WmSysKeyUpInfo{VK_MENU, kScanCodeAlt, kExtended}.Build(
1442 kWmResultDefault)});
1443 EXPECT_EQ(tester.key_calls.size(), 2);
1444 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
1445 kPhysicalControlLeft, kLogicalControlLeft, "",
1446 kNotSynthesized);
1447 EXPECT_CALL_IS_EVENT(tester.key_calls[1], kFlutterKeyEventTypeUp,
1448 kPhysicalAltRight, kLogicalAltRight, "",
1449 kNotSynthesized);
1450 tester.clear_key_calls();
1451 // The sys key up must not be redispatched. The forged ControlLeft up will.
1452 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1453
1454 // 5. For key sequence 2: a real ControlLeft up.
1455 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1456 WmKeyUpInfo{VK_CONTROL, kScanCodeControl, kNotExtended}.Build(
1457 kWmResultZero)});
1458 EXPECT_EQ(tester.key_calls.size(), 1);
1459 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeDown, 0, 0, "",
1460 kNotSynthesized);
1461 tester.clear_key_calls();
1462 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
1463}
1464
1465// This tests dead key ^ then E on a French keyboard, which should be combined
1466// into ê.
1467TEST_F(KeyboardTest, DeadKeyThatCombines) {
1468 KeyboardTester tester{GetContext()};
1469 tester.Responding(false);
1470
1471 tester.SetLayout(LayoutFrench);
1472
1473 // Press ^¨ (US: Left bracket)
1474 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1475 WmKeyDownInfo{0xDD, kScanCodeBracketLeft, kNotExtended, kWasUp}.Build(
1476 kWmResultZero),
1477 WmDeadCharInfo{'^', kScanCodeBracketLeft, kNotExtended, kWasUp}.Build(
1478 kWmResultZero)});
1479
1480 EXPECT_EQ(tester.key_calls.size(), 1);
1482 kPhysicalBracketLeft, kLogicalBracketRight, "^",
1483 kNotSynthesized);
1484 tester.clear_key_calls();
1485 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1486
1487 // Release ^¨
1488 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1489 WmKeyUpInfo{0xDD, kScanCodeBracketLeft, kNotExtended}.Build(
1490 kWmResultZero)});
1491
1492 EXPECT_EQ(tester.key_calls.size(), 1);
1493 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
1494 kPhysicalBracketLeft, kLogicalBracketRight, "",
1495 kNotSynthesized);
1496 tester.clear_key_calls();
1497 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1498
1499 // Press E
1500 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1501 WmKeyDownInfo{kVirtualKeyE, kScanCodeKeyE, kNotExtended, kWasUp}.Build(
1502 kWmResultZero),
1503 WmCharInfo{0xEA, kScanCodeKeyE, kNotExtended, kWasUp}.Build(
1504 kWmResultZero)});
1505
1506 EXPECT_EQ(tester.key_calls.size(), 2);
1508 kPhysicalKeyE, kLogicalKeyE, "ê", kNotSynthesized);
1509 EXPECT_CALL_IS_TEXT(tester.key_calls[1], u"ê");
1510 tester.clear_key_calls();
1511 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1512
1513 // Release E
1514 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1515 WmKeyUpInfo{kVirtualKeyE, kScanCodeKeyE, kNotExtended}.Build(
1516 kWmResultZero)});
1517
1518 EXPECT_EQ(tester.key_calls.size(), 1);
1519 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
1520 kPhysicalKeyE, kLogicalKeyE, "", kNotSynthesized);
1521 tester.clear_key_calls();
1522 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1523}
1524
1525// This tests dead key ^ then E on a US INTL keyboard, which should be combined
1526// into ê.
1527//
1528// It is different from French AZERTY because the character that the ^ key is
1529// mapped to does not contain the dead key character somehow.
1530TEST_F(KeyboardTest, DeadKeyWithoutDeadMaskThatCombines) {
1531 KeyboardTester tester{GetContext()};
1532 tester.Responding(false);
1533
1534 // Press ShiftLeft
1535 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1536 KeyStateChange{VK_LSHIFT, true, true},
1538 kWmResultZero)});
1539
1540 EXPECT_EQ(tester.key_calls.size(), 1);
1542 kPhysicalShiftLeft, kLogicalShiftLeft, "",
1543 kNotSynthesized);
1544 tester.clear_key_calls();
1545 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1546
1547 // Press 6^
1548 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1549 WmKeyDownInfo{'6', kScanCodeDigit6, kNotExtended, kWasUp}.Build(
1550 kWmResultZero),
1551 WmDeadCharInfo{'^', kScanCodeDigit6, kNotExtended, kWasUp}.Build(
1552 kWmResultZero)});
1553
1554 EXPECT_EQ(tester.key_calls.size(), 1);
1556 kPhysicalDigit6, kLogicalDigit6, "6", kNotSynthesized);
1557 tester.clear_key_calls();
1558 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1559
1560 // Release 6^
1561 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1562 WmKeyUpInfo{'6', kScanCodeDigit6, kNotExtended}.Build(kWmResultZero)});
1563
1564 EXPECT_EQ(tester.key_calls.size(), 1);
1565 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
1566 kPhysicalDigit6, kLogicalDigit6, "", kNotSynthesized);
1567 tester.clear_key_calls();
1568 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1569
1570 // Release ShiftLeft
1571 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1572 KeyStateChange{VK_LSHIFT, false, true},
1574 kWmResultZero)});
1575
1576 EXPECT_EQ(tester.key_calls.size(), 1);
1577 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
1578 kPhysicalShiftLeft, kLogicalShiftLeft, "",
1579 kNotSynthesized);
1580 tester.clear_key_calls();
1581 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1582
1583 // Press E
1584 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1585 WmKeyDownInfo{kVirtualKeyE, kScanCodeKeyE, kNotExtended, kWasUp}.Build(
1586 kWmResultZero),
1587 WmCharInfo{0xEA, kScanCodeKeyE, kNotExtended, kWasUp}.Build(
1588 kWmResultZero)});
1589
1590 EXPECT_EQ(tester.key_calls.size(), 2);
1592 kPhysicalKeyE, kLogicalKeyE, "ê", kNotSynthesized);
1593 EXPECT_CALL_IS_TEXT(tester.key_calls[1], u"ê");
1594 tester.clear_key_calls();
1595 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1596
1597 // Release E
1598 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1599 WmKeyUpInfo{kVirtualKeyE, kScanCodeKeyE, kNotExtended}.Build(
1600 kWmResultZero)});
1601
1602 EXPECT_EQ(tester.key_calls.size(), 1);
1603 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
1604 kPhysicalKeyE, kLogicalKeyE, "", kNotSynthesized);
1605 tester.clear_key_calls();
1606 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1607}
1608
1609// This tests dead key ^ then & (US: 1) on a French keyboard, which do not
1610// combine and should output "^&".
1611TEST_F(KeyboardTest, DeadKeyThatDoesNotCombine) {
1612 KeyboardTester tester{GetContext()};
1613 tester.Responding(false);
1614
1615 tester.SetLayout(LayoutFrench);
1616
1617 // Press ^¨ (US: Left bracket)
1618 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1619 WmKeyDownInfo{0xDD, kScanCodeBracketLeft, kNotExtended, kWasUp}.Build(
1620 kWmResultZero),
1621 WmDeadCharInfo{'^', kScanCodeBracketLeft, kNotExtended, kWasUp}.Build(
1622 kWmResultZero)});
1623
1624 EXPECT_EQ(tester.key_calls.size(), 1);
1626 kPhysicalBracketLeft, kLogicalBracketRight, "^",
1627 kNotSynthesized);
1628 tester.clear_key_calls();
1629 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1630
1631 // Release ^¨
1632 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1633 WmKeyUpInfo{0xDD, kScanCodeBracketLeft, kNotExtended}.Build(
1634 kWmResultZero)});
1635
1636 EXPECT_EQ(tester.key_calls.size(), 1);
1637 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
1638 kPhysicalBracketLeft, kLogicalBracketRight, "",
1639 kNotSynthesized);
1640 tester.clear_key_calls();
1641 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1642
1643 // Press 1
1644 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1645 WmKeyDownInfo{kVirtualDigit1, kScanCodeDigit1, kNotExtended, kWasUp}
1646 .Build(kWmResultZero),
1647 WmCharInfo{'^', kScanCodeDigit1, kNotExtended, kWasUp}.Build(
1648 kWmResultZero),
1649 WmCharInfo{'&', kScanCodeDigit1, kNotExtended, kWasUp}.Build(
1650 kWmResultZero)});
1651
1652 EXPECT_EQ(tester.key_calls.size(), 3);
1654 kPhysicalDigit1, kLogicalDigit1, "^", kNotSynthesized);
1655 EXPECT_CALL_IS_TEXT(tester.key_calls[1], u"^");
1656 EXPECT_CALL_IS_TEXT(tester.key_calls[2], u"&");
1657 tester.clear_key_calls();
1658 // TODO(dkwingsmt): This count should probably be 3. Currently the '^'
1659 // message is redispatched due to being part of the KeyDown session, which is
1660 // not handled by the framework, while the '&' message is not redispatched
1661 // for being a standalone message. We should resolve this inconsistency.
1662 // https://github.com/flutter/flutter/issues/98306
1663 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1664
1665 // Release 1
1666 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1667 WmKeyUpInfo{kVirtualDigit1, kScanCodeDigit1, kNotExtended}.Build(
1668 kWmResultZero)});
1669
1670 EXPECT_EQ(tester.key_calls.size(), 1);
1671 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
1672 kPhysicalDigit1, kLogicalDigit1, "", kNotSynthesized);
1673 tester.clear_key_calls();
1674 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1675}
1676
1677// This tests dead key `, then dead key `, then e.
1678//
1679// It should output ``e, instead of `è.
1680TEST_F(KeyboardTest, DeadKeyTwiceThenLetter) {
1681 KeyboardTester tester{GetContext()};
1682 tester.Responding(false);
1683
1684 // US INTL layout.
1685
1686 // Press `
1687 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1688 WmKeyDownInfo{0xC0, kScanCodeBackquote, kNotExtended, kWasUp}.Build(
1689 kWmResultZero),
1690 WmDeadCharInfo{'`', kScanCodeBackquote, kNotExtended, kWasUp}.Build(
1691 kWmResultZero)});
1692
1693 EXPECT_EQ(tester.key_calls.size(), 1);
1695 kPhysicalBackquote, kLogicalBackquote, "`",
1696 kNotSynthesized);
1697 tester.clear_key_calls();
1698 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1699
1700 // Release `
1701 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1702 WmKeyUpInfo{0xC0, kScanCodeBackquote, kNotExtended}.Build(
1703 kWmResultZero)});
1704
1705 EXPECT_EQ(tester.key_calls.size(), 1);
1706 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
1707 kPhysicalBackquote, kLogicalBackquote, "",
1708 kNotSynthesized);
1709 tester.clear_key_calls();
1710 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1711
1712 // Press ` again.
1713 // The response should be slow.
1714 std::vector<MockKeyResponseController::ResponseCallback> recorded_callbacks;
1715 tester.LateResponding(
1716 [&recorded_callbacks](
1717 const FlutterKeyEvent* event,
1718 MockKeyResponseController::ResponseCallback callback) {
1719 recorded_callbacks.push_back(callback);
1720 });
1721
1722 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1723 WmKeyDownInfo{0xC0, kScanCodeBackquote, kNotExtended, kWasUp}.Build(
1724 kWmResultZero),
1725 WmCharInfo{'`', kScanCodeBackquote, kNotExtended, kWasUp, kBeingReleased,
1726 kNoContext, 1, /*bit25*/ true}
1727 .Build(kWmResultZero),
1728 WmCharInfo{'`', kScanCodeBackquote, kNotExtended, kWasUp}.Build(
1729 kWmResultZero)});
1730
1731 EXPECT_EQ(recorded_callbacks.size(), 1);
1732 EXPECT_EQ(tester.key_calls.size(), 1);
1734 kPhysicalBackquote, kLogicalBackquote, "`",
1735 kNotSynthesized);
1736 tester.clear_key_calls();
1737 // Key down event responded with false.
1738 recorded_callbacks.front()(false);
1739 EXPECT_EQ(tester.key_calls.size(), 2);
1740 EXPECT_CALL_IS_TEXT(tester.key_calls[0], u"`");
1741 EXPECT_CALL_IS_TEXT(tester.key_calls[1], u"`");
1742 tester.clear_key_calls();
1743 // TODO(dkwingsmt): This count should probably be 3. See the comment above
1744 // that is marked with the same issue.
1745 // https://github.com/flutter/flutter/issues/98306
1746 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1747
1748 tester.Responding(false);
1749
1750 // Release `
1751 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1752 WmKeyUpInfo{0xC0, kScanCodeBackquote, kNotExtended}.Build(
1753 kWmResultZero)});
1754
1755 EXPECT_EQ(tester.key_calls.size(), 1);
1756 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
1757 kPhysicalBackquote, kLogicalBackquote, "",
1758 kNotSynthesized);
1759 tester.clear_key_calls();
1760 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1761}
1762
1763// This tests when the resulting character needs to be combined with surrogates.
1764TEST_F(KeyboardTest, MultibyteCharacter) {
1765 KeyboardTester tester{GetContext()};
1766 tester.Responding(false);
1767
1768 // Gothic Keyboard layout. (We need a layout that yields non-BMP characters
1769 // without IME, which is actually very rare.)
1770
1771 // Press key W of a US keyboard, which should yield character '𐍅'.
1772 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1773 WmKeyDownInfo{kVirtualKeyW, kScanCodeKeyW, kNotExtended, kWasUp}.Build(
1774 kWmResultZero),
1775 WmCharInfo{0xd800, kScanCodeKeyW, kNotExtended, kWasUp}.Build(
1776 kWmResultZero),
1777 WmCharInfo{0xdf45, kScanCodeKeyW, kNotExtended, kWasUp}.Build(
1778 kWmResultZero)});
1779
1780 const char* st = tester.key_calls[0].key_event.character;
1781
1782 EXPECT_EQ(tester.key_calls.size(), 2);
1784 kPhysicalKeyW, kLogicalKeyW, "𐍅", kNotSynthesized);
1785 EXPECT_CALL_IS_TEXT(tester.key_calls[1], u"𐍅");
1786 tester.clear_key_calls();
1787 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 3);
1788
1789 // Release W
1790 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1791 WmKeyUpInfo{kVirtualKeyW, kScanCodeKeyW, kNotExtended}.Build(
1792 kWmResultZero)});
1793
1794 EXPECT_EQ(tester.key_calls.size(), 1);
1795 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
1796 kPhysicalKeyW, kLogicalKeyW, "", kNotSynthesized);
1797 tester.clear_key_calls();
1798 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1799}
1800
1801TEST_F(KeyboardTest, SynthesizeModifiers) {
1802 KeyboardTester tester{GetContext()};
1803 tester.Responding(false);
1804
1805 // Two dummy events used to trigger synthesization.
1806 Win32Message event1 =
1807 WmKeyDownInfo{VK_BACK, kScanCodeBackspace, kNotExtended, kWasUp}.Build(
1808 kWmResultZero);
1809 Win32Message event2 =
1810 WmKeyUpInfo{VK_BACK, kScanCodeBackspace, kNotExtended}.Build(
1811 kWmResultZero);
1812
1813 // ShiftLeft
1814 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1815 KeyStateChange{VK_LSHIFT, true, true}, event1});
1816 EXPECT_EQ(tester.key_calls.size(), 2);
1818 kPhysicalShiftLeft, kLogicalShiftLeft, "", kSynthesized);
1819 tester.clear_key_calls();
1820 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1821
1822 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1823 KeyStateChange{VK_LSHIFT, false, true}, event2});
1824 EXPECT_EQ(tester.key_calls.size(), 2);
1825 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
1826 kPhysicalShiftLeft, kLogicalShiftLeft, "", kSynthesized);
1827 tester.clear_key_calls();
1828 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1829
1830 // ShiftRight
1831 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1832 KeyStateChange{VK_RSHIFT, true, true}, event1});
1833 EXPECT_EQ(tester.key_calls.size(), 2);
1835 kPhysicalShiftRight, kLogicalShiftRight, "",
1836 kSynthesized);
1837 tester.clear_key_calls();
1838 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1839
1840 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1841 KeyStateChange{VK_RSHIFT, false, true}, event2});
1842 EXPECT_EQ(tester.key_calls.size(), 2);
1843 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
1844 kPhysicalShiftRight, kLogicalShiftRight, "",
1845 kSynthesized);
1846 tester.clear_key_calls();
1847 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1848
1849 // ControlLeft
1850 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1851 KeyStateChange{VK_LCONTROL, true, true}, event1});
1852 EXPECT_EQ(tester.key_calls.size(), 2);
1854 kPhysicalControlLeft, kLogicalControlLeft, "",
1855 kSynthesized);
1856 tester.clear_key_calls();
1857 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1858
1859 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1860 KeyStateChange{VK_LCONTROL, false, true}, event2});
1861 EXPECT_EQ(tester.key_calls.size(), 2);
1862 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
1863 kPhysicalControlLeft, kLogicalControlLeft, "",
1864 kSynthesized);
1865 tester.clear_key_calls();
1866 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1867
1868 // ControlRight
1869 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1870 KeyStateChange{VK_RCONTROL, true, true}, event1});
1871 EXPECT_EQ(tester.key_calls.size(), 2);
1873 kPhysicalControlRight, kLogicalControlRight, "",
1874 kSynthesized);
1875 tester.clear_key_calls();
1876 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1877
1878 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1879 KeyStateChange{VK_RCONTROL, false, true}, event2});
1880 EXPECT_EQ(tester.key_calls.size(), 2);
1881 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
1882 kPhysicalControlRight, kLogicalControlRight, "",
1883 kSynthesized);
1884 tester.clear_key_calls();
1885 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1886
1887 // AltLeft
1888 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1889 KeyStateChange{VK_LMENU, true, true}, event1});
1890 EXPECT_EQ(tester.key_calls.size(), 2);
1892 kPhysicalAltLeft, kLogicalAltLeft, "", kSynthesized);
1893 tester.clear_key_calls();
1894 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1895
1896 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1897 KeyStateChange{VK_LMENU, false, true}, event2});
1898 EXPECT_EQ(tester.key_calls.size(), 2);
1899 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
1900 kPhysicalAltLeft, kLogicalAltLeft, "", kSynthesized);
1901 tester.clear_key_calls();
1902 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1903
1904 // AltRight
1905 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1906 KeyStateChange{VK_RMENU, true, true}, event1});
1907 EXPECT_EQ(tester.key_calls.size(), 2);
1909 kPhysicalAltRight, kLogicalAltRight, "", kSynthesized);
1910 tester.clear_key_calls();
1911 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1912
1913 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1914 KeyStateChange{VK_RMENU, false, true}, event2});
1915 EXPECT_EQ(tester.key_calls.size(), 2);
1916 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
1917 kPhysicalAltRight, kLogicalAltRight, "", kSynthesized);
1918 tester.clear_key_calls();
1919 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1920
1921 // MetaLeft
1922 tester.InjectKeyboardChanges(
1923 std::vector<KeyboardChange>{KeyStateChange{VK_LWIN, true, true}, event1});
1924 EXPECT_EQ(tester.key_calls.size(), 2);
1926 kPhysicalMetaLeft, kLogicalMetaLeft, "", kSynthesized);
1927 tester.clear_key_calls();
1928 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1929
1930 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1931 KeyStateChange{VK_LWIN, false, true}, event2});
1932 EXPECT_EQ(tester.key_calls.size(), 2);
1933 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
1934 kPhysicalMetaLeft, kLogicalMetaLeft, "", kSynthesized);
1935 tester.clear_key_calls();
1936 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1937
1938 // MetaRight
1939 tester.InjectKeyboardChanges(
1940 std::vector<KeyboardChange>{KeyStateChange{VK_RWIN, true, true}, event1});
1941 EXPECT_EQ(tester.key_calls.size(), 2);
1943 kPhysicalMetaRight, kLogicalMetaRight, "", kSynthesized);
1944 tester.clear_key_calls();
1945 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1946
1947 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1948 KeyStateChange{VK_RWIN, false, true}, event2});
1949 EXPECT_EQ(tester.key_calls.size(), 2);
1950 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
1951 kPhysicalMetaRight, kLogicalMetaRight, "", kSynthesized);
1952 tester.clear_key_calls();
1953 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1954
1955 // CapsLock, phase 0 -> 2 -> 0.
1956 // (For phases, see |SynchronizeCriticalToggledStates|.)
1957 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1958 KeyStateChange{VK_CAPITAL, false, true}, event1});
1959 EXPECT_EQ(tester.key_calls.size(), 3);
1961 kPhysicalCapsLock, kLogicalCapsLock, "", kSynthesized);
1962 EXPECT_CALL_IS_EVENT(tester.key_calls[1], kFlutterKeyEventTypeUp,
1963 kPhysicalCapsLock, kLogicalCapsLock, "", kSynthesized);
1964 tester.clear_key_calls();
1965 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1966
1967 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1968 KeyStateChange{VK_CAPITAL, false, false}, event2});
1969 EXPECT_EQ(tester.key_calls.size(), 3);
1971 kPhysicalCapsLock, kLogicalCapsLock, "", kSynthesized);
1972 EXPECT_CALL_IS_EVENT(tester.key_calls[1], kFlutterKeyEventTypeUp,
1973 kPhysicalCapsLock, kLogicalCapsLock, "", kSynthesized);
1974 tester.clear_key_calls();
1975 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1976
1977 // ScrollLock, phase 0 -> 1 -> 3
1978 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1979 KeyStateChange{VK_SCROLL, true, true}, event1});
1980 EXPECT_EQ(tester.key_calls.size(), 2);
1982 kPhysicalScrollLock, kLogicalScrollLock, "",
1983 kSynthesized);
1984 tester.clear_key_calls();
1985 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1986
1987 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1988 KeyStateChange{VK_SCROLL, true, false}, event2});
1989 EXPECT_EQ(tester.key_calls.size(), 3);
1990 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
1991 kPhysicalScrollLock, kLogicalScrollLock, "",
1992 kSynthesized);
1994 kPhysicalScrollLock, kLogicalScrollLock, "",
1995 kSynthesized);
1996 tester.clear_key_calls();
1997 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1998
1999 // NumLock, phase 0 -> 3 -> 2
2000 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2001 KeyStateChange{VK_NUMLOCK, true, false}, event1});
2002 // TODO(dkwingsmt): Synthesizing from phase 0 to 3 should yield a full key
2003 // tap and a key down. Fix the algorithm so that the following result becomes
2004 // 4 keycalls with an extra pair of key down and up.
2005 // https://github.com/flutter/flutter/issues/98533
2006 EXPECT_EQ(tester.key_calls.size(), 2);
2008 kPhysicalNumLock, kLogicalNumLock, "", kSynthesized);
2009 tester.clear_key_calls();
2010 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
2011
2012 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2013 KeyStateChange{VK_NUMLOCK, false, true}, event2});
2014 EXPECT_EQ(tester.key_calls.size(), 4);
2015 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
2016 kPhysicalNumLock, kLogicalNumLock, "", kSynthesized);
2018 kPhysicalNumLock, kLogicalNumLock, "", kSynthesized);
2019 EXPECT_CALL_IS_EVENT(tester.key_calls[2], kFlutterKeyEventTypeUp,
2020 kPhysicalNumLock, kLogicalNumLock, "", kSynthesized);
2021 tester.clear_key_calls();
2022 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
2023}
2024
2025// Pressing extended keys during IME events should work properly by not sending
2026// any events.
2027//
2028// Regression test for https://github.com/flutter/flutter/issues/95888 .
2029TEST_F(KeyboardTest, ImeExtendedEventsAreIgnored) {
2030 KeyboardTester tester{GetContext()};
2031 tester.Responding(false);
2032
2033 // US Keyboard layout.
2034
2035 // There should be preceding key events to make the keyboard into IME mode.
2036 // Omit them in this test since they are not relavent.
2037
2038 // Press CtrlRight in IME mode.
2039 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2040 KeyStateChange{VK_RCONTROL, true, false},
2041 WmKeyDownInfo{VK_PROCESSKEY, kScanCodeControl, kExtended, kWasUp}.Build(
2042 kWmResultZero)});
2043
2044 EXPECT_EQ(tester.key_calls.size(), 1);
2045 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeDown, 0, 0, "",
2046 kNotSynthesized);
2047 tester.clear_key_calls();
2048 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
2049}
2050
2051// Ensures that synthesization works correctly when a Shift key is pressed and
2052// (only) its up event is labeled as an IME event (VK_PROCESSKEY).
2053//
2054// Regression test for https://github.com/flutter/flutter/issues/104169. These
2055// are real messages recorded when pressing Shift-2 using Microsoft Pinyin IME
2056// on Win 10 Enterprise, which crashed the app before the fix.
2057TEST_F(KeyboardTest, UpOnlyImeEventsAreCorrectlyHandled) {
2058 KeyboardTester tester{GetContext()};
2059 tester.Responding(true);
2060
2061 // US Keyboard layout.
2062
2063 // Press CtrlRight in IME mode.
2064 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2065 KeyStateChange{VK_LSHIFT, true, false},
2067 kWmResultZero),
2068 WmKeyDownInfo{VK_PROCESSKEY, kScanCodeDigit2, kNotExtended, kWasUp}.Build(
2069 kWmResultZero),
2070 KeyStateChange{VK_LSHIFT, false, true},
2071 WmKeyUpInfo{VK_PROCESSKEY, kScanCodeShiftLeft, kNotExtended}.Build(
2072 kWmResultZero),
2073 WmKeyUpInfo{'2', kScanCodeDigit2, kNotExtended, kWasUp}.Build(
2074 kWmResultZero)});
2075
2076 EXPECT_EQ(tester.key_calls.size(), 4);
2078 kPhysicalShiftLeft, kLogicalShiftLeft, "",
2079 kNotSynthesized);
2080 EXPECT_CALL_IS_EVENT(tester.key_calls[1], kFlutterKeyEventTypeDown, 0, 0, "",
2081 kNotSynthesized);
2082 EXPECT_CALL_IS_EVENT(tester.key_calls[2], kFlutterKeyEventTypeUp,
2083 kPhysicalShiftLeft, kLogicalShiftLeft, "",
2084 kNotSynthesized);
2085 EXPECT_CALL_IS_EVENT(tester.key_calls[3], kFlutterKeyEventTypeDown, 0, 0, "",
2086 kNotSynthesized);
2087 tester.clear_key_calls();
2088}
2089
2090// Regression test for a crash in an earlier implementation.
2091//
2092// In real life, the framework responds slowly. The next real event might
2093// arrive earlier than the framework response, and if the 2nd event has an
2094// identical hash as the one waiting for response, an earlier implementation
2095// will crash upon the response.
2096TEST_F(KeyboardTest, SlowFrameworkResponse) {
2097 KeyboardTester tester{GetContext()};
2098
2099 std::vector<MockKeyResponseController::ResponseCallback> recorded_callbacks;
2100
2101 // Store callbacks to manually call them.
2102 tester.LateResponding(
2103 [&recorded_callbacks](
2104 const FlutterKeyEvent* event,
2105 MockKeyResponseController::ResponseCallback callback) {
2106 recorded_callbacks.push_back(callback);
2107 });
2108
2109 // Press A
2110 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2112 kWmResultZero),
2113 WmCharInfo{'a', kScanCodeKeyA, kNotExtended, kWasUp}.Build(
2114 kWmResultZero)});
2115
2116 // Hold A
2117 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2119 kWmResultZero),
2120 WmCharInfo{'a', kScanCodeKeyA, kNotExtended, kWasDown}.Build(
2121 kWmResultZero)});
2122
2123 EXPECT_EQ(tester.key_calls.size(), 1);
2125 kPhysicalKeyA, kLogicalKeyA, "a", kNotSynthesized);
2126 EXPECT_EQ(recorded_callbacks.size(), 1);
2127 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
2128
2129 // The first response.
2130 recorded_callbacks.front()(false);
2131
2132 EXPECT_EQ(tester.key_calls.size(), 3);
2133 EXPECT_EQ(recorded_callbacks.size(), 2);
2134 EXPECT_CALL_IS_TEXT(tester.key_calls[1], u"a");
2136 kPhysicalKeyA, kLogicalKeyA, "a", kNotSynthesized);
2137 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
2138
2139 // The second response.
2140 recorded_callbacks.back()(false);
2141
2142 EXPECT_EQ(tester.key_calls.size(), 4);
2143 EXPECT_CALL_IS_TEXT(tester.key_calls[3], u"a");
2144 tester.clear_key_calls();
2145 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
2146}
2147
2148// Regression test for https://github.com/flutter/flutter/issues/84210.
2149//
2150// When the framework response is slow during a sequence of identical messages,
2151// make sure the real messages are not mistaken as redispatched messages,
2152// in order to not mess up the order of events.
2153//
2154// In this test we use:
2155//
2156// KeyA down, KeyA up, (down event responded with false), KeyA down, KeyA up,
2157//
2158// The code must not take the 2nd real key down events as a redispatched event.
2159TEST_F(KeyboardTest, SlowFrameworkResponseForIdenticalEvents) {
2160 KeyboardTester tester{GetContext()};
2161 std::vector<MockKeyResponseController::ResponseCallback> recorded_callbacks;
2162
2163 // Store callbacks to manually call them.
2164 tester.LateResponding(
2165 [&recorded_callbacks](
2166 const FlutterKeyEvent* event,
2167 MockKeyResponseController::ResponseCallback callback) {
2168 recorded_callbacks.push_back(callback);
2169 });
2170
2171 // Press A
2172 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2174 kWmResultZero),
2175 WmCharInfo{'a', kScanCodeKeyA, kNotExtended, kWasUp}.Build(
2176 kWmResultZero)});
2177
2178 EXPECT_EQ(tester.key_calls.size(), 1);
2180 kPhysicalKeyA, kLogicalKeyA, "a", kNotSynthesized);
2181 tester.clear_key_calls();
2182 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
2183
2184 // Release A
2185 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2187 kWmResultZero)});
2188
2189 EXPECT_EQ(tester.key_calls.size(), 0);
2190 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
2191
2192 // The first down event responded with false.
2193 EXPECT_EQ(recorded_callbacks.size(), 1);
2194 recorded_callbacks.front()(false);
2195
2196 EXPECT_EQ(tester.key_calls.size(), 2);
2197 EXPECT_CALL_IS_TEXT(tester.key_calls[0], u"a");
2198 EXPECT_CALL_IS_EVENT(tester.key_calls[1], kFlutterKeyEventTypeUp,
2199 kPhysicalKeyA, kLogicalKeyA, "", kNotSynthesized);
2200 tester.clear_key_calls();
2201 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
2202
2203 // Press A again
2204 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2206 kWmResultZero),
2207 WmCharInfo{'a', kScanCodeKeyA, kNotExtended, kWasUp}.Build(
2208 kWmResultZero)});
2209
2210 // Nothing more was dispatched because the first up event hasn't been
2211 // responded yet.
2212 EXPECT_EQ(recorded_callbacks.size(), 2);
2213 EXPECT_EQ(tester.key_calls.size(), 0);
2214 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
2215
2216 // The first up event responded with false, which was redispatched, and caused
2217 // the down event to be dispatched.
2218 recorded_callbacks.back()(false);
2219 EXPECT_EQ(tester.key_calls.size(), 1);
2221 kPhysicalKeyA, kLogicalKeyA, "a", kNotSynthesized);
2222 tester.clear_key_calls();
2223 EXPECT_EQ(recorded_callbacks.size(), 3);
2224 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
2225
2226 // Release A again
2227 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2229 kWmResultZero)});
2230
2231 EXPECT_EQ(tester.key_calls.size(), 0);
2232 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
2233}
2234
2235TEST_F(KeyboardTest, TextInputSubmit) {
2236 KeyboardTester tester{GetContext()};
2237 tester.Responding(false);
2238
2239 // US Keyboard layout
2240
2241 tester.InjectPlatformMessage(
2242 "flutter/textinput", "TextInput.setClient",
2243 R"|([108, {"inputAction": "TextInputAction.none", "viewId": 0}])|");
2244
2245 // Press Enter
2246 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2247 WmKeyDownInfo{VK_RETURN, kScanCodeEnter, kNotExtended, kWasUp}.Build(
2248 kWmResultZero),
2249 WmCharInfo{'\n', kScanCodeEnter, kNotExtended, kWasUp}.Build(
2250 kWmResultZero)});
2251
2252 EXPECT_EQ(tester.key_calls.size(), 2);
2254 kPhysicalEnter, kLogicalEnter, "", kNotSynthesized);
2256 tester.key_calls[1],
2257 "{"
2258 R"|("method":"TextInputClient.performAction",)|"
2259 R"|("args":[108,"TextInputAction.none"])|"
2260 "}");
2261 tester.clear_key_calls();
2262 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
2263
2264 // Release Enter
2265 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2266 WmKeyUpInfo{VK_RETURN, kScanCodeEnter, kNotExtended}.Build(
2267 kWmResultZero)});
2268
2269 EXPECT_EQ(tester.key_calls.size(), 1);
2270 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
2271 kPhysicalEnter, kLogicalEnter, "", kNotSynthesized);
2272 tester.clear_key_calls();
2273 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
2274
2275 // Make sure OnText is not obstructed after pressing Enter.
2276 //
2277 // Regression test for https://github.com/flutter/flutter/issues/97706.
2278
2279 // Press A
2280 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2282 kWmResultZero),
2283 WmCharInfo{'a', kScanCodeKeyA, kNotExtended, kWasUp}.Build(
2284 kWmResultZero)});
2285
2286 EXPECT_EQ(tester.key_calls.size(), 2);
2288 kPhysicalKeyA, kLogicalKeyA, "a", kNotSynthesized);
2289 EXPECT_CALL_IS_TEXT(tester.key_calls[1], u"a");
2290 tester.clear_key_calls();
2291
2292 // Release A
2293 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2295 kWmResultZero)});
2296
2297 EXPECT_EQ(tester.key_calls.size(), 1);
2298 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
2299 kPhysicalKeyA, kLogicalKeyA, "", kNotSynthesized);
2300 tester.clear_key_calls();
2301}
2302
2303TEST_F(KeyboardTest, VietnameseTelexAddDiacriticWithFastResponse) {
2304 // In this test, the user presses the folloing keys:
2305 //
2306 // Key Current text
2307 // ===========================
2308 // A a
2309 // F à
2310 //
2311 // And the Backspace event is responded immediately.
2312
2313 KeyboardTester tester{GetContext()};
2314 tester.Responding(false);
2315
2316 // US Keyboard layout
2317
2318 // Press A
2319 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2321 kWmResultZero),
2322 WmCharInfo{'a', kScanCodeKeyA, kNotExtended, kWasUp}.Build(
2323 kWmResultZero)});
2324
2325 EXPECT_EQ(tester.key_calls.size(), 2);
2327 kPhysicalKeyA, kLogicalKeyA, "a", kNotSynthesized);
2328 EXPECT_CALL_IS_TEXT(tester.key_calls[1], u"a");
2329 tester.clear_key_calls();
2330 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
2331
2332 // Release A
2333 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2335 kWmResultZero)});
2336
2337 EXPECT_EQ(tester.key_calls.size(), 1);
2338 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
2339 kPhysicalKeyA, kLogicalKeyA, "", kNotSynthesized);
2340 tester.clear_key_calls();
2341 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
2342
2343 // Press F, which is translated to:
2344 //
2345 // Backspace down, char & up, then VK_PACKET('à').
2346 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2347 WmKeyDownInfo{VK_BACK, kScanCodeBackspace, kNotExtended, kWasUp}.Build(
2348 kWmResultZero),
2349 WmCharInfo{0x8, kScanCodeBackspace, kNotExtended, kWasUp}.Build(
2350 kWmResultZero),
2351 WmKeyUpInfo{VK_BACK, kScanCodeBackspace, kNotExtended}.Build(
2352 kWmResultZero),
2353 WmKeyDownInfo{VK_PACKET, 0, kNotExtended, kWasUp}.Build(kWmResultDefault),
2354 WmCharInfo{0xe0 /*'à'*/, 0, kNotExtended, kWasUp}.Build(kWmResultZero),
2355 WmKeyUpInfo{VK_PACKET, 0, kNotExtended}.Build(kWmResultDefault)});
2356
2357 EXPECT_EQ(tester.key_calls.size(), 3);
2359 kPhysicalBackspace, kLogicalBackspace, "",
2360 kNotSynthesized);
2361 EXPECT_CALL_IS_EVENT(tester.key_calls[1], kFlutterKeyEventTypeUp,
2362 kPhysicalBackspace, kLogicalBackspace, "",
2363 kNotSynthesized);
2364 EXPECT_CALL_IS_TEXT(tester.key_calls[2], u"à");
2365 tester.clear_key_calls();
2366 // TODO(dkwingsmt): This count should probably be 4. Currently the CHAR 0x8
2367 // message is redispatched due to being part of the KeyDown session, which is
2368 // not handled by the framework, while the 'à' message is not redispatched
2369 // for being a standalone message. We should resolve this inconsistency.
2370 // https://github.com/flutter/flutter/issues/98306
2371 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 3);
2372
2373 // Release F
2374 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2375 WmKeyUpInfo{kVirtualKeyF, kScanCodeKeyF, kNotExtended,
2376 /* overwrite_prev_state_0 */ true}
2377 .Build(kWmResultZero)});
2378
2379 EXPECT_EQ(tester.key_calls.size(), 1);
2380 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeDown, 0, 0, "",
2381 kNotSynthesized);
2382 tester.clear_key_calls();
2383 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
2384}
2385
2386void VietnameseTelexAddDiacriticWithSlowResponse(WindowsTestContext& context,
2387 bool backspace_response) {
2388 // In this test, the user presses the following keys:
2389 //
2390 // Key Current text
2391 // ===========================
2392 // A a
2393 // F à
2394 //
2395 // And the Backspace down event is responded slowly with `backspace_response`.
2396
2397 KeyboardTester tester{context};
2398 tester.Responding(false);
2399
2400 // US Keyboard layout
2401
2402 // Press A
2403 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2405 kWmResultZero),
2406 WmCharInfo{'a', kScanCodeKeyA, kNotExtended, kWasUp}.Build(
2407 kWmResultZero)});
2408
2409 EXPECT_EQ(tester.key_calls.size(), 2);
2411 kPhysicalKeyA, kLogicalKeyA, "a", kNotSynthesized);
2412 EXPECT_CALL_IS_TEXT(tester.key_calls[1], u"a");
2413 tester.clear_key_calls();
2414 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
2415
2416 // Release A
2417 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2419 kWmResultZero)});
2420
2421 EXPECT_EQ(tester.key_calls.size(), 1);
2422 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
2423 kPhysicalKeyA, kLogicalKeyA, "", kNotSynthesized);
2424 tester.clear_key_calls();
2425 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
2426
2427 std::vector<MockKeyResponseController::ResponseCallback> recorded_callbacks;
2428 tester.LateResponding(
2429 [&recorded_callbacks](
2430 const FlutterKeyEvent* event,
2431 MockKeyResponseController::ResponseCallback callback) {
2432 recorded_callbacks.push_back(callback);
2433 });
2434
2435 // Press F, which is translated to:
2436 //
2437 // Backspace down, char & up, VK_PACKET('à').
2438 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2439 WmKeyDownInfo{VK_BACK, kScanCodeBackspace, kNotExtended, kWasUp}.Build(
2440 kWmResultZero),
2441 WmCharInfo{0x8, kScanCodeBackspace, kNotExtended, kWasUp}.Build(
2442 kWmResultZero),
2443 WmKeyUpInfo{VK_BACK, kScanCodeBackspace, kNotExtended}.Build(
2444 kWmResultZero),
2445 WmKeyDownInfo{VK_PACKET, 0, kNotExtended, kWasUp}.Build(kWmResultDefault),
2446 WmCharInfo{0xe0 /*'à'*/, 0, kNotExtended, kWasUp}.Build(kWmResultZero),
2447 WmKeyUpInfo{VK_PACKET, 0, kNotExtended}.Build(kWmResultDefault)});
2448
2449 // The Backspace event has not responded yet, therefore the char message must
2450 // hold. This is because when the framework is handling the Backspace event,
2451 // it will send a setEditingState message that updates the text state that has
2452 // the last character deleted (denoted by `string1`). Processing the char
2453 // message before then will cause the final text to set to `string1`.
2454 EXPECT_EQ(tester.key_calls.size(), 1);
2456 kPhysicalBackspace, kLogicalBackspace, "",
2457 kNotSynthesized);
2458 tester.clear_key_calls();
2459 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
2460
2461 EXPECT_EQ(recorded_callbacks.size(), 1);
2462 recorded_callbacks[0](backspace_response);
2463
2464 EXPECT_EQ(tester.key_calls.size(), 1);
2465 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeUp,
2466 kPhysicalBackspace, kLogicalBackspace, "",
2467 kNotSynthesized);
2468 tester.clear_key_calls();
2469 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(),
2470 backspace_response ? 0 : 2);
2471
2472 recorded_callbacks[1](false);
2473 EXPECT_EQ(tester.key_calls.size(), 1);
2474 EXPECT_CALL_IS_TEXT(tester.key_calls[0], u"à");
2475 tester.clear_key_calls();
2476 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
2477
2478 tester.Responding(false);
2479
2480 // Release F
2481 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2482 WmKeyUpInfo{kVirtualKeyF, kScanCodeKeyF, kNotExtended,
2483 /* overwrite_prev_state_0 */ true}
2484 .Build(kWmResultZero)});
2485
2486 EXPECT_EQ(tester.key_calls.size(), 1);
2487 EXPECT_CALL_IS_EVENT(tester.key_calls[0], kFlutterKeyEventTypeDown, 0, 0, "",
2488 kNotSynthesized);
2489 tester.clear_key_calls();
2490 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
2491}
2492
2493TEST_F(KeyboardTest, VietnameseTelexAddDiacriticWithSlowFalseResponse) {
2495}
2496
2497TEST_F(KeyboardTest, VietnameseTelexAddDiacriticWithSlowTrueResponse) {
2499}
2500
2501// Ensure that the scancode-less key events issued by Narrator
2502// when toggling caps lock don't violate assert statements.
2503TEST_F(KeyboardTest, DoubleCapsLock) {
2504 KeyboardTester tester{GetContext()};
2505 tester.Responding(false);
2506
2507 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2508 WmKeyDownInfo{VK_CAPITAL, 0, kNotExtended}.Build(),
2509 WmKeyUpInfo{VK_CAPITAL, 0, kNotExtended}.Build()});
2510
2511 tester.clear_key_calls();
2512}
2513
2514} // namespace testing
2515} // namespace flutter
@ kFlutterKeyEventTypeDown
Definition embedder.h:1378
@ kFlutterKeyEventTypeUp
Definition embedder.h:1377
@ kFlutterKeyEventTypeRepeat
Definition embedder.h:1379
FlutterDesktopBinaryReply callback
#define EXPECT_CALL_IS_TEXT(_key_call, u16_string)
#define EXPECT_CALL_IS_TEXT_METHOD_CALL(_key_call, json_string)
#define EXPECT_CALL_IS_EVENT(_key_call, _type, _physical, _logical, _character, _synthesized)
struct flutter::testing::WmKeyDownInfo WmKeyDownInfo
struct flutter::testing::WmSysKeyUpInfo WmSysKeyUpInfo
struct flutter::testing::WmKeyUpInfo WmKeyUpInfo
struct flutter::testing::WmSysKeyDownInfo WmSysKeyDownInfo
void VietnameseTelexAddDiacriticWithSlowResponse(WindowsTestContext &context, bool backspace_response)
constexpr int kScanCodeShiftRight
constexpr int kScanCodeShiftLeft

◆ EXPECT_CALL_IS_TEXT

#define EXPECT_CALL_IS_TEXT (   _key_call,
  u16_string 
)
Value:
EXPECT_EQ(_key_call.type, KeyCall::kKeyCallOnText); \
EXPECT_EQ(_key_call.text, u16_string);

Definition at line 564 of file keyboard_unittests.cc.

◆ EXPECT_CALL_IS_TEXT_METHOD_CALL

#define EXPECT_CALL_IS_TEXT_METHOD_CALL (   _key_call,
  json_string 
)
Value:
EXPECT_EQ(_key_call.type, KeyCall::kKeyCallTextMethodCall); \
EXPECT_STREQ(_key_call.text_method_call.c_str(), json_string);

Definition at line 568 of file keyboard_unittests.cc.

Variable Documentation

◆ []

◆ expected_forged_message

Win32Message expected_forged_message

Definition at line 167 of file keyboard_unittests.cc.

◆ key

uint32_t key

Definition at line 125 of file keyboard_unittests.cc.

◆ key_calls

std::vector<KeyCall> key_calls

Definition at line 467 of file keyboard_unittests.cc.

◆ key_event

◆ key_state_change

KeyStateChange key_state_change

Definition at line 166 of file keyboard_unittests.cc.

◆ message

Win32Message message

Definition at line 139 of file keyboard_unittests.cc.

◆ pressed

bool pressed

Definition at line 126 of file keyboard_unittests.cc.

◆ state_changes_afterwards

std::list<KeyStateChange> state_changes_afterwards

Definition at line 310 of file keyboard_unittests.cc.

◆ text

std::u16string text

Definition at line 332 of file keyboard_unittests.cc.

Referenced by CommentsUtil::AddCEndTrimLine(), CommentsUtil::AddCTrimLine(), flutter::TextInputModel::AddText(), flutter::ParagraphBuilder::addText(), flutter::TextInputModel::AddText(), txt::ParagraphBuilderSkia::AddText(), CommentsUtil::AddTrimLine(), flutter::FlutterWindowsView::AnnounceAlert(), ui::AXPlatformNodeMac::AnnounceText(), BENCHMARK_DEFINE_F(), BENCHMARK_DEFINE_F(), BENCHMARK_F(), BENCHMARK_F(), BENCHMARK_F(), BENCHMARK_F(), BENCHMARK_F(), BENCHMARK_F(), BENCHMARK_F(), BENCHMARK_F(), clipboard_set_data(), clipboard_set_data(), clipboard_text_cb(), clipboard_text_has_strings_cb(), flutter::TextInputPlugin::ComposeBeginHook(), flutter::TextInputPlugin::ComposeChangeHook(), flutter::TextInputPlugin::ComposeEndHook(), ui::AXPlatformNodeTextRangeProviderTest::ComputeWordBoundariesOffsets(), decode_error_message(), decode_error_method_call(), decode_error_response(), decode_message(), decode_method_call(), decode_response_with_error(), decode_response_with_success(), flutter::DlSkCanvasDispatcher::drawText(), flutter::testing::ImageSizeTextBlobInspector::drawText(), flutter::testing::DisplayListStreamDispatcher::drawText(), flutter::DisplayListBuilder::DrawText(), flutter::DlSkCanvasAdapter::DrawText(), impeller::DlDispatcherBase::drawText(), impeller::FirstPassDispatcher::drawText(), flutter::testing::PainterTestBase< T >::drawText(), impeller::interop::testing::DrawTextFrame(), fl_accessible_text_field_add_selection(), fl_accessible_text_field_get_caret_offset(), fl_accessible_text_field_get_character_count(), fl_accessible_text_field_get_n_selections(), fl_accessible_text_field_get_selection(), fl_accessible_text_field_get_string_at_offset(), fl_accessible_text_field_get_text(), fl_accessible_text_field_get_text_at_offset(), fl_accessible_text_field_remove_selection(), fl_accessible_text_field_set_caret_offset(), fl_accessible_text_field_set_selection(), fl_json_message_codec_decode(), fl_json_message_codec_encode_message(), fl_platform_channel_respond_clipboard_get_data(), fl_standard_message_codec_real_write_value(), fl_string_codec_encode_message(), fl_test_codec_encode_error_envelope(), fl_test_codec_encode_method_call(), fl_test_codec_encode_success_envelope(), fl_text_input_channel_update_editing_state(), fl_text_input_handler_filter_keypress(), flutter::FlutterPlatformNodeDelegateMac::GetLiveRegionText(), flutter::testing::GetTestTextBlob(), flutter::testing::GetTestTextBlob(), ui::AXNodePosition::GetText(), gtk_im_context_set_surrounding(), flutter_runner::TextDelegate::HandleFlutterTextInputChannelPlatformMessage(), FlutterSpellCheckPlugin::handleMethodCall:result:, im_commit_cb(), im_preedit_changed_cb(), im_retrieve_surrounding_cb(), IsEmoji(), flutter::PerformanceOverlayLayer::MakeStatisticsText(), flutter::FlutterWindow::OnComposeChange(), flutter::FlutterWindowsView::OnComposeChange(), flutter::FlutterWindow::OnImeComposition(), flutter::FlutterWindowsView::OnText(), flutter::FlutterWindow::OnText(), std::operator<<(), paragraphBuilder_addText(), paragraphBuilder_build(), perform_set_text_action(), fml::RangeForCharacterAtIndex(), fml::RangeForCharactersInRange(), flutter::testing::RenderTextInCanvasSkia(), set_editing_state(), set_editing_state(), flutter::PlatformHandler::SetPlainText(), flutter::TextInputModel::SetText(), flutter::AlertPlatformNodeDelegate::SetText(), fuchsia_test_utils::PortableUITest::SimulateTextEntry(), flutter::testing::TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), flutter::testing::TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), impeller::testing::TEST_P(), impeller::testing::TEST_P(), flutter::testing::TEST_P(), flutter::testing::TEST_P(), impeller::interop::testing::TEST_P(), impeller::interop::testing::TEST_P(), impeller::interop::testing::TEST_P(), impeller::interop::testing::TEST_P(), text_to_message(), text_to_message(), flutter::TextInputPlugin::TextHook(), ui::AXPosition< AXPositionType, AXNodeType >::ToString(), flutter::TextInputModel::UpdateComposingText(), flutter::TextInputModel::UpdateComposingText(), and flutter::TextInputModel::UpdateComposingText().

◆ text_method_call

std::string text_method_call

Definition at line 333 of file keyboard_unittests.cc.

◆ toggled_on

bool toggled_on

Definition at line 127 of file keyboard_unittests.cc.

◆ []

enum { ... } type