Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Namespaces | Macros | Functions
keyboard_unittests.cc File Reference
#include "flutter/fml/logging.h"
#include "flutter/shell/platform/common/json_message_codec.h"
#include "flutter/shell/platform/embedder/embedder.h"
#include "flutter/shell/platform/embedder/test_utils/key_codes.g.h"
#include "flutter/shell/platform/windows/flutter_windows_engine.h"
#include "flutter/shell/platform/windows/flutter_windows_view.h"
#include "flutter/shell/platform/windows/keyboard_key_channel_handler.h"
#include "flutter/shell/platform/windows/keyboard_key_embedder_handler.h"
#include "flutter/shell/platform/windows/keyboard_key_handler.h"
#include "flutter/shell/platform/windows/keyboard_manager.h"
#include "flutter/shell/platform/windows/testing/engine_modifier.h"
#include "flutter/shell/platform/windows/testing/flutter_windows_engine_builder.h"
#include "flutter/shell/platform/windows/testing/mock_window_binding_handler.h"
#include "flutter/shell/platform/windows/testing/test_keyboard.h"
#include "flutter/shell/platform/windows/testing/windows_test.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "rapidjson/stringbuffer.h"
#include "rapidjson/writer.h"
#include <functional>
#include <list>
#include <vector>

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, 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 {
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);
593 kPhysicalKeyA, kLogicalKeyA, "", kNotSynthesized);
594 tester.clear_key_calls();
595 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
596}
597
598TEST_F(KeyboardTest, LowerCaseAUnhandled) {
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);
625 kPhysicalKeyA, kLogicalKeyA, "", kNotSynthesized);
626 tester.clear_key_calls();
627 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
628}
629
630TEST_F(KeyboardTest, ArrowLeftHandled) {
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);
655 kPhysicalArrowLeft, kLogicalArrowLeft, "",
656 kNotSynthesized);
657 tester.clear_key_calls();
658 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
659}
660
661TEST_F(KeyboardTest, ArrowLeftUnhandled) {
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);
686 kPhysicalArrowLeft, kLogicalArrowLeft, "",
687 kNotSynthesized);
688 tester.clear_key_calls();
689 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
690}
691
692TEST_F(KeyboardTest, ShiftLeftUnhandled) {
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);
731 kPhysicalShiftLeft, kLogicalShiftLeft, "",
732 kNotSynthesized);
733 tester.clear_key_calls();
734 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
735}
736
737TEST_F(KeyboardTest, ShiftRightUnhandled) {
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);
764 kPhysicalShiftRight, kLogicalShiftRight, "",
765 kNotSynthesized);
766 tester.clear_key_calls();
767 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
768}
769
770TEST_F(KeyboardTest, CtrlLeftUnhandled) {
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);
797 kPhysicalControlLeft, kLogicalControlLeft, "",
798 kNotSynthesized);
799 tester.clear_key_calls();
800 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
801}
802
803TEST_F(KeyboardTest, CtrlRightUnhandled) {
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);
830 kPhysicalControlRight, kLogicalControlRight, "",
831 kNotSynthesized);
832 tester.clear_key_calls();
833 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
834}
835
836TEST_F(KeyboardTest, AltLeftUnhandled) {
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);
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) {
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);
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) {
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);
930 kPhysicalMetaLeft, kLogicalMetaLeft, "",
931 kNotSynthesized);
932 tester.clear_key_calls();
933 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
934}
935
936TEST_F(KeyboardTest, MetaRightUnhandled) {
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);
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) {
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) {
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 Shift-A. This is special because Win32 gives 'A' as character for the
1030// KeyA press.
1031TEST_F(KeyboardTest, ShiftLeftKeyA) {
1033 tester.Responding(false);
1034
1035 // US Keyboard layout
1036
1037 // Press ShiftLeft
1038 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1039 KeyStateChange{VK_LSHIFT, true, true},
1041 kWmResultZero)});
1042
1043 EXPECT_EQ(tester.key_calls.size(), 1);
1045 kPhysicalShiftLeft, kLogicalShiftLeft, "",
1046 kNotSynthesized);
1047 tester.clear_key_calls();
1048 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1049
1050 // Press A
1051 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1053 kWmResultZero),
1054 WmCharInfo{'A', kScanCodeKeyA, kNotExtended, kWasUp}.Build(
1055 kWmResultZero)});
1056
1057 EXPECT_EQ(tester.key_calls.size(), 2);
1059 kPhysicalKeyA, kLogicalKeyA, "A", kNotSynthesized);
1060 EXPECT_CALL_IS_TEXT(tester.key_calls[1], u"A");
1061 tester.clear_key_calls();
1062 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1063
1064 // Release ShiftLeft
1065 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1066 KeyStateChange{VK_LSHIFT, false, true},
1068 kWmResultZero)});
1069
1070 EXPECT_EQ(tester.key_calls.size(), 1);
1072 kPhysicalShiftLeft, kLogicalShiftLeft, "",
1073 kNotSynthesized);
1074 tester.clear_key_calls();
1075 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1076
1077 // Release A
1078 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1080 kWmResultZero)});
1081
1082 EXPECT_EQ(tester.key_calls.size(), 1);
1084 kPhysicalKeyA, kLogicalKeyA, "", kNotSynthesized);
1085 tester.clear_key_calls();
1086 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1087}
1088
1089// Press Ctrl-A. This is special because Win32 gives 0x01 as character for the
1090// KeyA press.
1091TEST_F(KeyboardTest, CtrlLeftKeyA) {
1093 tester.Responding(false);
1094
1095 // US Keyboard layout
1096
1097 // Press ControlLeft
1098 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1099 KeyStateChange{VK_LCONTROL, true, true},
1100 WmKeyDownInfo{VK_CONTROL, kScanCodeControl, kNotExtended, kWasUp}.Build(
1101 kWmResultZero)});
1102
1103 EXPECT_EQ(tester.key_calls.size(), 1);
1105 kPhysicalControlLeft, kLogicalControlLeft, "",
1106 kNotSynthesized);
1107 tester.clear_key_calls();
1108 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1109
1110 // Press A
1111 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1113 kWmResultZero),
1114 WmCharInfo{0x01, kScanCodeKeyA, kNotExtended, kWasUp}.Build(
1115 kWmResultZero)});
1116
1117 EXPECT_EQ(tester.key_calls.size(), 1);
1119 kPhysicalKeyA, kLogicalKeyA, "", kNotSynthesized);
1120 tester.clear_key_calls();
1121 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1122
1123 // Release A
1124 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1126 kWmResultZero)});
1127
1128 EXPECT_EQ(tester.key_calls.size(), 1);
1130 kPhysicalKeyA, kLogicalKeyA, "", kNotSynthesized);
1131 tester.clear_key_calls();
1132 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1133
1134 // Release ControlLeft
1135 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1136 KeyStateChange{VK_LCONTROL, false, true},
1137 WmKeyUpInfo{VK_CONTROL, kScanCodeControl, kNotExtended}.Build(
1138 kWmResultZero)});
1139
1140 EXPECT_EQ(tester.key_calls.size(), 1);
1142 kPhysicalControlLeft, kLogicalControlLeft, "",
1143 kNotSynthesized);
1144 tester.clear_key_calls();
1145 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1146}
1147
1148// Press Ctrl-1. This is special because it yields no WM_CHAR for the 1.
1149TEST_F(KeyboardTest, CtrlLeftDigit1) {
1151 tester.Responding(false);
1152
1153 // US Keyboard layout
1154
1155 // Press ControlLeft
1156 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1157 KeyStateChange{VK_LCONTROL, true, true},
1158 WmKeyDownInfo{VK_CONTROL, kScanCodeControl, kNotExtended, kWasUp}.Build(
1159 kWmResultZero)});
1160
1161 EXPECT_EQ(tester.key_calls.size(), 1);
1163 kPhysicalControlLeft, kLogicalControlLeft, "",
1164 kNotSynthesized);
1165 tester.clear_key_calls();
1166 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1167
1168 // Press 1
1169 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1170 WmKeyDownInfo{kVirtualDigit1, kScanCodeDigit1, kNotExtended, kWasUp}
1171 .Build(kWmResultZero)});
1172
1173 EXPECT_EQ(tester.key_calls.size(), 1);
1175 kPhysicalDigit1, kLogicalDigit1, "", kNotSynthesized);
1176 tester.clear_key_calls();
1177 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1178
1179 // Release 1
1180 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1181 WmKeyUpInfo{kVirtualDigit1, kScanCodeDigit1, kNotExtended}.Build(
1182 kWmResultZero)});
1183
1184 EXPECT_EQ(tester.key_calls.size(), 1);
1186 kPhysicalDigit1, kLogicalDigit1, "", kNotSynthesized);
1187 tester.clear_key_calls();
1188 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1189
1190 // Release ControlLeft
1191 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1192 KeyStateChange{VK_LCONTROL, false, true},
1193 WmKeyUpInfo{VK_CONTROL, kScanCodeControl, kNotExtended}.Build(
1194 kWmResultZero)});
1195
1196 EXPECT_EQ(tester.key_calls.size(), 1);
1198 kPhysicalControlLeft, kLogicalControlLeft, "",
1199 kNotSynthesized);
1200 tester.clear_key_calls();
1201 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1202}
1203
1204// Press 1 on a French keyboard. This is special because it yields WM_CHAR
1205// with char_code '&'.
1206TEST_F(KeyboardTest, Digit1OnFrenchLayout) {
1208 tester.Responding(false);
1209
1210 tester.SetLayout(LayoutFrench);
1211
1212 // Press 1
1213 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1214 WmKeyDownInfo{kVirtualDigit1, kScanCodeDigit1, kNotExtended, kWasUp}
1215 .Build(kWmResultZero),
1216 WmCharInfo{'&', kScanCodeDigit1, kNotExtended, kWasUp}.Build(
1217 kWmResultZero)});
1218
1219 EXPECT_EQ(tester.key_calls.size(), 2);
1221 kPhysicalDigit1, kLogicalDigit1, "&", kNotSynthesized);
1222 EXPECT_CALL_IS_TEXT(tester.key_calls[1], u"&");
1223 tester.clear_key_calls();
1224 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1225
1226 // Release 1
1227 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1228 WmKeyUpInfo{kVirtualDigit1, kScanCodeDigit1, kNotExtended}.Build(
1229 kWmResultZero)});
1230
1231 EXPECT_EQ(tester.key_calls.size(), 1);
1233 kPhysicalDigit1, kLogicalDigit1, "", kNotSynthesized);
1234 tester.clear_key_calls();
1235 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1236}
1237
1238// This tests AltGr-Q on a German keyboard, which should print '@'.
1239TEST_F(KeyboardTest, AltGrModifiedKey) {
1241 tester.Responding(false);
1242
1243 // German Keyboard layout
1244
1245 // Press AltGr, which Win32 precedes with a ContrlLeft down.
1246 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1247 KeyStateChange{VK_LCONTROL, true, true},
1248 WmKeyDownInfo{VK_LCONTROL, kScanCodeControl, kNotExtended, kWasUp}.Build(
1249 kWmResultZero),
1250 KeyStateChange{VK_RMENU, true, true},
1251 WmKeyDownInfo{VK_MENU, kScanCodeAlt, kExtended, kWasUp}.Build(
1252 kWmResultZero)});
1253
1254 EXPECT_EQ(tester.key_calls.size(), 2);
1256 kPhysicalControlLeft, kLogicalControlLeft, "",
1257 kNotSynthesized);
1259 kPhysicalAltRight, kLogicalAltRight, "",
1260 kNotSynthesized);
1261 tester.clear_key_calls();
1262 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1263
1264 // Press Q
1265 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1266 WmKeyDownInfo{kVirtualKeyQ, kScanCodeKeyQ, kNotExtended, kWasUp}.Build(
1267 kWmResultZero),
1268 WmCharInfo{'@', kScanCodeKeyQ, kNotExtended, kWasUp}.Build(
1269 kWmResultZero)});
1270
1271 EXPECT_EQ(tester.key_calls.size(), 2);
1273 kPhysicalKeyQ, kLogicalKeyQ, "@", kNotSynthesized);
1274 EXPECT_CALL_IS_TEXT(tester.key_calls[1], u"@");
1275 tester.clear_key_calls();
1276 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1277
1278 // Release Q
1279 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1280 WmKeyUpInfo{kVirtualKeyQ, kScanCodeKeyQ, kNotExtended}.Build(
1281 kWmResultZero)});
1282
1283 EXPECT_EQ(tester.key_calls.size(), 1);
1285 kPhysicalKeyQ, kLogicalKeyQ, "", kNotSynthesized);
1286 tester.clear_key_calls();
1287 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1288
1289 // Release AltGr. Win32 doesn't dispatch ControlLeft up. Instead Flutter will
1290 // forge one. The AltGr is a system key, therefore will be handled by Win32's
1291 // default WndProc.
1292 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1293 KeyStateChange{VK_LCONTROL, false, true},
1294 ExpectForgedMessage{
1295 WmKeyUpInfo{VK_CONTROL, kScanCodeControl, kNotExtended}.Build(
1296 kWmResultZero)},
1297 KeyStateChange{VK_RMENU, false, true},
1298 WmSysKeyUpInfo{VK_MENU, kScanCodeAlt, kExtended}.Build(
1299 kWmResultDefault)});
1300
1301 EXPECT_EQ(tester.key_calls.size(), 2);
1303 kPhysicalControlLeft, kLogicalControlLeft, "",
1304 kNotSynthesized);
1306 kPhysicalAltRight, kLogicalAltRight, "",
1307 kNotSynthesized);
1308 tester.clear_key_calls();
1309 // The sys key up must not be redispatched. The forged ControlLeft up will.
1310 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1311}
1312
1313// Test the following two key sequences at the same time:
1314//
1315// 1. Tap AltGr, then tap AltGr.
1316// 2. Tap AltGr, hold CtrlLeft, tap AltGr, release CtrlLeft.
1317//
1318// The two sequences are indistinguishable until the very end when a CtrlLeft
1319// up event might or might not follow.
1320//
1321// Sequence 1: CtrlLeft down, AltRight down, AltRight up
1322// Sequence 2: CtrlLeft down, AltRight down, AltRight up, CtrlLeft up
1323//
1324// This is because pressing AltGr alone causes Win32 to send a fake "CtrlLeft
1325// down" event first (see |IsKeyDownAltRight| for detailed explanation).
1326TEST_F(KeyboardTest, AltGrTwice) {
1328 tester.Responding(false);
1329
1330 // 1. AltGr down.
1331
1332 // The key down event causes a ControlLeft down and a AltRight (extended
1333 // AltLeft) down.
1334 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1335 KeyStateChange{VK_LCONTROL, true, true},
1336 WmKeyDownInfo{VK_CONTROL, kScanCodeControl, kNotExtended, kWasUp}.Build(
1337 kWmResultZero),
1338 KeyStateChange{VK_RMENU, true, true},
1339 WmKeyDownInfo{VK_MENU, kScanCodeAlt, kExtended, kWasUp}.Build(
1340 kWmResultZero)});
1341
1342 EXPECT_EQ(tester.key_calls.size(), 2);
1344 kPhysicalControlLeft, kLogicalControlLeft, "",
1345 kNotSynthesized);
1347 kPhysicalAltRight, kLogicalAltRight, "",
1348 kNotSynthesized);
1349 tester.clear_key_calls();
1350 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1351
1352 // 2. AltGr up.
1353
1354 // The key up event only causes a AltRight (extended AltLeft) up.
1355 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1356 KeyStateChange{VK_LCONTROL, false, true},
1357 ExpectForgedMessage{
1358 WmKeyUpInfo{VK_CONTROL, kScanCodeControl, kNotExtended}.Build(
1359 kWmResultZero)},
1360 KeyStateChange{VK_RMENU, false, true},
1361 WmSysKeyUpInfo{VK_MENU, kScanCodeAlt, kExtended}.Build(
1362 kWmResultDefault)});
1363 EXPECT_EQ(tester.key_calls.size(), 2);
1365 kPhysicalControlLeft, kLogicalControlLeft, "",
1366 kNotSynthesized);
1368 kPhysicalAltRight, kLogicalAltRight, "",
1369 kNotSynthesized);
1370 tester.clear_key_calls();
1371 // The sys key up must not be redispatched. The forged ControlLeft up will.
1372 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1373
1374 // 3. AltGr down (or: ControlLeft down then AltRight down.)
1375
1376 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1377 KeyStateChange{VK_LCONTROL, true, false},
1378 WmKeyDownInfo{VK_CONTROL, kScanCodeControl, kNotExtended, kWasUp}.Build(
1379 kWmResultZero),
1380 KeyStateChange{VK_RMENU, true, true},
1381 WmKeyDownInfo{VK_MENU, kScanCodeAlt, kExtended, kWasUp}.Build(
1382 kWmResultZero)});
1383
1384 EXPECT_EQ(tester.key_calls.size(), 2);
1386 kPhysicalControlLeft, kLogicalControlLeft, "",
1387 kNotSynthesized);
1389 kPhysicalAltRight, kLogicalAltRight, "",
1390 kNotSynthesized);
1391 tester.clear_key_calls();
1392 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1393
1394 // 4. AltGr up.
1395
1396 // The key up event only causes a AltRight (extended AltLeft) up.
1397 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1398 KeyStateChange{VK_LCONTROL, false, false},
1399 ExpectForgedMessage{
1400 WmKeyUpInfo{VK_CONTROL, kScanCodeControl, kNotExtended}.Build(
1401 kWmResultZero)},
1402 KeyStateChange{VK_RMENU, false, false},
1403 WmSysKeyUpInfo{VK_MENU, kScanCodeAlt, kExtended}.Build(
1404 kWmResultDefault)});
1405 EXPECT_EQ(tester.key_calls.size(), 2);
1407 kPhysicalControlLeft, kLogicalControlLeft, "",
1408 kNotSynthesized);
1410 kPhysicalAltRight, kLogicalAltRight, "",
1411 kNotSynthesized);
1412 tester.clear_key_calls();
1413 // The sys key up must not be redispatched. The forged ControlLeft up will.
1414 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1415
1416 // 5. For key sequence 2: a real ControlLeft up.
1417 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1418 WmKeyUpInfo{VK_CONTROL, kScanCodeControl, kNotExtended}.Build(
1419 kWmResultZero)});
1420 EXPECT_EQ(tester.key_calls.size(), 1);
1422 kNotSynthesized);
1423 tester.clear_key_calls();
1424 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
1425}
1426
1427// This tests dead key ^ then E on a French keyboard, which should be combined
1428// into ê.
1429TEST_F(KeyboardTest, DeadKeyThatCombines) {
1431 tester.Responding(false);
1432
1433 tester.SetLayout(LayoutFrench);
1434
1435 // Press ^¨ (US: Left bracket)
1436 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1437 WmKeyDownInfo{0xDD, kScanCodeBracketLeft, kNotExtended, kWasUp}.Build(
1438 kWmResultZero),
1439 WmDeadCharInfo{'^', kScanCodeBracketLeft, kNotExtended, kWasUp}.Build(
1440 kWmResultZero)});
1441
1442 EXPECT_EQ(tester.key_calls.size(), 1);
1444 kPhysicalBracketLeft, kLogicalBracketRight, "^",
1445 kNotSynthesized);
1446 tester.clear_key_calls();
1447 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1448
1449 // Release ^¨
1450 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1451 WmKeyUpInfo{0xDD, kScanCodeBracketLeft, kNotExtended}.Build(
1452 kWmResultZero)});
1453
1454 EXPECT_EQ(tester.key_calls.size(), 1);
1456 kPhysicalBracketLeft, kLogicalBracketRight, "",
1457 kNotSynthesized);
1458 tester.clear_key_calls();
1459 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1460
1461 // Press E
1462 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1463 WmKeyDownInfo{kVirtualKeyE, kScanCodeKeyE, kNotExtended, kWasUp}.Build(
1464 kWmResultZero),
1465 WmCharInfo{0xEA, kScanCodeKeyE, kNotExtended, kWasUp}.Build(
1466 kWmResultZero)});
1467
1468 EXPECT_EQ(tester.key_calls.size(), 2);
1470 kPhysicalKeyE, kLogicalKeyE, "ê", kNotSynthesized);
1471 EXPECT_CALL_IS_TEXT(tester.key_calls[1], u"ê");
1472 tester.clear_key_calls();
1473 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1474
1475 // Release E
1476 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1477 WmKeyUpInfo{kVirtualKeyE, kScanCodeKeyE, kNotExtended}.Build(
1478 kWmResultZero)});
1479
1480 EXPECT_EQ(tester.key_calls.size(), 1);
1482 kPhysicalKeyE, kLogicalKeyE, "", kNotSynthesized);
1483 tester.clear_key_calls();
1484 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1485}
1486
1487// This tests dead key ^ then E on a US INTL keyboard, which should be combined
1488// into ê.
1489//
1490// It is different from French AZERTY because the character that the ^ key is
1491// mapped to does not contain the dead key character somehow.
1492TEST_F(KeyboardTest, DeadKeyWithoutDeadMaskThatCombines) {
1494 tester.Responding(false);
1495
1496 // Press ShiftLeft
1497 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1498 KeyStateChange{VK_LSHIFT, true, true},
1500 kWmResultZero)});
1501
1502 EXPECT_EQ(tester.key_calls.size(), 1);
1504 kPhysicalShiftLeft, kLogicalShiftLeft, "",
1505 kNotSynthesized);
1506 tester.clear_key_calls();
1507 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1508
1509 // Press 6^
1510 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1511 WmKeyDownInfo{'6', kScanCodeDigit6, kNotExtended, kWasUp}.Build(
1512 kWmResultZero),
1513 WmDeadCharInfo{'^', kScanCodeDigit6, kNotExtended, kWasUp}.Build(
1514 kWmResultZero)});
1515
1516 EXPECT_EQ(tester.key_calls.size(), 1);
1518 kPhysicalDigit6, kLogicalDigit6, "6", kNotSynthesized);
1519 tester.clear_key_calls();
1520 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1521
1522 // Release 6^
1523 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1524 WmKeyUpInfo{'6', kScanCodeDigit6, kNotExtended}.Build(kWmResultZero)});
1525
1526 EXPECT_EQ(tester.key_calls.size(), 1);
1528 kPhysicalDigit6, kLogicalDigit6, "", kNotSynthesized);
1529 tester.clear_key_calls();
1530 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1531
1532 // Release ShiftLeft
1533 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1534 KeyStateChange{VK_LSHIFT, false, true},
1536 kWmResultZero)});
1537
1538 EXPECT_EQ(tester.key_calls.size(), 1);
1540 kPhysicalShiftLeft, kLogicalShiftLeft, "",
1541 kNotSynthesized);
1542 tester.clear_key_calls();
1543 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1544
1545 // Press E
1546 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1547 WmKeyDownInfo{kVirtualKeyE, kScanCodeKeyE, kNotExtended, kWasUp}.Build(
1548 kWmResultZero),
1549 WmCharInfo{0xEA, kScanCodeKeyE, kNotExtended, kWasUp}.Build(
1550 kWmResultZero)});
1551
1552 EXPECT_EQ(tester.key_calls.size(), 2);
1554 kPhysicalKeyE, kLogicalKeyE, "ê", kNotSynthesized);
1555 EXPECT_CALL_IS_TEXT(tester.key_calls[1], u"ê");
1556 tester.clear_key_calls();
1557 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1558
1559 // Release E
1560 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1561 WmKeyUpInfo{kVirtualKeyE, kScanCodeKeyE, kNotExtended}.Build(
1562 kWmResultZero)});
1563
1564 EXPECT_EQ(tester.key_calls.size(), 1);
1566 kPhysicalKeyE, kLogicalKeyE, "", kNotSynthesized);
1567 tester.clear_key_calls();
1568 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1569}
1570
1571// This tests dead key ^ then & (US: 1) on a French keyboard, which do not
1572// combine and should output "^&".
1573TEST_F(KeyboardTest, DeadKeyThatDoesNotCombine) {
1575 tester.Responding(false);
1576
1577 tester.SetLayout(LayoutFrench);
1578
1579 // Press ^¨ (US: Left bracket)
1580 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1581 WmKeyDownInfo{0xDD, kScanCodeBracketLeft, kNotExtended, kWasUp}.Build(
1582 kWmResultZero),
1583 WmDeadCharInfo{'^', kScanCodeBracketLeft, kNotExtended, kWasUp}.Build(
1584 kWmResultZero)});
1585
1586 EXPECT_EQ(tester.key_calls.size(), 1);
1588 kPhysicalBracketLeft, kLogicalBracketRight, "^",
1589 kNotSynthesized);
1590 tester.clear_key_calls();
1591 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1592
1593 // Release ^¨
1594 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1595 WmKeyUpInfo{0xDD, kScanCodeBracketLeft, kNotExtended}.Build(
1596 kWmResultZero)});
1597
1598 EXPECT_EQ(tester.key_calls.size(), 1);
1600 kPhysicalBracketLeft, kLogicalBracketRight, "",
1601 kNotSynthesized);
1602 tester.clear_key_calls();
1603 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1604
1605 // Press 1
1606 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1607 WmKeyDownInfo{kVirtualDigit1, kScanCodeDigit1, kNotExtended, kWasUp}
1608 .Build(kWmResultZero),
1609 WmCharInfo{'^', kScanCodeDigit1, kNotExtended, kWasUp}.Build(
1610 kWmResultZero),
1611 WmCharInfo{'&', kScanCodeDigit1, kNotExtended, kWasUp}.Build(
1612 kWmResultZero)});
1613
1614 EXPECT_EQ(tester.key_calls.size(), 3);
1616 kPhysicalDigit1, kLogicalDigit1, "^", kNotSynthesized);
1617 EXPECT_CALL_IS_TEXT(tester.key_calls[1], u"^");
1618 EXPECT_CALL_IS_TEXT(tester.key_calls[2], u"&");
1619 tester.clear_key_calls();
1620 // TODO(dkwingsmt): This count should probably be 3. Currently the '^'
1621 // message is redispatched due to being part of the KeyDown session, which is
1622 // not handled by the framework, while the '&' message is not redispatched
1623 // for being a standalone message. We should resolve this inconsistency.
1624 // https://github.com/flutter/flutter/issues/98306
1625 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1626
1627 // Release 1
1628 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1629 WmKeyUpInfo{kVirtualDigit1, kScanCodeDigit1, kNotExtended}.Build(
1630 kWmResultZero)});
1631
1632 EXPECT_EQ(tester.key_calls.size(), 1);
1634 kPhysicalDigit1, kLogicalDigit1, "", kNotSynthesized);
1635 tester.clear_key_calls();
1636 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1637}
1638
1639// This tests dead key `, then dead key `, then e.
1640//
1641// It should output ``e, instead of `è.
1642TEST_F(KeyboardTest, DeadKeyTwiceThenLetter) {
1644 tester.Responding(false);
1645
1646 // US INTL layout.
1647
1648 // Press `
1649 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1650 WmKeyDownInfo{0xC0, kScanCodeBackquote, kNotExtended, kWasUp}.Build(
1651 kWmResultZero),
1652 WmDeadCharInfo{'`', kScanCodeBackquote, kNotExtended, kWasUp}.Build(
1653 kWmResultZero)});
1654
1655 EXPECT_EQ(tester.key_calls.size(), 1);
1657 kPhysicalBackquote, kLogicalBackquote, "`",
1658 kNotSynthesized);
1659 tester.clear_key_calls();
1660 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1661
1662 // Release `
1663 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1664 WmKeyUpInfo{0xC0, kScanCodeBackquote, kNotExtended}.Build(
1665 kWmResultZero)});
1666
1667 EXPECT_EQ(tester.key_calls.size(), 1);
1669 kPhysicalBackquote, kLogicalBackquote, "",
1670 kNotSynthesized);
1671 tester.clear_key_calls();
1672 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1673
1674 // Press ` again.
1675 // The response should be slow.
1676 std::vector<MockKeyResponseController::ResponseCallback> recorded_callbacks;
1677 tester.LateResponding(
1678 [&recorded_callbacks](
1679 const FlutterKeyEvent* event,
1680 MockKeyResponseController::ResponseCallback callback) {
1681 recorded_callbacks.push_back(callback);
1682 });
1683
1684 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1685 WmKeyDownInfo{0xC0, kScanCodeBackquote, kNotExtended, kWasUp}.Build(
1686 kWmResultZero),
1687 WmCharInfo{'`', kScanCodeBackquote, kNotExtended, kWasUp, kBeingReleased,
1688 kNoContext, 1, /*bit25*/ true}
1689 .Build(kWmResultZero),
1690 WmCharInfo{'`', kScanCodeBackquote, kNotExtended, kWasUp}.Build(
1691 kWmResultZero)});
1692
1693 EXPECT_EQ(recorded_callbacks.size(), 1);
1694 EXPECT_EQ(tester.key_calls.size(), 1);
1696 kPhysicalBackquote, kLogicalBackquote, "`",
1697 kNotSynthesized);
1698 tester.clear_key_calls();
1699 // Key down event responded with false.
1700 recorded_callbacks.front()(false);
1701 EXPECT_EQ(tester.key_calls.size(), 2);
1702 EXPECT_CALL_IS_TEXT(tester.key_calls[0], u"`");
1703 EXPECT_CALL_IS_TEXT(tester.key_calls[1], u"`");
1704 tester.clear_key_calls();
1705 // TODO(dkwingsmt): This count should probably be 3. See the comment above
1706 // that is marked with the same issue.
1707 // https://github.com/flutter/flutter/issues/98306
1708 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
1709
1710 tester.Responding(false);
1711
1712 // Release `
1713 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1714 WmKeyUpInfo{0xC0, kScanCodeBackquote, kNotExtended}.Build(
1715 kWmResultZero)});
1716
1717 EXPECT_EQ(tester.key_calls.size(), 1);
1719 kPhysicalBackquote, kLogicalBackquote, "",
1720 kNotSynthesized);
1721 tester.clear_key_calls();
1722 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1723}
1724
1725// This tests when the resulting character needs to be combined with surrogates.
1726TEST_F(KeyboardTest, MultibyteCharacter) {
1728 tester.Responding(false);
1729
1730 // Gothic Keyboard layout. (We need a layout that yields non-BMP characters
1731 // without IME, which is actually very rare.)
1732
1733 // Press key W of a US keyboard, which should yield character '𐍅'.
1734 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1735 WmKeyDownInfo{kVirtualKeyW, kScanCodeKeyW, kNotExtended, kWasUp}.Build(
1736 kWmResultZero),
1737 WmCharInfo{0xd800, kScanCodeKeyW, kNotExtended, kWasUp}.Build(
1738 kWmResultZero),
1739 WmCharInfo{0xdf45, kScanCodeKeyW, kNotExtended, kWasUp}.Build(
1740 kWmResultZero)});
1741
1742 const char* st = tester.key_calls[0].key_event.character;
1743
1744 EXPECT_EQ(tester.key_calls.size(), 2);
1746 kPhysicalKeyW, kLogicalKeyW, "𐍅", kNotSynthesized);
1747 EXPECT_CALL_IS_TEXT(tester.key_calls[1], u"𐍅");
1748 tester.clear_key_calls();
1749 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 3);
1750
1751 // Release W
1752 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1753 WmKeyUpInfo{kVirtualKeyW, kScanCodeKeyW, kNotExtended}.Build(
1754 kWmResultZero)});
1755
1756 EXPECT_EQ(tester.key_calls.size(), 1);
1758 kPhysicalKeyW, kLogicalKeyW, "", kNotSynthesized);
1759 tester.clear_key_calls();
1760 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1761}
1762
1763TEST_F(KeyboardTest, SynthesizeModifiers) {
1765 tester.Responding(false);
1766
1767 // Two dummy events used to trigger synthesization.
1768 Win32Message event1 =
1769 WmKeyDownInfo{VK_BACK, kScanCodeBackspace, kNotExtended, kWasUp}.Build(
1770 kWmResultZero);
1771 Win32Message event2 =
1772 WmKeyUpInfo{VK_BACK, kScanCodeBackspace, kNotExtended}.Build(
1773 kWmResultZero);
1774
1775 // ShiftLeft
1776 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1777 KeyStateChange{VK_LSHIFT, true, true}, event1});
1778 EXPECT_EQ(tester.key_calls.size(), 2);
1780 kPhysicalShiftLeft, kLogicalShiftLeft, "", kSynthesized);
1781 tester.clear_key_calls();
1782 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1783
1784 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1785 KeyStateChange{VK_LSHIFT, false, true}, event2});
1786 EXPECT_EQ(tester.key_calls.size(), 2);
1788 kPhysicalShiftLeft, kLogicalShiftLeft, "", kSynthesized);
1789 tester.clear_key_calls();
1790 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1791
1792 // ShiftRight
1793 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1794 KeyStateChange{VK_RSHIFT, true, true}, event1});
1795 EXPECT_EQ(tester.key_calls.size(), 2);
1797 kPhysicalShiftRight, kLogicalShiftRight, "",
1798 kSynthesized);
1799 tester.clear_key_calls();
1800 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1801
1802 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1803 KeyStateChange{VK_RSHIFT, false, true}, event2});
1804 EXPECT_EQ(tester.key_calls.size(), 2);
1806 kPhysicalShiftRight, kLogicalShiftRight, "",
1807 kSynthesized);
1808 tester.clear_key_calls();
1809 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1810
1811 // ControlLeft
1812 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1813 KeyStateChange{VK_LCONTROL, true, true}, event1});
1814 EXPECT_EQ(tester.key_calls.size(), 2);
1816 kPhysicalControlLeft, kLogicalControlLeft, "",
1817 kSynthesized);
1818 tester.clear_key_calls();
1819 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1820
1821 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1822 KeyStateChange{VK_LCONTROL, false, true}, event2});
1823 EXPECT_EQ(tester.key_calls.size(), 2);
1825 kPhysicalControlLeft, kLogicalControlLeft, "",
1826 kSynthesized);
1827 tester.clear_key_calls();
1828 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1829
1830 // ControlRight
1831 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1832 KeyStateChange{VK_RCONTROL, true, true}, event1});
1833 EXPECT_EQ(tester.key_calls.size(), 2);
1835 kPhysicalControlRight, kLogicalControlRight, "",
1836 kSynthesized);
1837 tester.clear_key_calls();
1838 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1839
1840 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1841 KeyStateChange{VK_RCONTROL, false, true}, event2});
1842 EXPECT_EQ(tester.key_calls.size(), 2);
1844 kPhysicalControlRight, kLogicalControlRight, "",
1845 kSynthesized);
1846 tester.clear_key_calls();
1847 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1848
1849 // AltLeft
1850 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1851 KeyStateChange{VK_LMENU, true, true}, event1});
1852 EXPECT_EQ(tester.key_calls.size(), 2);
1854 kPhysicalAltLeft, kLogicalAltLeft, "", kSynthesized);
1855 tester.clear_key_calls();
1856 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1857
1858 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1859 KeyStateChange{VK_LMENU, false, true}, event2});
1860 EXPECT_EQ(tester.key_calls.size(), 2);
1862 kPhysicalAltLeft, kLogicalAltLeft, "", kSynthesized);
1863 tester.clear_key_calls();
1864 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1865
1866 // AltRight
1867 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1868 KeyStateChange{VK_RMENU, true, true}, event1});
1869 EXPECT_EQ(tester.key_calls.size(), 2);
1871 kPhysicalAltRight, kLogicalAltRight, "", kSynthesized);
1872 tester.clear_key_calls();
1873 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1874
1875 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1876 KeyStateChange{VK_RMENU, false, true}, event2});
1877 EXPECT_EQ(tester.key_calls.size(), 2);
1879 kPhysicalAltRight, kLogicalAltRight, "", kSynthesized);
1880 tester.clear_key_calls();
1881 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1882
1883 // MetaLeft
1884 tester.InjectKeyboardChanges(
1885 std::vector<KeyboardChange>{KeyStateChange{VK_LWIN, true, true}, event1});
1886 EXPECT_EQ(tester.key_calls.size(), 2);
1888 kPhysicalMetaLeft, kLogicalMetaLeft, "", kSynthesized);
1889 tester.clear_key_calls();
1890 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1891
1892 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1893 KeyStateChange{VK_LWIN, false, true}, event2});
1894 EXPECT_EQ(tester.key_calls.size(), 2);
1896 kPhysicalMetaLeft, kLogicalMetaLeft, "", kSynthesized);
1897 tester.clear_key_calls();
1898 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1899
1900 // MetaRight
1901 tester.InjectKeyboardChanges(
1902 std::vector<KeyboardChange>{KeyStateChange{VK_RWIN, true, true}, event1});
1903 EXPECT_EQ(tester.key_calls.size(), 2);
1905 kPhysicalMetaRight, kLogicalMetaRight, "", kSynthesized);
1906 tester.clear_key_calls();
1907 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1908
1909 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1910 KeyStateChange{VK_RWIN, false, true}, event2});
1911 EXPECT_EQ(tester.key_calls.size(), 2);
1913 kPhysicalMetaRight, kLogicalMetaRight, "", kSynthesized);
1914 tester.clear_key_calls();
1915 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1916
1917 // CapsLock, phase 0 -> 2 -> 0.
1918 // (For phases, see |SynchronizeCriticalToggledStates|.)
1919 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1920 KeyStateChange{VK_CAPITAL, false, true}, event1});
1921 EXPECT_EQ(tester.key_calls.size(), 3);
1923 kPhysicalCapsLock, kLogicalCapsLock, "", kSynthesized);
1925 kPhysicalCapsLock, kLogicalCapsLock, "", kSynthesized);
1926 tester.clear_key_calls();
1927 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1928
1929 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1930 KeyStateChange{VK_CAPITAL, false, false}, event2});
1931 EXPECT_EQ(tester.key_calls.size(), 3);
1933 kPhysicalCapsLock, kLogicalCapsLock, "", kSynthesized);
1935 kPhysicalCapsLock, kLogicalCapsLock, "", kSynthesized);
1936 tester.clear_key_calls();
1937 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1938
1939 // ScrollLock, phase 0 -> 1 -> 3
1940 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1941 KeyStateChange{VK_SCROLL, true, true}, event1});
1942 EXPECT_EQ(tester.key_calls.size(), 2);
1944 kPhysicalScrollLock, kLogicalScrollLock, "",
1945 kSynthesized);
1946 tester.clear_key_calls();
1947 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1948
1949 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1950 KeyStateChange{VK_SCROLL, true, false}, event2});
1951 EXPECT_EQ(tester.key_calls.size(), 3);
1953 kPhysicalScrollLock, kLogicalScrollLock, "",
1954 kSynthesized);
1956 kPhysicalScrollLock, kLogicalScrollLock, "",
1957 kSynthesized);
1958 tester.clear_key_calls();
1959 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1960
1961 // NumLock, phase 0 -> 3 -> 2
1962 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1963 KeyStateChange{VK_NUMLOCK, true, false}, event1});
1964 // TODO(dkwingsmt): Synthesizing from phase 0 to 3 should yield a full key
1965 // tap and a key down. Fix the algorithm so that the following result becomes
1966 // 4 keycalls with an extra pair of key down and up.
1967 // https://github.com/flutter/flutter/issues/98533
1968 EXPECT_EQ(tester.key_calls.size(), 2);
1970 kPhysicalNumLock, kLogicalNumLock, "", kSynthesized);
1971 tester.clear_key_calls();
1972 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1973
1974 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
1975 KeyStateChange{VK_NUMLOCK, false, true}, event2});
1976 EXPECT_EQ(tester.key_calls.size(), 4);
1978 kPhysicalNumLock, kLogicalNumLock, "", kSynthesized);
1980 kPhysicalNumLock, kLogicalNumLock, "", kSynthesized);
1982 kPhysicalNumLock, kLogicalNumLock, "", kSynthesized);
1983 tester.clear_key_calls();
1984 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
1985}
1986
1987// Pressing extended keys during IME events should work properly by not sending
1988// any events.
1989//
1990// Regression test for https://github.com/flutter/flutter/issues/95888 .
1991TEST_F(KeyboardTest, ImeExtendedEventsAreIgnored) {
1993 tester.Responding(false);
1994
1995 // US Keyboard layout.
1996
1997 // There should be preceding key events to make the keyboard into IME mode.
1998 // Omit them in this test since they are not relavent.
1999
2000 // Press CtrlRight in IME mode.
2001 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2002 KeyStateChange{VK_RCONTROL, true, false},
2003 WmKeyDownInfo{VK_PROCESSKEY, kScanCodeControl, kExtended, kWasUp}.Build(
2004 kWmResultZero)});
2005
2006 EXPECT_EQ(tester.key_calls.size(), 1);
2008 kNotSynthesized);
2009 tester.clear_key_calls();
2010 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
2011}
2012
2013// Ensures that synthesization works correctly when a Shift key is pressed and
2014// (only) its up event is labeled as an IME event (VK_PROCESSKEY).
2015//
2016// Regression test for https://github.com/flutter/flutter/issues/104169. These
2017// are real messages recorded when pressing Shift-2 using Microsoft Pinyin IME
2018// on Win 10 Enterprise, which crashed the app before the fix.
2019TEST_F(KeyboardTest, UpOnlyImeEventsAreCorrectlyHandled) {
2021 tester.Responding(true);
2022
2023 // US Keyboard layout.
2024
2025 // Press CtrlRight in IME mode.
2026 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2027 KeyStateChange{VK_LSHIFT, true, false},
2029 kWmResultZero),
2030 WmKeyDownInfo{VK_PROCESSKEY, kScanCodeDigit2, kNotExtended, kWasUp}.Build(
2031 kWmResultZero),
2032 KeyStateChange{VK_LSHIFT, false, true},
2033 WmKeyUpInfo{VK_PROCESSKEY, kScanCodeShiftLeft, kNotExtended}.Build(
2034 kWmResultZero),
2035 WmKeyUpInfo{'2', kScanCodeDigit2, kNotExtended, kWasUp}.Build(
2036 kWmResultZero)});
2037
2038 EXPECT_EQ(tester.key_calls.size(), 4);
2040 kPhysicalShiftLeft, kLogicalShiftLeft, "",
2041 kNotSynthesized);
2043 kNotSynthesized);
2045 kPhysicalShiftLeft, kLogicalShiftLeft, "",
2046 kNotSynthesized);
2048 kNotSynthesized);
2049 tester.clear_key_calls();
2050}
2051
2052// Regression test for a crash in an earlier implementation.
2053//
2054// In real life, the framework responds slowly. The next real event might
2055// arrive earlier than the framework response, and if the 2nd event has an
2056// identical hash as the one waiting for response, an earlier implementation
2057// will crash upon the response.
2058TEST_F(KeyboardTest, SlowFrameworkResponse) {
2060
2061 std::vector<MockKeyResponseController::ResponseCallback> recorded_callbacks;
2062
2063 // Store callbacks to manually call them.
2064 tester.LateResponding(
2065 [&recorded_callbacks](
2066 const FlutterKeyEvent* event,
2067 MockKeyResponseController::ResponseCallback callback) {
2068 recorded_callbacks.push_back(callback);
2069 });
2070
2071 // Press A
2072 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2074 kWmResultZero),
2075 WmCharInfo{'a', kScanCodeKeyA, kNotExtended, kWasUp}.Build(
2076 kWmResultZero)});
2077
2078 // Hold A
2079 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2081 kWmResultZero),
2082 WmCharInfo{'a', kScanCodeKeyA, kNotExtended, kWasDown}.Build(
2083 kWmResultZero)});
2084
2085 EXPECT_EQ(tester.key_calls.size(), 1);
2087 kPhysicalKeyA, kLogicalKeyA, "a", kNotSynthesized);
2088 EXPECT_EQ(recorded_callbacks.size(), 1);
2089 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
2090
2091 // The first response.
2092 recorded_callbacks.front()(false);
2093
2094 EXPECT_EQ(tester.key_calls.size(), 3);
2095 EXPECT_EQ(recorded_callbacks.size(), 2);
2096 EXPECT_CALL_IS_TEXT(tester.key_calls[1], u"a");
2098 kPhysicalKeyA, kLogicalKeyA, "a", kNotSynthesized);
2099 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
2100
2101 // The second response.
2102 recorded_callbacks.back()(false);
2103
2104 EXPECT_EQ(tester.key_calls.size(), 4);
2105 EXPECT_CALL_IS_TEXT(tester.key_calls[3], u"a");
2106 tester.clear_key_calls();
2107 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
2108}
2109
2110// Regression test for https://github.com/flutter/flutter/issues/84210.
2111//
2112// When the framework response is slow during a sequence of identical messages,
2113// make sure the real messages are not mistaken as redispatched messages,
2114// in order to not mess up the order of events.
2115//
2116// In this test we use:
2117//
2118// KeyA down, KeyA up, (down event responded with false), KeyA down, KeyA up,
2119//
2120// The code must not take the 2nd real key down events as a redispatched event.
2121TEST_F(KeyboardTest, SlowFrameworkResponseForIdenticalEvents) {
2123 std::vector<MockKeyResponseController::ResponseCallback> recorded_callbacks;
2124
2125 // Store callbacks to manually call them.
2126 tester.LateResponding(
2127 [&recorded_callbacks](
2128 const FlutterKeyEvent* event,
2129 MockKeyResponseController::ResponseCallback callback) {
2130 recorded_callbacks.push_back(callback);
2131 });
2132
2133 // Press A
2134 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2136 kWmResultZero),
2137 WmCharInfo{'a', kScanCodeKeyA, kNotExtended, kWasUp}.Build(
2138 kWmResultZero)});
2139
2140 EXPECT_EQ(tester.key_calls.size(), 1);
2142 kPhysicalKeyA, kLogicalKeyA, "a", kNotSynthesized);
2143 tester.clear_key_calls();
2144 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
2145
2146 // Release A
2147 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2149 kWmResultZero)});
2150
2151 EXPECT_EQ(tester.key_calls.size(), 0);
2152 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
2153
2154 // The first down event responded with false.
2155 EXPECT_EQ(recorded_callbacks.size(), 1);
2156 recorded_callbacks.front()(false);
2157
2158 EXPECT_EQ(tester.key_calls.size(), 2);
2159 EXPECT_CALL_IS_TEXT(tester.key_calls[0], u"a");
2161 kPhysicalKeyA, kLogicalKeyA, "", kNotSynthesized);
2162 tester.clear_key_calls();
2163 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
2164
2165 // Press A again
2166 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2168 kWmResultZero),
2169 WmCharInfo{'a', kScanCodeKeyA, kNotExtended, kWasUp}.Build(
2170 kWmResultZero)});
2171
2172 // Nothing more was dispatched because the first up event hasn't been
2173 // responded yet.
2174 EXPECT_EQ(recorded_callbacks.size(), 2);
2175 EXPECT_EQ(tester.key_calls.size(), 0);
2176 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
2177
2178 // The first up event responded with false, which was redispatched, and caused
2179 // the down event to be dispatched.
2180 recorded_callbacks.back()(false);
2181 EXPECT_EQ(tester.key_calls.size(), 1);
2183 kPhysicalKeyA, kLogicalKeyA, "a", kNotSynthesized);
2184 tester.clear_key_calls();
2185 EXPECT_EQ(recorded_callbacks.size(), 3);
2186 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
2187
2188 // Release A again
2189 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2191 kWmResultZero)});
2192
2193 EXPECT_EQ(tester.key_calls.size(), 0);
2194 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
2195}
2196
2197TEST_F(KeyboardTest, TextInputSubmit) {
2199 tester.Responding(false);
2200
2201 // US Keyboard layout
2202
2203 tester.InjectPlatformMessage(
2204 "flutter/textinput", "TextInput.setClient",
2205 R"|([108, {"inputAction": "TextInputAction.none"}])|");
2206
2207 // Press Enter
2208 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2209 WmKeyDownInfo{VK_RETURN, kScanCodeEnter, kNotExtended, kWasUp}.Build(
2210 kWmResultZero),
2211 WmCharInfo{'\n', kScanCodeEnter, kNotExtended, kWasUp}.Build(
2212 kWmResultZero)});
2213
2214 EXPECT_EQ(tester.key_calls.size(), 2);
2216 kPhysicalEnter, kLogicalEnter, "", kNotSynthesized);
2218 tester.key_calls[1],
2219 "{"
2220 R"|("method":"TextInputClient.performAction",)|"
2221 R"|("args":[108,"TextInputAction.none"])|"
2222 "}");
2223 tester.clear_key_calls();
2224 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
2225
2226 // Release Enter
2227 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2228 WmKeyUpInfo{VK_RETURN, kScanCodeEnter, kNotExtended}.Build(
2229 kWmResultZero)});
2230
2231 EXPECT_EQ(tester.key_calls.size(), 1);
2233 kPhysicalEnter, kLogicalEnter, "", kNotSynthesized);
2234 tester.clear_key_calls();
2235 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
2236
2237 // Make sure OnText is not obstructed after pressing Enter.
2238 //
2239 // Regression test for https://github.com/flutter/flutter/issues/97706.
2240
2241 // Press A
2242 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2244 kWmResultZero),
2245 WmCharInfo{'a', kScanCodeKeyA, kNotExtended, kWasUp}.Build(
2246 kWmResultZero)});
2247
2248 EXPECT_EQ(tester.key_calls.size(), 2);
2250 kPhysicalKeyA, kLogicalKeyA, "a", kNotSynthesized);
2251 EXPECT_CALL_IS_TEXT(tester.key_calls[1], u"a");
2252 tester.clear_key_calls();
2253
2254 // Release A
2255 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2257 kWmResultZero)});
2258
2259 EXPECT_EQ(tester.key_calls.size(), 1);
2261 kPhysicalKeyA, kLogicalKeyA, "", kNotSynthesized);
2262 tester.clear_key_calls();
2263}
2264
2265TEST_F(KeyboardTest, VietnameseTelexAddDiacriticWithFastResponse) {
2266 // In this test, the user presses the folloing keys:
2267 //
2268 // Key Current text
2269 // ===========================
2270 // A a
2271 // F à
2272 //
2273 // And the Backspace event is responded immediately.
2274
2276 tester.Responding(false);
2277
2278 // US Keyboard layout
2279
2280 // Press A
2281 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2283 kWmResultZero),
2284 WmCharInfo{'a', kScanCodeKeyA, kNotExtended, kWasUp}.Build(
2285 kWmResultZero)});
2286
2287 EXPECT_EQ(tester.key_calls.size(), 2);
2289 kPhysicalKeyA, kLogicalKeyA, "a", kNotSynthesized);
2290 EXPECT_CALL_IS_TEXT(tester.key_calls[1], u"a");
2291 tester.clear_key_calls();
2292 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
2293
2294 // Release A
2295 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2297 kWmResultZero)});
2298
2299 EXPECT_EQ(tester.key_calls.size(), 1);
2301 kPhysicalKeyA, kLogicalKeyA, "", kNotSynthesized);
2302 tester.clear_key_calls();
2303 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
2304
2305 // Press F, which is translated to:
2306 //
2307 // Backspace down, char & up, then VK_PACKET('à').
2308 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2309 WmKeyDownInfo{VK_BACK, kScanCodeBackspace, kNotExtended, kWasUp}.Build(
2310 kWmResultZero),
2311 WmCharInfo{0x8, kScanCodeBackspace, kNotExtended, kWasUp}.Build(
2312 kWmResultZero),
2313 WmKeyUpInfo{VK_BACK, kScanCodeBackspace, kNotExtended}.Build(
2314 kWmResultZero),
2315 WmKeyDownInfo{VK_PACKET, 0, kNotExtended, kWasUp}.Build(kWmResultDefault),
2316 WmCharInfo{0xe0 /*'à'*/, 0, kNotExtended, kWasUp}.Build(kWmResultZero),
2317 WmKeyUpInfo{VK_PACKET, 0, kNotExtended}.Build(kWmResultDefault)});
2318
2319 EXPECT_EQ(tester.key_calls.size(), 3);
2321 kPhysicalBackspace, kLogicalBackspace, "",
2322 kNotSynthesized);
2324 kPhysicalBackspace, kLogicalBackspace, "",
2325 kNotSynthesized);
2326 EXPECT_CALL_IS_TEXT(tester.key_calls[2], u"à");
2327 tester.clear_key_calls();
2328 // TODO(dkwingsmt): This count should probably be 4. Currently the CHAR 0x8
2329 // message is redispatched due to being part of the KeyDown session, which is
2330 // not handled by the framework, while the 'à' message is not redispatched
2331 // for being a standalone message. We should resolve this inconsistency.
2332 // https://github.com/flutter/flutter/issues/98306
2333 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 3);
2334
2335 // Release F
2336 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2337 WmKeyUpInfo{kVirtualKeyF, kScanCodeKeyF, kNotExtended,
2338 /* overwrite_prev_state_0 */ true}
2339 .Build(kWmResultZero)});
2340
2341 EXPECT_EQ(tester.key_calls.size(), 1);
2343 kNotSynthesized);
2344 tester.clear_key_calls();
2345 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
2346}
2347
2348void VietnameseTelexAddDiacriticWithSlowResponse(WindowsTestContext& context,
2349 bool backspace_response) {
2350 // In this test, the user presses the following keys:
2351 //
2352 // Key Current text
2353 // ===========================
2354 // A a
2355 // F à
2356 //
2357 // And the Backspace down event is responded slowly with `backspace_response`.
2358
2359 KeyboardTester tester{context};
2360 tester.Responding(false);
2361
2362 // US Keyboard layout
2363
2364 // Press A
2365 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2367 kWmResultZero),
2368 WmCharInfo{'a', kScanCodeKeyA, kNotExtended, kWasUp}.Build(
2369 kWmResultZero)});
2370
2371 EXPECT_EQ(tester.key_calls.size(), 2);
2373 kPhysicalKeyA, kLogicalKeyA, "a", kNotSynthesized);
2374 EXPECT_CALL_IS_TEXT(tester.key_calls[1], u"a");
2375 tester.clear_key_calls();
2376 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2);
2377
2378 // Release A
2379 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2381 kWmResultZero)});
2382
2383 EXPECT_EQ(tester.key_calls.size(), 1);
2385 kPhysicalKeyA, kLogicalKeyA, "", kNotSynthesized);
2386 tester.clear_key_calls();
2387 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
2388
2389 std::vector<MockKeyResponseController::ResponseCallback> recorded_callbacks;
2390 tester.LateResponding(
2391 [&recorded_callbacks](
2392 const FlutterKeyEvent* event,
2393 MockKeyResponseController::ResponseCallback callback) {
2394 recorded_callbacks.push_back(callback);
2395 });
2396
2397 // Press F, which is translated to:
2398 //
2399 // Backspace down, char & up, VK_PACKET('à').
2400 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2401 WmKeyDownInfo{VK_BACK, kScanCodeBackspace, kNotExtended, kWasUp}.Build(
2402 kWmResultZero),
2403 WmCharInfo{0x8, kScanCodeBackspace, kNotExtended, kWasUp}.Build(
2404 kWmResultZero),
2405 WmKeyUpInfo{VK_BACK, kScanCodeBackspace, kNotExtended}.Build(
2406 kWmResultZero),
2407 WmKeyDownInfo{VK_PACKET, 0, kNotExtended, kWasUp}.Build(kWmResultDefault),
2408 WmCharInfo{0xe0 /*'à'*/, 0, kNotExtended, kWasUp}.Build(kWmResultZero),
2409 WmKeyUpInfo{VK_PACKET, 0, kNotExtended}.Build(kWmResultDefault)});
2410
2411 // The Backspace event has not responded yet, therefore the char message must
2412 // hold. This is because when the framework is handling the Backspace event,
2413 // it will send a setEditingState message that updates the text state that has
2414 // the last character deleted (denoted by `string1`). Processing the char
2415 // message before then will cause the final text to set to `string1`.
2416 EXPECT_EQ(tester.key_calls.size(), 1);
2418 kPhysicalBackspace, kLogicalBackspace, "",
2419 kNotSynthesized);
2420 tester.clear_key_calls();
2421 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
2422
2423 EXPECT_EQ(recorded_callbacks.size(), 1);
2424 recorded_callbacks[0](backspace_response);
2425
2426 EXPECT_EQ(tester.key_calls.size(), 1);
2428 kPhysicalBackspace, kLogicalBackspace, "",
2429 kNotSynthesized);
2430 tester.clear_key_calls();
2431 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(),
2432 backspace_response ? 0 : 2);
2433
2434 recorded_callbacks[1](false);
2435 EXPECT_EQ(tester.key_calls.size(), 1);
2436 EXPECT_CALL_IS_TEXT(tester.key_calls[0], u"à");
2437 tester.clear_key_calls();
2438 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1);
2439
2440 tester.Responding(false);
2441
2442 // Release F
2443 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2444 WmKeyUpInfo{kVirtualKeyF, kScanCodeKeyF, kNotExtended,
2445 /* overwrite_prev_state_0 */ true}
2446 .Build(kWmResultZero)});
2447
2448 EXPECT_EQ(tester.key_calls.size(), 1);
2450 kNotSynthesized);
2451 tester.clear_key_calls();
2452 EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0);
2453}
2454
2455TEST_F(KeyboardTest, VietnameseTelexAddDiacriticWithSlowFalseResponse) {
2457}
2458
2459TEST_F(KeyboardTest, VietnameseTelexAddDiacriticWithSlowTrueResponse) {
2461}
2462
2463// Ensure that the scancode-less key events issued by Narrator
2464// when toggling caps lock don't violate assert statements.
2465TEST_F(KeyboardTest, DoubleCapsLock) {
2467 tester.Responding(false);
2468
2469 tester.InjectKeyboardChanges(std::vector<KeyboardChange>{
2470 WmKeyDownInfo{VK_CAPITAL, 0, kNotExtended}.Build(),
2471 WmKeyUpInfo{VK_CAPITAL, 0, kNotExtended}.Build()});
2472
2473 tester.clear_key_calls();
2474}
2475
2476} // namespace testing
2477} // namespace flutter
@ kFlutterKeyEventTypeDown
Definition embedder.h:1074
@ kFlutterKeyEventTypeUp
Definition embedder.h:1073
@ kFlutterKeyEventTypeRepeat
Definition embedder.h:1075
TEST_F(FlGnomeSettingsTest, ClockFormat)
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
FlKeyEvent * event
#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)
SK_API GrDirectContext * GetContext(const SkImage *src)
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

◆ []

union { ... } content

◆ 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

FlutterKeyEvent key_event

Definition at line 331 of file keyboard_unittests.cc.

◆ 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.

◆ 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