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 554 of file keyboard_unittests.cc.

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