From 7e0fa774841e5e055f14faaccc7ae548d4458dec Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 7 Feb 2022 04:43:22 -0800 Subject: [PATCH 01/22] Tests --- .../windows/keyboard_win32_unittests.cc | 137 ++++++++++++++---- .../platform/windows/testing/test_keyboard.cc | 36 ++--- .../platform/windows/testing/test_keyboard.h | 14 +- 3 files changed, 134 insertions(+), 53 deletions(-) diff --git a/shell/platform/windows/keyboard_win32_unittests.cc b/shell/platform/windows/keyboard_win32_unittests.cc index 14869f56eb462..cd11d1f9c5b03 100644 --- a/shell/platform/windows/keyboard_win32_unittests.cc +++ b/shell/platform/windows/keyboard_win32_unittests.cc @@ -81,6 +81,25 @@ class TestKeyboardManagerWin32 : public KeyboardManagerWin32 { bool during_redispatch_ = false; }; +struct KeyboardStateChange { + uint32_t key; + bool pressed; + bool toggled_on; +}; + +class TestKeystate { + public: + void Set(uint32_t virtual_key, bool pressed, bool toggled_on = false) { + state_[virtual_key] = (pressed ? kStateMaskPressed : 0) | + (toggled_on ? kStateMaskToggled : 0); + } + + SHORT Get(uint32_t virtual_key) { return state_[virtual_key]; } + + private: + std::map state_; +}; + class MockKeyboardManagerWin32Delegate : public KeyboardManagerWin32::WindowDelegate, public MockMessageQueue { @@ -111,6 +130,22 @@ class MockKeyboardManagerWin32Delegate map_vk_to_char == nullptr ? LayoutDefault : map_vk_to_char; } + void SetKeyState(uint32_t key, bool pressed, bool toggled_on) { + key_state_.Set(key, pressed, toggled_on); + } + + SHORT GetKeyState(int virtual_key) { + return key_state_.Get(virtual_key); + } + + void PushBackMessage(const flutter::testing::Win32Message* message) { + PushBack(message); + } + + LRESULT DispatchFrontMessage() { + return DispatchFront(); + } + protected: BOOL Win32PeekMessage(LPMSG lpMsg, UINT wMsgFilterMin, @@ -148,23 +183,7 @@ class MockKeyboardManagerWin32Delegate WindowBindingHandlerDelegate* view_; std::unique_ptr keyboard_manager_; MapVkToCharHandler map_vk_to_char_; -}; - -class TestKeystate { - public: - void Set(uint32_t virtual_key, bool pressed, bool toggled_on = false) { - state_[virtual_key] = (pressed ? kStateMaskPressed : 0) | - (toggled_on ? kStateMaskToggled : 0); - } - - SHORT Get(uint32_t virtual_key) { return state_[virtual_key]; } - - KeyboardKeyEmbedderHandler::GetKeyStateHandler Getter() { - return [this](uint32_t virtual_key) { return Get(virtual_key); }; - } - - private: - std::map state_; + TestKeystate key_state_; }; // A FlutterWindowsView that overrides the RegisterKeyboardHandlers function @@ -173,19 +192,18 @@ class TestFlutterWindowsView : public FlutterWindowsView { public: typedef std::function U16StringHandler; - TestFlutterWindowsView(U16StringHandler on_text) + TestFlutterWindowsView( + U16StringHandler on_text, + KeyboardKeyEmbedderHandler::GetKeyStateHandler get_keyboard_state) // The WindowBindingHandler is used for window size and such, and doesn't // affect keyboard. : FlutterWindowsView( std::make_unique<::testing::NiceMock>()), + get_keyboard_state_(std::move(get_keyboard_state)), on_text_(std::move(on_text)) {} void OnText(const std::u16string& text) override { on_text_(text); } - void SetKeyState(uint32_t key, bool pressed, bool toggled_on) { - key_state_.Set(key, pressed, toggled_on); - } - void HandleMessage(const char* channel, const char* method, const char* args) { @@ -220,13 +238,17 @@ class TestFlutterWindowsView : public FlutterWindowsView { std::unique_ptr CreateKeyboardKeyHandler( BinaryMessenger* messenger, KeyboardKeyEmbedderHandler::GetKeyStateHandler get_key_state) override { - return FlutterWindowsView::CreateKeyboardKeyHandler(messenger, - key_state_.Getter()); + assert(get_keyboard_state_); + return FlutterWindowsView::CreateKeyboardKeyHandler( + messenger, + [this](int virtual_key) { + return get_keyboard_state_(virtual_key); + }); } private: U16StringHandler on_text_; - TestKeystate key_state_; + KeyboardKeyEmbedderHandler::GetKeyStateHandler get_keyboard_state_; }; typedef enum { @@ -261,6 +283,26 @@ class KeyboardTester { using ResponseHandler = std::function; + struct KeyboardChange { + KeyboardChange(Win32Message message) : type(kMessage) { + content.message = message; + } + + KeyboardChange(KeyboardStateChange change) : type(kStateChange) { + content.state_change = change; + } + + enum Type { + kMessage, + kStateChange, + } type; + + union { + Win32Message message; + KeyboardStateChange state_change; + } content; + }; + explicit KeyboardTester() : callback_handler_(RespondValue(false)) { view_ = std::make_unique( [](const std::u16string& text) { @@ -268,6 +310,12 @@ class KeyboardTester { .type = kKeyCallOnText, .text = text, }); + }, + [this](int virtual_key) -> SHORT { + if (!window_) { + return 0; + } + return window_->GetKeyState(virtual_key); }); view_->SetEngine(GetTestEngine( [&callback_handler = callback_handler_]( @@ -287,11 +335,13 @@ class KeyboardTester { } TestFlutterWindowsView& GetView() { return *view_; } + MockKeyboardManagerWin32Delegate& GetWindow() { return *window_; } void SetKeyState(uint32_t key, bool pressed, bool toggled_on) { - view_->SetKeyState(key, pressed, toggled_on); + window_->SetKeyState(key, pressed, toggled_on); } + // Set all events to be handled (true) or unhandled (false). void Responding(bool response) { callback_handler_ = RespondValue(response); } // Manually handle event callback of the onKeyData embedder API. @@ -308,15 +358,42 @@ class KeyboardTester { void SetLayout(MapVkToCharHandler layout) { window_->SetLayout(layout); } void InjectMessages(int count, Win32Message message1, ...) { - Win32Message messages[count]; - messages[0] = message1; + std::vector messages; + messages.push_back(message1); va_list args; va_start(args, message1); for (int i = 1; i < count; i += 1) { - messages[i] = va_arg(args, Win32Message); + messages.push_back(va_arg(args, Win32Message)); } va_end(args); - window_->InjectMessageList(count, messages); + InjectKeyboardChanges(messages); + } + + void InjectKeyboardChanges(std::vector changes) { + for (const KeyboardChange& change : changes) { + switch (change.type) { + case KeyboardChange::kMessage: + window_->PushBackMessage(&change.content.message); + break; + default: + break; + } + } + for (const KeyboardChange& change : changes) { + switch (change.type) { + case KeyboardChange::kMessage: + window_->DispatchFrontMessage(); + break; + case KeyboardChange::kStateChange: { + const KeyboardStateChange& state_change = + change.content.state_change; + SetKeyState(state_change.key, state_change.pressed, state_change.toggled_on); + break; + } + default: + assert(false); + } + } } private: diff --git a/shell/platform/windows/testing/test_keyboard.cc b/shell/platform/windows/testing/test_keyboard.cc index 6b2030afb4a4c..393614b229c82 100644 --- a/shell/platform/windows/testing/test_keyboard.cc +++ b/shell/platform/windows/testing/test_keyboard.cc @@ -191,25 +191,25 @@ void MockEmbedderApiForKeyboard( modifier.embedder_api().Shutdown = [](auto engine) { return kSuccess; }; } -void MockMessageQueue::InjectMessageList(int count, - const Win32Message* messages) { - for (int i = 0; i < count; i += 1) { - _pending_messages.push_back(messages[i]); - } - while (!_pending_messages.empty()) { - Win32Message message = _pending_messages.front(); - _pending_messages.pop_front(); - _sent_messages.push_back(message); - LRESULT result = - Win32SendMessage(message.message, message.wParam, message.lParam); - if (message.expected_result != kWmResultDontCheck) { - EXPECT_EQ(result, message.expected_result) - << " This is the " << _sent_messages.size() - << ordinal(_sent_messages.size()) << " event, with\n " << std::hex - << "Message 0x" << message.message << " LParam 0x" << message.lParam - << " WParam 0x" << message.wParam; - } +void MockMessageQueue::PushBack(const Win32Message* message) { + _pending_messages.push_back(*message); +} + +LRESULT MockMessageQueue::DispatchFront() { + assert(!_pending_messages.empty()); + Win32Message message = _pending_messages.front(); + _pending_messages.pop_front(); + _sent_messages.push_back(message); + LRESULT result = + Win32SendMessage(message.message, message.wParam, message.lParam); + if (message.expected_result != kWmResultDontCheck) { + EXPECT_EQ(result, message.expected_result) + << " This is the " << _sent_messages.size() + << ordinal(_sent_messages.size()) << " event, with\n " << std::hex + << "Message 0x" << message.message << " LParam 0x" << message.lParam + << " WParam 0x" << message.wParam; } + return result; } BOOL MockMessageQueue::Win32PeekMessage(LPMSG lpMsg, diff --git a/shell/platform/windows/testing/test_keyboard.h b/shell/platform/windows/testing/test_keyboard.h index 868b9f1ba8212..8eddff6bfcd2a 100644 --- a/shell/platform/windows/testing/test_keyboard.h +++ b/shell/platform/windows/testing/test_keyboard.h @@ -110,10 +110,14 @@ void MockEmbedderApiForKeyboard( // Subclasses must implement |Win32SendMessage| for how dispatched messages are // processed. class MockMessageQueue { - public: - // Push a list of messages to the message queue, then dispatch - // them with |Win32SendMessage| one by one. - void InjectMessageList(int count, const Win32Message* messages); + protected: + // Push a message to the message queue without dispatching it. + void PushBack(const Win32Message* message); + + // Dispatch the first message of the message queue and return its result. + // + // This method asserts that the queue is not empty. + LRESULT DispatchFront(); // Peak the next message in the message queue. // @@ -123,7 +127,7 @@ class MockMessageQueue { UINT wMsgFilterMax, UINT wRemoveMsg); - protected: + // Simulate dispatching a message to the system. virtual LRESULT Win32SendMessage(UINT const message, WPARAM const wparam, LPARAM const lparam) = 0; From ea5413628e7c5bfc258420927125d5c38225b86a Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 7 Feb 2022 04:49:04 -0800 Subject: [PATCH 02/22] KeyStateChange --- shell/platform/windows/keyboard_win32_unittests.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/shell/platform/windows/keyboard_win32_unittests.cc b/shell/platform/windows/keyboard_win32_unittests.cc index cd11d1f9c5b03..252f61a879d5b 100644 --- a/shell/platform/windows/keyboard_win32_unittests.cc +++ b/shell/platform/windows/keyboard_win32_unittests.cc @@ -81,7 +81,7 @@ class TestKeyboardManagerWin32 : public KeyboardManagerWin32 { bool during_redispatch_ = false; }; -struct KeyboardStateChange { +struct KeyStateChange { uint32_t key; bool pressed; bool toggled_on; @@ -288,7 +288,7 @@ class KeyboardTester { content.message = message; } - KeyboardChange(KeyboardStateChange change) : type(kStateChange) { + KeyboardChange(KeyStateChange change) : type(kStateChange) { content.state_change = change; } @@ -299,7 +299,7 @@ class KeyboardTester { union { Win32Message message; - KeyboardStateChange state_change; + KeyStateChange state_change; } content; }; @@ -385,7 +385,7 @@ class KeyboardTester { window_->DispatchFrontMessage(); break; case KeyboardChange::kStateChange: { - const KeyboardStateChange& state_change = + const KeyStateChange& state_change = change.content.state_change; SetKeyState(state_change.key, state_change.pressed, state_change.toggled_on); break; From 782a8c72f7bbc1d5f9544cb9f3ce9076e6fa96c7 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 7 Feb 2022 04:50:05 -0800 Subject: [PATCH 03/22] Format --- .../windows/keyboard_win32_unittests.cc | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/shell/platform/windows/keyboard_win32_unittests.cc b/shell/platform/windows/keyboard_win32_unittests.cc index 252f61a879d5b..30d67503b2b03 100644 --- a/shell/platform/windows/keyboard_win32_unittests.cc +++ b/shell/platform/windows/keyboard_win32_unittests.cc @@ -134,17 +134,13 @@ class MockKeyboardManagerWin32Delegate key_state_.Set(key, pressed, toggled_on); } - SHORT GetKeyState(int virtual_key) { - return key_state_.Get(virtual_key); - } + SHORT GetKeyState(int virtual_key) { return key_state_.Get(virtual_key); } void PushBackMessage(const flutter::testing::Win32Message* message) { PushBack(message); } - LRESULT DispatchFrontMessage() { - return DispatchFront(); - } + LRESULT DispatchFrontMessage() { return DispatchFront(); } protected: BOOL Win32PeekMessage(LPMSG lpMsg, @@ -241,9 +237,7 @@ class TestFlutterWindowsView : public FlutterWindowsView { assert(get_keyboard_state_); return FlutterWindowsView::CreateKeyboardKeyHandler( messenger, - [this](int virtual_key) { - return get_keyboard_state_(virtual_key); - }); + [this](int virtual_key) { return get_keyboard_state_(virtual_key); }); } private: @@ -385,9 +379,9 @@ class KeyboardTester { window_->DispatchFrontMessage(); break; case KeyboardChange::kStateChange: { - const KeyStateChange& state_change = - change.content.state_change; - SetKeyState(state_change.key, state_change.pressed, state_change.toggled_on); + const KeyStateChange& state_change = change.content.state_change; + SetKeyState(state_change.key, state_change.pressed, + state_change.toggled_on); break; } default: From 2aea85e076d58e65aec591700ae89546af20c2c4 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 7 Feb 2022 04:56:28 -0800 Subject: [PATCH 04/22] InjectKeyboardChanges --- .../windows/keyboard_win32_unittests.cc | 535 ++++++++---------- 1 file changed, 245 insertions(+), 290 deletions(-) diff --git a/shell/platform/windows/keyboard_win32_unittests.cc b/shell/platform/windows/keyboard_win32_unittests.cc index 30d67503b2b03..f24234fd48e9d 100644 --- a/shell/platform/windows/keyboard_win32_unittests.cc +++ b/shell/platform/windows/keyboard_win32_unittests.cc @@ -87,6 +87,28 @@ struct KeyStateChange { bool toggled_on; }; +struct KeyboardChange { + // The constructors are intentionally for implicit conversion. + + KeyboardChange(Win32Message message) : type(kMessage) { + content.message = message; + } + + KeyboardChange(KeyStateChange change) : type(kStateChange) { + content.state_change = change; + } + + enum Type { + kMessage, + kStateChange, + } type; + + union { + Win32Message message; + KeyStateChange state_change; + } content; +}; + class TestKeystate { public: void Set(uint32_t virtual_key, bool pressed, bool toggled_on = false) { @@ -277,26 +299,6 @@ class KeyboardTester { using ResponseHandler = std::function; - struct KeyboardChange { - KeyboardChange(Win32Message message) : type(kMessage) { - content.message = message; - } - - KeyboardChange(KeyStateChange change) : type(kStateChange) { - content.state_change = change; - } - - enum Type { - kMessage, - kStateChange, - } type; - - union { - Win32Message message; - KeyStateChange state_change; - } content; - }; - explicit KeyboardTester() : callback_handler_(RespondValue(false)) { view_ = std::make_unique( [](const std::u16string& text) { @@ -306,10 +308,9 @@ class KeyboardTester { }); }, [this](int virtual_key) -> SHORT { - if (!window_) { - return 0; - } - return window_->GetKeyState(virtual_key); + // `window_` is not initialized yet when this callback is first + // called. + return window_ ? window_->GetKeyState(virtual_key) : 0; }); view_->SetEngine(GetTestEngine( [&callback_handler = callback_handler_]( @@ -351,18 +352,6 @@ class KeyboardTester { void SetLayout(MapVkToCharHandler layout) { window_->SetLayout(layout); } - void InjectMessages(int count, Win32Message message1, ...) { - std::vector messages; - messages.push_back(message1); - va_list args; - va_start(args, message1); - for (int i = 1; i < count; i += 1) { - messages.push_back(va_arg(args, Win32Message)); - } - va_end(args); - InjectKeyboardChanges(messages); - } - void InjectKeyboardChanges(std::vector changes) { for (const KeyboardChange& change : changes) { switch (change.type) { @@ -494,12 +483,11 @@ TEST(KeyboardTest, LowerCaseAHandled) { // US Keyboard layout // Press A - tester.InjectMessages( - 2, + tester.InjectKeyboardChanges(std::vector{ WmKeyDownInfo{kVirtualKeyA, kScanCodeKeyA, kNotExtended, kWasUp}.Build( kWmResultZero), WmCharInfo{'a', kScanCodeKeyA, kNotExtended, kWasUp}.Build( - kWmResultZero)); + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, kPhysicalKeyA, @@ -507,9 +495,9 @@ TEST(KeyboardTest, LowerCaseAHandled) { clear_key_calls(); // Release A - tester.InjectMessages( - 1, WmKeyUpInfo{kVirtualKeyA, kScanCodeKeyA, kNotExtended}.Build( - kWmResultZero)); + tester.InjectKeyboardChanges(std::vector{ + WmKeyUpInfo{kVirtualKeyA, kScanCodeKeyA, kNotExtended}.Build( + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalKeyA, @@ -524,12 +512,11 @@ TEST(KeyboardTest, LowerCaseAUnhandled) { // US Keyboard layout // Press A - tester.InjectMessages( - 2, + tester.InjectKeyboardChanges(std::vector{ WmKeyDownInfo{kVirtualKeyA, kScanCodeKeyA, kNotExtended, kWasUp}.Build( kWmResultZero), WmCharInfo{'a', kScanCodeKeyA, kNotExtended, kWasUp}.Build( - kWmResultZero)); + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 2); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, kPhysicalKeyA, @@ -538,9 +525,9 @@ TEST(KeyboardTest, LowerCaseAUnhandled) { clear_key_calls(); // Release A - tester.InjectMessages( - 1, WmKeyUpInfo{kVirtualKeyA, kScanCodeKeyA, kNotExtended}.Build( - kWmResultZero)); + tester.InjectKeyboardChanges(std::vector{ + WmKeyUpInfo{kVirtualKeyA, kScanCodeKeyA, kNotExtended}.Build( + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalKeyA, @@ -555,9 +542,9 @@ TEST(KeyboardTest, ArrowLeftHandled) { // US Keyboard layout // Press ArrowLeft - tester.InjectMessages( - 1, WmKeyDownInfo{VK_LEFT, kScanCodeArrowLeft, kExtended, kWasUp}.Build( - kWmResultZero)); + tester.InjectKeyboardChanges(std::vector{ + WmKeyDownInfo{VK_LEFT, kScanCodeArrowLeft, kExtended, kWasUp}.Build( + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, @@ -566,9 +553,9 @@ TEST(KeyboardTest, ArrowLeftHandled) { clear_key_calls(); // Release ArrowLeft - tester.InjectMessages( - 1, - WmKeyUpInfo{VK_LEFT, kScanCodeArrowLeft, kExtended}.Build(kWmResultZero)); + tester.InjectKeyboardChanges(std::vector{ + WmKeyUpInfo{VK_LEFT, kScanCodeArrowLeft, kExtended}.Build( + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalArrowLeft, @@ -583,9 +570,9 @@ TEST(KeyboardTest, ArrowLeftUnhandled) { // US Keyboard layout // Press ArrowLeft - tester.InjectMessages( - 1, WmKeyDownInfo{VK_LEFT, kScanCodeArrowLeft, kExtended, kWasUp}.Build( - kWmResultZero)); + tester.InjectKeyboardChanges(std::vector{ + WmKeyDownInfo{VK_LEFT, kScanCodeArrowLeft, kExtended, kWasUp}.Build( + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, @@ -594,9 +581,9 @@ TEST(KeyboardTest, ArrowLeftUnhandled) { clear_key_calls(); // Release ArrowLeft - tester.InjectMessages( - 1, - WmKeyUpInfo{VK_LEFT, kScanCodeArrowLeft, kExtended}.Build(kWmResultZero)); + tester.InjectKeyboardChanges(std::vector{ + WmKeyUpInfo{VK_LEFT, kScanCodeArrowLeft, kExtended}.Build( + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalArrowLeft, @@ -612,10 +599,9 @@ TEST(KeyboardTest, ShiftLeftUnhandled) { // Press ShiftLeft tester.SetKeyState(VK_LSHIFT, true, false); - tester.InjectMessages( - 1, + tester.InjectKeyboardChanges(std::vector{ WmKeyDownInfo{VK_SHIFT, kScanCodeShiftLeft, kNotExtended, kWasUp}.Build( - kWmResultZero)); + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, @@ -625,9 +611,9 @@ TEST(KeyboardTest, ShiftLeftUnhandled) { // Release ShiftLeft tester.SetKeyState(VK_LSHIFT, false, true); - tester.InjectMessages( - 1, WmKeyUpInfo{VK_SHIFT, kScanCodeShiftLeft, kNotExtended}.Build( - kWmResultZero)); + tester.InjectKeyboardChanges(std::vector{ + WmKeyUpInfo{VK_SHIFT, kScanCodeShiftLeft, kNotExtended}.Build( + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalShiftLeft, @@ -643,10 +629,9 @@ TEST(KeyboardTest, ShiftRightUnhandled) { // Press ShiftRight tester.SetKeyState(VK_RSHIFT, true, false); - tester.InjectMessages( - 1, + tester.InjectKeyboardChanges(std::vector{ WmKeyDownInfo{VK_SHIFT, kScanCodeShiftRight, kNotExtended, kWasUp}.Build( - kWmResultZero)); + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, @@ -656,9 +641,9 @@ TEST(KeyboardTest, ShiftRightUnhandled) { // Release ShiftRight tester.SetKeyState(VK_RSHIFT, false, true); - tester.InjectMessages( - 1, WmKeyUpInfo{VK_SHIFT, kScanCodeShiftRight, kNotExtended}.Build( - kWmResultZero)); + tester.InjectKeyboardChanges(std::vector{ + WmKeyUpInfo{VK_SHIFT, kScanCodeShiftRight, kNotExtended}.Build( + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, @@ -675,10 +660,9 @@ TEST(KeyboardTest, CtrlLeftUnhandled) { // Press CtrlLeft tester.SetKeyState(VK_LCONTROL, true, false); - tester.InjectMessages( - 1, + tester.InjectKeyboardChanges(std::vector{ WmKeyDownInfo{VK_CONTROL, kScanCodeControl, kNotExtended, kWasUp}.Build( - kWmResultZero)); + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, @@ -688,9 +672,9 @@ TEST(KeyboardTest, CtrlLeftUnhandled) { // Release CtrlLeft tester.SetKeyState(VK_LCONTROL, false, true); - tester.InjectMessages( - 1, WmKeyUpInfo{VK_SHIFT, kScanCodeControl, kNotExtended}.Build( - kWmResultZero)); + tester.InjectKeyboardChanges(std::vector{ + WmKeyUpInfo{VK_SHIFT, kScanCodeControl, kNotExtended}.Build( + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, @@ -707,9 +691,9 @@ TEST(KeyboardTest, CtrlRightUnhandled) { // Press CtrlRight tester.SetKeyState(VK_RCONTROL, true, false); - tester.InjectMessages( - 1, WmKeyDownInfo{VK_CONTROL, kScanCodeControl, kExtended, kWasUp}.Build( - kWmResultZero)); + tester.InjectKeyboardChanges(std::vector{ + WmKeyDownInfo{VK_CONTROL, kScanCodeControl, kExtended, kWasUp}.Build( + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, @@ -719,9 +703,9 @@ TEST(KeyboardTest, CtrlRightUnhandled) { // Release CtrlRight tester.SetKeyState(VK_RCONTROL, false, true); - tester.InjectMessages( - 1, WmKeyUpInfo{VK_CONTROL, kScanCodeControl, kExtended}.Build( - kWmResultZero)); + tester.InjectKeyboardChanges(std::vector{ + WmKeyUpInfo{VK_CONTROL, kScanCodeControl, kExtended}.Build( + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, @@ -738,9 +722,9 @@ TEST(KeyboardTest, AltLeftUnhandled) { // Press AltLeft. AltLeft is a SysKeyDown event. tester.SetKeyState(VK_LMENU, true, false); - tester.InjectMessages( - 1, WmSysKeyDownInfo{VK_MENU, kScanCodeAlt, kNotExtended, kWasUp}.Build( - kWmResultDefault)); // Always pass to the default WndProc. + tester.InjectKeyboardChanges(std::vector{ + WmSysKeyDownInfo{VK_MENU, kScanCodeAlt, kNotExtended, kWasUp}.Build( + kWmResultDefault)}); // Always pass to the default WndProc. EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, kPhysicalAltLeft, @@ -749,9 +733,9 @@ TEST(KeyboardTest, AltLeftUnhandled) { // Release AltLeft. AltLeft is a SysKeyUp event. tester.SetKeyState(VK_LMENU, false, true); - tester.InjectMessages( - 1, WmSysKeyUpInfo{VK_MENU, kScanCodeAlt, kNotExtended}.Build( - kWmResultDefault)); // Always pass to the default WndProc. + tester.InjectKeyboardChanges(std::vector{ + WmSysKeyUpInfo{VK_MENU, kScanCodeAlt, kNotExtended}.Build( + kWmResultDefault)}); // Always pass to the default WndProc. EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalAltLeft, @@ -767,9 +751,9 @@ TEST(KeyboardTest, AltRightUnhandled) { // Press AltRight. AltRight is a SysKeyDown event. tester.SetKeyState(VK_RMENU, true, false); - tester.InjectMessages( - 1, WmSysKeyDownInfo{VK_MENU, kScanCodeAlt, kExtended, kWasUp}.Build( - kWmResultDefault)); // Always pass to the default WndProc. + tester.InjectKeyboardChanges(std::vector{ + WmSysKeyDownInfo{VK_MENU, kScanCodeAlt, kExtended, kWasUp}.Build( + kWmResultDefault)}); // Always pass to the default WndProc. EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, @@ -779,9 +763,9 @@ TEST(KeyboardTest, AltRightUnhandled) { // Release AltRight. AltRight is a SysKeyUp event. tester.SetKeyState(VK_RMENU, false, true); - tester.InjectMessages( - 1, WmSysKeyUpInfo{VK_MENU, kScanCodeAlt, kExtended}.Build( - kWmResultDefault)); // Always pass to the default WndProc. + tester.InjectKeyboardChanges(std::vector{ + WmSysKeyUpInfo{VK_MENU, kScanCodeAlt, kExtended}.Build( + kWmResultDefault)}); // Always pass to the default WndProc. EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalAltRight, @@ -797,9 +781,9 @@ TEST(KeyboardTest, MetaLeftUnhandled) { // Press MetaLeft tester.SetKeyState(VK_LWIN, true, false); - tester.InjectMessages( - 1, WmKeyDownInfo{VK_LWIN, kScanCodeMetaLeft, kExtended, kWasUp}.Build( - kWmResultZero)); + tester.InjectKeyboardChanges(std::vector{ + WmKeyDownInfo{VK_LWIN, kScanCodeMetaLeft, kExtended, kWasUp}.Build( + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, @@ -809,9 +793,8 @@ TEST(KeyboardTest, MetaLeftUnhandled) { // Release MetaLeft tester.SetKeyState(VK_LWIN, false, true); - tester.InjectMessages( - 1, - WmKeyUpInfo{VK_LWIN, kScanCodeMetaLeft, kExtended}.Build(kWmResultZero)); + tester.InjectKeyboardChanges(std::vector{ + WmKeyUpInfo{VK_LWIN, kScanCodeMetaLeft, kExtended}.Build(kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalMetaLeft, @@ -827,9 +810,9 @@ TEST(KeyboardTest, MetaRightUnhandled) { // Press MetaRight tester.SetKeyState(VK_RWIN, true, false); - tester.InjectMessages( - 1, WmKeyDownInfo{VK_RWIN, kScanCodeMetaRight, kExtended, kWasUp}.Build( - kWmResultZero)); + tester.InjectKeyboardChanges(std::vector{ + WmKeyDownInfo{VK_RWIN, kScanCodeMetaRight, kExtended, kWasUp}.Build( + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, @@ -839,9 +822,9 @@ TEST(KeyboardTest, MetaRightUnhandled) { // Release MetaRight tester.SetKeyState(VK_RWIN, false, true); - tester.InjectMessages( - 1, - WmKeyUpInfo{VK_RWIN, kScanCodeMetaRight, kExtended}.Build(kWmResultZero)); + tester.InjectKeyboardChanges(std::vector{ + WmKeyUpInfo{VK_RWIN, kScanCodeMetaRight, kExtended}.Build( + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalMetaRight, @@ -859,10 +842,9 @@ TEST(KeyboardTest, ShiftLeftKeyA) { // Press ShiftLeft tester.SetKeyState(VK_LSHIFT, true, true); - tester.InjectMessages( - 1, + tester.InjectKeyboardChanges(std::vector{ WmKeyDownInfo{VK_SHIFT, kScanCodeShiftLeft, kNotExtended, kWasUp}.Build( - kWmResultZero)); + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, @@ -871,12 +853,11 @@ TEST(KeyboardTest, ShiftLeftKeyA) { clear_key_calls(); // Press A - tester.InjectMessages( - 2, + tester.InjectKeyboardChanges(std::vector{ WmKeyDownInfo{kVirtualKeyA, kScanCodeKeyA, kNotExtended, kWasUp}.Build( kWmResultZero), WmCharInfo{'A', kScanCodeKeyA, kNotExtended, kWasUp}.Build( - kWmResultZero)); + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 2); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, kPhysicalKeyA, @@ -886,9 +867,9 @@ TEST(KeyboardTest, ShiftLeftKeyA) { // Release ShiftLeft tester.SetKeyState(VK_LSHIFT, false, true); - tester.InjectMessages( - 1, WmKeyUpInfo{VK_SHIFT, kScanCodeShiftLeft, kNotExtended}.Build( - kWmResultZero)); + tester.InjectKeyboardChanges(std::vector{ + WmKeyUpInfo{VK_SHIFT, kScanCodeShiftLeft, kNotExtended}.Build( + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalShiftLeft, @@ -896,9 +877,9 @@ TEST(KeyboardTest, ShiftLeftKeyA) { clear_key_calls(); // Release A - tester.InjectMessages( - 1, WmKeyUpInfo{kVirtualKeyA, kScanCodeKeyA, kNotExtended}.Build( - kWmResultZero)); + tester.InjectKeyboardChanges(std::vector{ + WmKeyUpInfo{kVirtualKeyA, kScanCodeKeyA, kNotExtended}.Build( + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalKeyA, @@ -916,10 +897,9 @@ TEST(KeyboardTest, CtrlLeftKeyA) { // Press ControlLeft tester.SetKeyState(VK_LCONTROL, true, true); - tester.InjectMessages( - 1, + tester.InjectKeyboardChanges(std::vector{ WmKeyDownInfo{VK_CONTROL, kScanCodeControl, kNotExtended, kWasUp}.Build( - kWmResultZero)); + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, @@ -928,12 +908,11 @@ TEST(KeyboardTest, CtrlLeftKeyA) { clear_key_calls(); // Press A - tester.InjectMessages( - 2, + tester.InjectKeyboardChanges(std::vector{ WmKeyDownInfo{kVirtualKeyA, kScanCodeKeyA, kNotExtended, kWasUp}.Build( kWmResultZero), WmCharInfo{0x01, kScanCodeKeyA, kNotExtended, kWasUp}.Build( - kWmResultZero)); + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, kPhysicalKeyA, @@ -941,9 +920,9 @@ TEST(KeyboardTest, CtrlLeftKeyA) { clear_key_calls(); // Release A - tester.InjectMessages( - 1, WmKeyUpInfo{kVirtualKeyA, kScanCodeKeyA, kNotExtended}.Build( - kWmResultZero)); + tester.InjectKeyboardChanges(std::vector{ + WmKeyUpInfo{kVirtualKeyA, kScanCodeKeyA, kNotExtended}.Build( + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalKeyA, @@ -952,9 +931,9 @@ TEST(KeyboardTest, CtrlLeftKeyA) { // Release ControlLeft tester.SetKeyState(VK_LCONTROL, false, true); - tester.InjectMessages( - 1, WmKeyUpInfo{VK_CONTROL, kScanCodeControl, kNotExtended}.Build( - kWmResultZero)); + tester.InjectKeyboardChanges(std::vector{ + WmKeyUpInfo{VK_CONTROL, kScanCodeControl, kNotExtended}.Build( + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, @@ -972,10 +951,9 @@ TEST(KeyboardTest, CtrlLeftDigit1) { // Press ControlLeft tester.SetKeyState(VK_LCONTROL, true, true); - tester.InjectMessages( - 1, + tester.InjectKeyboardChanges(std::vector{ WmKeyDownInfo{VK_CONTROL, kScanCodeControl, kNotExtended, kWasUp}.Build( - kWmResultZero)); + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, @@ -984,9 +962,9 @@ TEST(KeyboardTest, CtrlLeftDigit1) { clear_key_calls(); // Press 1 - tester.InjectMessages( - 1, WmKeyDownInfo{kVirtualDigit1, kScanCodeDigit1, kNotExtended, kWasUp} - .Build(kWmResultZero)); + tester.InjectKeyboardChanges(std::vector{ + WmKeyDownInfo{kVirtualDigit1, kScanCodeDigit1, kNotExtended, kWasUp} + .Build(kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, kPhysicalDigit1, @@ -994,9 +972,9 @@ TEST(KeyboardTest, CtrlLeftDigit1) { clear_key_calls(); // Release 1 - tester.InjectMessages( - 1, WmKeyUpInfo{kVirtualDigit1, kScanCodeDigit1, kNotExtended}.Build( - kWmResultZero)); + tester.InjectKeyboardChanges(std::vector{ + WmKeyUpInfo{kVirtualDigit1, kScanCodeDigit1, kNotExtended}.Build( + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalDigit1, @@ -1005,9 +983,9 @@ TEST(KeyboardTest, CtrlLeftDigit1) { // Release ControlLeft tester.SetKeyState(VK_LCONTROL, false, true); - tester.InjectMessages( - 1, WmKeyUpInfo{VK_CONTROL, kScanCodeControl, kNotExtended}.Build( - kWmResultZero)); + tester.InjectKeyboardChanges(std::vector{ + WmKeyUpInfo{VK_CONTROL, kScanCodeControl, kNotExtended}.Build( + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, @@ -1025,12 +1003,11 @@ TEST(KeyboardTest, Digit1OnFrenchLayout) { tester.SetLayout(LayoutFrench); // Press 1 - tester.InjectMessages( - 2, + tester.InjectKeyboardChanges(std::vector{ WmKeyDownInfo{kVirtualDigit1, kScanCodeDigit1, kNotExtended, kWasUp} .Build(kWmResultZero), WmCharInfo{'&', kScanCodeDigit1, kNotExtended, kWasUp}.Build( - kWmResultZero)); + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 2); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, kPhysicalDigit1, @@ -1039,9 +1016,9 @@ TEST(KeyboardTest, Digit1OnFrenchLayout) { clear_key_calls(); // Release 1 - tester.InjectMessages( - 1, WmKeyUpInfo{kVirtualDigit1, kScanCodeDigit1, kNotExtended}.Build( - kWmResultZero)); + tester.InjectKeyboardChanges(std::vector{ + WmKeyUpInfo{kVirtualDigit1, kScanCodeDigit1, kNotExtended}.Build( + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalDigit1, @@ -1058,12 +1035,11 @@ TEST(KeyboardTest, AltGrModifiedKey) { // Press AltGr, which Win32 precedes with a ContrlLeft down. tester.SetKeyState(VK_LCONTROL, true, true); - tester.InjectMessages( - 2, + tester.InjectKeyboardChanges(std::vector{ WmKeyDownInfo{VK_LCONTROL, kScanCodeControl, kNotExtended, kWasUp}.Build( kWmResultZero), WmKeyDownInfo{VK_MENU, kScanCodeAlt, kExtended, kWasUp}.Build( - kWmResultZero)); + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 2); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, @@ -1075,12 +1051,11 @@ TEST(KeyboardTest, AltGrModifiedKey) { clear_key_calls(); // Press Q - tester.InjectMessages( - 2, + tester.InjectKeyboardChanges(std::vector{ WmKeyDownInfo{kVirtualKeyQ, kScanCodeKeyQ, kNotExtended, kWasUp}.Build( kWmResultZero), WmCharInfo{'@', kScanCodeKeyQ, kNotExtended, kWasUp}.Build( - kWmResultZero)); + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 2); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, kPhysicalKeyQ, @@ -1089,22 +1064,22 @@ TEST(KeyboardTest, AltGrModifiedKey) { clear_key_calls(); // Release Q - tester.InjectMessages( - 1, WmKeyUpInfo{kVirtualKeyQ, kScanCodeKeyQ, kNotExtended}.Build( - kWmResultZero)); + tester.InjectKeyboardChanges(std::vector{ + WmKeyUpInfo{kVirtualKeyQ, kScanCodeKeyQ, kNotExtended}.Build( + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalKeyQ, kLogicalKeyQ, "", kNotSynthesized); clear_key_calls(); - // Release AltGr. Win32 doesn't dispatch ControlLeft up. Instead Flutter will - // dispatch one. The AltGr is a system key, therefore will be handled by - // Win32's default WndProc. + // Release AltGr. Win32 doesn't dispatch ControlLeft up. Instead + // Flutter will dispatch one. The AltGr is a system key, therefore + // will be handled by Win32's default WndProc. tester.SetKeyState(VK_LCONTROL, false, true); - tester.InjectMessages( - 1, - WmSysKeyUpInfo{VK_MENU, kScanCodeAlt, kExtended}.Build(kWmResultDefault)); + tester.InjectKeyboardChanges(std::vector{ + WmSysKeyUpInfo{VK_MENU, kScanCodeAlt, kExtended}.Build( + kWmResultDefault)}); EXPECT_EQ(key_calls.size(), 2); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, @@ -1134,15 +1109,14 @@ TEST(KeyboardTest, AltGrTwice) { // 1. AltGr down. - // The key down event causes a ControlLeft down and a AltRight (extended - // AltLeft) down. + // The key down event causes a ControlLeft down and a AltRight + // (extended AltLeft) down. tester.SetKeyState(VK_LCONTROL, true, true); - tester.InjectMessages( - 2, + tester.InjectKeyboardChanges(std::vector{ WmKeyDownInfo{VK_LCONTROL, kScanCodeControl, kNotExtended, kWasUp}.Build( kWmResultZero), WmKeyDownInfo{VK_MENU, kScanCodeAlt, kExtended, kWasUp}.Build( - kWmResultZero)); + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 2); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, @@ -1158,9 +1132,9 @@ TEST(KeyboardTest, AltGrTwice) { // The key up event only causes a AltRight (extended AltLeft) up. tester.SetKeyState(VK_RMENU, false, true); tester.SetKeyState(VK_LCONTROL, false, true); - tester.InjectMessages( - 1, - WmSysKeyUpInfo{VK_MENU, kScanCodeAlt, kExtended}.Build(kWmResultDefault)); + tester.InjectKeyboardChanges(std::vector{ + WmSysKeyUpInfo{VK_MENU, kScanCodeAlt, kExtended}.Build( + kWmResultDefault)}); EXPECT_EQ(key_calls.size(), 2); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalControlLeft, kLogicalControlLeft, "", @@ -1172,12 +1146,11 @@ TEST(KeyboardTest, AltGrTwice) { // 3. AltGr down (or: ControlLeft down then AltRight down.) tester.SetKeyState(VK_LCONTROL, true, false); - tester.InjectMessages( - 2, + tester.InjectKeyboardChanges(std::vector{ WmKeyDownInfo{VK_LCONTROL, kScanCodeControl, kNotExtended, kWasUp}.Build( kWmResultZero), WmKeyDownInfo{VK_MENU, kScanCodeAlt, kExtended, kWasUp}.Build( - kWmResultZero)); + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 2); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, @@ -1193,9 +1166,9 @@ TEST(KeyboardTest, AltGrTwice) { // The key up event only causes a AltRight (extended AltLeft) up. tester.SetKeyState(VK_RMENU, false, false); tester.SetKeyState(VK_LCONTROL, false, false); - tester.InjectMessages( - 1, - WmSysKeyUpInfo{VK_MENU, kScanCodeAlt, kExtended}.Build(kWmResultDefault)); + tester.InjectKeyboardChanges(std::vector{ + WmSysKeyUpInfo{VK_MENU, kScanCodeAlt, kExtended}.Build( + kWmResultDefault)}); EXPECT_EQ(key_calls.size(), 2); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalControlLeft, kLogicalControlLeft, "", @@ -1205,9 +1178,9 @@ TEST(KeyboardTest, AltGrTwice) { clear_key_calls(); // 5. For key sequence 2: a real ControlLeft up. - tester.InjectMessages( - 1, WmKeyUpInfo{VK_LCONTROL, kScanCodeControl, kNotExtended}.Build( - kWmResultZero)); + tester.InjectKeyboardChanges(std::vector{ + WmKeyUpInfo{VK_LCONTROL, kScanCodeControl, kNotExtended}.Build( + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, 0, 0, "", kNotSynthesized); @@ -1223,12 +1196,11 @@ TEST(KeyboardTest, DeadKeyThatCombines) { tester.SetLayout(LayoutFrench); // Press ^¨ (US: Left bracket) - tester.InjectMessages( - 2, + tester.InjectKeyboardChanges(std::vector{ WmKeyDownInfo{0xDD, kScanCodeBracketLeft, kNotExtended, kWasUp}.Build( kWmResultZero), WmDeadCharInfo{'^', kScanCodeBracketLeft, kNotExtended, kWasUp}.Build( - kWmResultZero)); + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, @@ -1237,9 +1209,9 @@ TEST(KeyboardTest, DeadKeyThatCombines) { clear_key_calls(); // Release ^¨ - tester.InjectMessages( - 1, WmKeyUpInfo{0xDD, kScanCodeBracketLeft, kNotExtended}.Build( - kWmResultZero)); + tester.InjectKeyboardChanges(std::vector{ + WmKeyUpInfo{0xDD, kScanCodeBracketLeft, kNotExtended}.Build( + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, @@ -1248,12 +1220,11 @@ TEST(KeyboardTest, DeadKeyThatCombines) { clear_key_calls(); // Press E - tester.InjectMessages( - 2, + tester.InjectKeyboardChanges(std::vector{ WmKeyDownInfo{kVirtualKeyE, kScanCodeKeyE, kNotExtended, kWasUp}.Build( kWmResultZero), WmCharInfo{0xEA, kScanCodeKeyE, kNotExtended, kWasUp}.Build( - kWmResultZero)); + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 2); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, kPhysicalKeyE, @@ -1262,9 +1233,9 @@ TEST(KeyboardTest, DeadKeyThatCombines) { clear_key_calls(); // Release E - tester.InjectMessages( - 1, WmKeyUpInfo{kVirtualKeyE, kScanCodeKeyE, kNotExtended}.Build( - kWmResultZero)); + tester.InjectKeyboardChanges(std::vector{ + WmKeyUpInfo{kVirtualKeyE, kScanCodeKeyE, kNotExtended}.Build( + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalKeyE, @@ -1283,10 +1254,9 @@ TEST(KeyboardTest, DeadKeyWithoutDeadMaskThatCombines) { // Press ShiftLeft tester.SetKeyState(VK_LSHIFT, true, true); - tester.InjectMessages( - 1, + tester.InjectKeyboardChanges(std::vector{ WmKeyDownInfo{VK_SHIFT, kScanCodeShiftLeft, kNotExtended, kWasUp}.Build( - kWmResultZero)); + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, @@ -1295,12 +1265,11 @@ TEST(KeyboardTest, DeadKeyWithoutDeadMaskThatCombines) { clear_key_calls(); // Press 6^ - tester.InjectMessages( - 2, + tester.InjectKeyboardChanges(std::vector{ WmKeyDownInfo{'6', kScanCodeDigit6, kNotExtended, kWasUp}.Build( kWmResultZero), WmDeadCharInfo{'^', kScanCodeDigit6, kNotExtended, kWasUp}.Build( - kWmResultZero)); + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, kPhysicalDigit6, @@ -1308,8 +1277,8 @@ TEST(KeyboardTest, DeadKeyWithoutDeadMaskThatCombines) { clear_key_calls(); // Release 6^ - tester.InjectMessages( - 1, WmKeyUpInfo{'6', kScanCodeDigit6, kNotExtended}.Build(kWmResultZero)); + tester.InjectKeyboardChanges(std::vector{ + WmKeyUpInfo{'6', kScanCodeDigit6, kNotExtended}.Build(kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalDigit6, @@ -1318,9 +1287,9 @@ TEST(KeyboardTest, DeadKeyWithoutDeadMaskThatCombines) { // Release ShiftLeft tester.SetKeyState(VK_LSHIFT, false, true); - tester.InjectMessages( - 1, WmKeyUpInfo{VK_SHIFT, kScanCodeShiftLeft, kNotExtended}.Build( - kWmResultZero)); + tester.InjectKeyboardChanges(std::vector{ + WmKeyUpInfo{VK_SHIFT, kScanCodeShiftLeft, kNotExtended}.Build( + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalShiftLeft, @@ -1328,12 +1297,11 @@ TEST(KeyboardTest, DeadKeyWithoutDeadMaskThatCombines) { clear_key_calls(); // Press E - tester.InjectMessages( - 2, + tester.InjectKeyboardChanges(std::vector{ WmKeyDownInfo{kVirtualKeyE, kScanCodeKeyE, kNotExtended, kWasUp}.Build( kWmResultZero), WmCharInfo{0xEA, kScanCodeKeyE, kNotExtended, kWasUp}.Build( - kWmResultZero)); + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 2); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, kPhysicalKeyE, @@ -1342,9 +1310,9 @@ TEST(KeyboardTest, DeadKeyWithoutDeadMaskThatCombines) { clear_key_calls(); // Release E - tester.InjectMessages( - 1, WmKeyUpInfo{kVirtualKeyE, kScanCodeKeyE, kNotExtended}.Build( - kWmResultZero)); + tester.InjectKeyboardChanges(std::vector{ + WmKeyUpInfo{kVirtualKeyE, kScanCodeKeyE, kNotExtended}.Build( + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalKeyE, @@ -1361,12 +1329,11 @@ TEST(KeyboardTest, DeadKeyThatDoesNotCombine) { tester.SetLayout(LayoutFrench); // Press ^¨ (US: Left bracket) - tester.InjectMessages( - 2, + tester.InjectKeyboardChanges(std::vector{ WmKeyDownInfo{0xDD, kScanCodeBracketLeft, kNotExtended, kWasUp}.Build( kWmResultZero), WmDeadCharInfo{'^', kScanCodeBracketLeft, kNotExtended, kWasUp}.Build( - kWmResultZero)); + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, @@ -1375,9 +1342,9 @@ TEST(KeyboardTest, DeadKeyThatDoesNotCombine) { clear_key_calls(); // Release ^¨ - tester.InjectMessages( - 1, WmKeyUpInfo{0xDD, kScanCodeBracketLeft, kNotExtended}.Build( - kWmResultZero)); + tester.InjectKeyboardChanges(std::vector{ + WmKeyUpInfo{0xDD, kScanCodeBracketLeft, kNotExtended}.Build( + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, @@ -1386,14 +1353,13 @@ TEST(KeyboardTest, DeadKeyThatDoesNotCombine) { clear_key_calls(); // Press 1 - tester.InjectMessages( - 3, + tester.InjectKeyboardChanges(std::vector{ WmKeyDownInfo{kVirtualDigit1, kScanCodeDigit1, kNotExtended, kWasUp} .Build(kWmResultZero), WmCharInfo{'^', kScanCodeDigit1, kNotExtended, kWasUp}.Build( kWmResultZero), WmCharInfo{'&', kScanCodeDigit1, kNotExtended, kWasUp}.Build( - kWmResultZero)); + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 3); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, kPhysicalDigit1, @@ -1403,9 +1369,9 @@ TEST(KeyboardTest, DeadKeyThatDoesNotCombine) { clear_key_calls(); // Release 1 - tester.InjectMessages( - 1, WmKeyUpInfo{kVirtualDigit1, kScanCodeDigit1, kNotExtended}.Build( - kWmResultZero)); + tester.InjectKeyboardChanges(std::vector{ + WmKeyUpInfo{kVirtualDigit1, kScanCodeDigit1, kNotExtended}.Build( + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalDigit1, @@ -1423,12 +1389,11 @@ TEST(KeyboardTest, DeadKeyTwiceThenLetter) { // US INTL layout. // Press ` - tester.InjectMessages( - 2, + tester.InjectKeyboardChanges(std::vector{ WmKeyDownInfo{0xC0, kScanCodeBackquote, kNotExtended, kWasUp}.Build( kWmResultZero), WmDeadCharInfo{'`', kScanCodeBackquote, kNotExtended, kWasUp}.Build( - kWmResultZero)); + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, @@ -1437,9 +1402,9 @@ TEST(KeyboardTest, DeadKeyTwiceThenLetter) { clear_key_calls(); // Release ` - tester.InjectMessages( - 1, - WmKeyUpInfo{0xC0, kScanCodeBackquote, kNotExtended}.Build(kWmResultZero)); + tester.InjectKeyboardChanges(std::vector{ + WmKeyUpInfo{0xC0, kScanCodeBackquote, kNotExtended}.Build( + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalBackquote, @@ -1456,15 +1421,14 @@ TEST(KeyboardTest, DeadKeyTwiceThenLetter) { recorded_callbacks.push_back(callback); }); - tester.InjectMessages( - 3, + tester.InjectKeyboardChanges(std::vector{ WmKeyDownInfo{0xC0, kScanCodeBackquote, kNotExtended, kWasUp}.Build( kWmResultZero), WmCharInfo{'`', kScanCodeBackquote, kNotExtended, kWasUp, kBeingReleased, kNoContext, 1, /*bit25*/ true} .Build(kWmResultZero), WmCharInfo{'`', kScanCodeBackquote, kNotExtended, kWasUp}.Build( - kWmResultZero)); + kWmResultZero)}); EXPECT_EQ(recorded_callbacks.size(), 1); EXPECT_EQ(key_calls.size(), 1); @@ -1482,9 +1446,9 @@ TEST(KeyboardTest, DeadKeyTwiceThenLetter) { tester.Responding(false); // Release ` - tester.InjectMessages( - 1, - WmKeyUpInfo{0xC0, kScanCodeBackquote, kNotExtended}.Build(kWmResultZero)); + tester.InjectKeyboardChanges(std::vector{ + WmKeyUpInfo{0xC0, kScanCodeBackquote, kNotExtended}.Build( + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalBackquote, @@ -1497,18 +1461,18 @@ TEST(KeyboardTest, MultibyteCharacter) { KeyboardTester tester; tester.Responding(false); - // Gothic Keyboard layout. (We need a layout that yields non-BMP characters - // without IME, which is actually very rare.) + // Gothic Keyboard layout. (We need a layout that yields non-BMP + // characters without IME, which is actually very rare.) - // Press key W of a US keyboard, which should yield character '𐍅'. - tester.InjectMessages( - 3, + // Press key W of a US keyboard, which should yield character + // '𐍅'. + tester.InjectKeyboardChanges(std::vector{ WmKeyDownInfo{kVirtualKeyW, kScanCodeKeyW, kNotExtended, kWasUp}.Build( kWmResultZero), WmCharInfo{0xd800, kScanCodeKeyW, kNotExtended, kWasUp}.Build( kWmResultZero), WmCharInfo{0xdf45, kScanCodeKeyW, kNotExtended, kWasUp}.Build( - kWmResultZero)); + kWmResultZero)}); const char* st = key_calls[0].key_event.character; @@ -1519,9 +1483,9 @@ TEST(KeyboardTest, MultibyteCharacter) { clear_key_calls(); // Release W - tester.InjectMessages( - 1, WmKeyUpInfo{kVirtualKeyW, kScanCodeKeyW, kNotExtended}.Build( - kWmResultZero)); + tester.InjectKeyboardChanges(std::vector{ + WmKeyUpInfo{kVirtualKeyW, kScanCodeKeyW, kNotExtended}.Build( + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalKeyW, @@ -1539,10 +1503,9 @@ TEST(KeyboardTest, NeverRedispatchShiftRightKeyDown) { // Press ShiftRight and the delegate responds false. tester.SetKeyState(VK_RSHIFT, true, true); - tester.InjectMessages( - 1, + tester.InjectKeyboardChanges(std::vector{ WmKeyDownInfo{VK_SHIFT, kScanCodeShiftRight, kNotExtended, kWasUp}.Build( - kWmResultZero)); + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); clear_key_calls(); @@ -1558,16 +1521,15 @@ TEST(KeyboardTest, ImeModifierEventsAreIgnored) { // US Keyboard layout. - // To make the keyboard into IME mode, there should have been events like - // letter key down with VK_PROCESSKEY. Omit them in this test since they don't - // seem significant. + // To make the keyboard into IME mode, there should have been + // events like letter key down with VK_PROCESSKEY. Omit them in + // this test since they don't seem significant. // Press CtrlRight in IME mode. tester.SetKeyState(VK_RCONTROL, true, false); - tester.InjectMessages( - 1, + tester.InjectKeyboardChanges(std::vector{ WmKeyDownInfo{VK_PROCESSKEY, kScanCodeControl, kExtended, kWasUp}.Build( - kWmResultZero)); + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, 0, 0, "", @@ -1588,20 +1550,18 @@ TEST(KeyboardTest, DisorderlyRespondedEvents) { }); // Press A - tester.InjectMessages( - 2, + tester.InjectKeyboardChanges(std::vector{ WmKeyDownInfo{kVirtualKeyA, kScanCodeKeyA, kNotExtended, kWasUp}.Build( kWmResultZero), WmCharInfo{'a', kScanCodeKeyA, kNotExtended, kWasUp}.Build( - kWmResultZero)); + kWmResultZero)}); // Press B - tester.InjectMessages( - 2, + tester.InjectKeyboardChanges(std::vector{ WmKeyDownInfo{kVirtualKeyB, kScanCodeKeyB, kNotExtended, kWasUp}.Build( kWmResultZero), WmCharInfo{'b', kScanCodeKeyB, kNotExtended, kWasUp}.Build( - kWmResultZero)); + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 2); EXPECT_EQ(recorded_callbacks.size(), 2); @@ -1642,20 +1602,18 @@ TEST(KeyboardTest, SlowFrameworkResponse) { }); // Press A - tester.InjectMessages( - 2, + tester.InjectKeyboardChanges(std::vector{ WmKeyDownInfo{kVirtualKeyA, kScanCodeKeyA, kNotExtended, kWasUp}.Build( kWmResultZero), WmCharInfo{'a', kScanCodeKeyA, kNotExtended, kWasUp}.Build( - kWmResultZero)); + kWmResultZero)}); // Hold A - tester.InjectMessages( - 2, + tester.InjectKeyboardChanges(std::vector{ WmKeyDownInfo{kVirtualKeyA, kScanCodeKeyA, kNotExtended, kWasDown}.Build( kWmResultZero), WmCharInfo{'a', kScanCodeKeyA, kNotExtended, kWasDown}.Build( - kWmResultZero)); + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 2); EXPECT_EQ(recorded_callbacks.size(), 2); @@ -1701,12 +1659,11 @@ TEST(KeyboardTest, SlowFrameworkResponseForIdenticalEvents) { }); // Press A - tester.InjectMessages( - 2, + tester.InjectKeyboardChanges(std::vector{ WmKeyDownInfo{kVirtualKeyA, kScanCodeKeyA, kNotExtended, kWasUp}.Build( kWmResultZero), WmCharInfo{'a', kScanCodeKeyA, kNotExtended, kWasUp}.Build( - kWmResultZero)); + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, kPhysicalKeyA, @@ -1714,9 +1671,9 @@ TEST(KeyboardTest, SlowFrameworkResponseForIdenticalEvents) { clear_key_calls(); // Release A - tester.InjectMessages( - 1, WmKeyUpInfo{kVirtualKeyA, kScanCodeKeyA, kNotExtended}.Build( - kWmResultZero)); + tester.InjectKeyboardChanges(std::vector{ + WmKeyUpInfo{kVirtualKeyA, kScanCodeKeyA, kNotExtended}.Build( + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalKeyA, @@ -1732,12 +1689,11 @@ TEST(KeyboardTest, SlowFrameworkResponseForIdenticalEvents) { clear_key_calls(); // Press A again - tester.InjectMessages( - 2, + tester.InjectKeyboardChanges(std::vector{ WmKeyDownInfo{kVirtualKeyA, kScanCodeKeyA, kNotExtended, kWasUp}.Build( kWmResultZero), WmCharInfo{'a', kScanCodeKeyA, kNotExtended, kWasUp}.Build( - kWmResultZero)); + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, kPhysicalKeyA, @@ -1745,9 +1701,9 @@ TEST(KeyboardTest, SlowFrameworkResponseForIdenticalEvents) { clear_key_calls(); // Release A again - tester.InjectMessages( - 1, WmKeyUpInfo{kVirtualKeyA, kScanCodeKeyA, kNotExtended}.Build( - kWmResultZero)); + tester.InjectKeyboardChanges(std::vector{ + WmKeyUpInfo{kVirtualKeyA, kScanCodeKeyA, kNotExtended}.Build( + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalKeyA, @@ -1766,12 +1722,11 @@ TEST(KeyboardTest, TextInputSubmit) { R"|([108, {"inputAction": "TextInputAction.none"}])|"); // Press Enter - tester.InjectMessages( - 2, + tester.InjectKeyboardChanges(std::vector{ WmKeyDownInfo{VK_RETURN, kScanCodeEnter, kNotExtended, kWasUp}.Build( kWmResultZero), WmCharInfo{'\n', kScanCodeEnter, kNotExtended, kWasUp}.Build( - kWmResultZero)); + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 2); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, kPhysicalEnter, @@ -1785,9 +1740,9 @@ TEST(KeyboardTest, TextInputSubmit) { clear_key_calls(); // Release Enter - tester.InjectMessages( - 1, WmKeyUpInfo{VK_RETURN, kScanCodeEnter, kNotExtended}.Build( - kWmResultZero)); + tester.InjectKeyboardChanges(std::vector{ + WmKeyUpInfo{VK_RETURN, kScanCodeEnter, kNotExtended}.Build( + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalEnter, @@ -1796,15 +1751,15 @@ TEST(KeyboardTest, TextInputSubmit) { // Make sure OnText is not obstructed after pressing Enter. // - // Regression test for https://github.com/flutter/flutter/issues/97706. + // Regression test for + // https://github.com/flutter/flutter/issues/97706. // Press A - tester.InjectMessages( - 2, + tester.InjectKeyboardChanges(std::vector{ WmKeyDownInfo{kVirtualKeyA, kScanCodeKeyA, kNotExtended, kWasUp}.Build( kWmResultZero), WmCharInfo{'a', kScanCodeKeyA, kNotExtended, kWasUp}.Build( - kWmResultZero)); + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 2); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, kPhysicalKeyA, @@ -1813,9 +1768,9 @@ TEST(KeyboardTest, TextInputSubmit) { clear_key_calls(); // Release A - tester.InjectMessages( - 1, WmKeyUpInfo{kVirtualKeyA, kScanCodeKeyA, kNotExtended}.Build( - kWmResultZero)); + tester.InjectKeyboardChanges(std::vector{ + WmKeyUpInfo{kVirtualKeyA, kScanCodeKeyA, kNotExtended}.Build( + kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalKeyA, From 9d93de3ccf93c0a6affcc3a309acf46719ba089d Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 7 Feb 2022 05:02:29 -0800 Subject: [PATCH 05/22] Migrate KeyStateChange --- .../windows/keyboard_win32_unittests.cc | 76 +++++++++---------- 1 file changed, 36 insertions(+), 40 deletions(-) diff --git a/shell/platform/windows/keyboard_win32_unittests.cc b/shell/platform/windows/keyboard_win32_unittests.cc index f24234fd48e9d..4e8c86b454233 100644 --- a/shell/platform/windows/keyboard_win32_unittests.cc +++ b/shell/platform/windows/keyboard_win32_unittests.cc @@ -332,10 +332,6 @@ class KeyboardTester { TestFlutterWindowsView& GetView() { return *view_; } MockKeyboardManagerWin32Delegate& GetWindow() { return *window_; } - void SetKeyState(uint32_t key, bool pressed, bool toggled_on) { - window_->SetKeyState(key, pressed, toggled_on); - } - // Set all events to be handled (true) or unhandled (false). void Responding(bool response) { callback_handler_ = RespondValue(response); } @@ -369,8 +365,8 @@ class KeyboardTester { break; case KeyboardChange::kStateChange: { const KeyStateChange& state_change = change.content.state_change; - SetKeyState(state_change.key, state_change.pressed, - state_change.toggled_on); + window_->SetKeyState(state_change.key, state_change.pressed, + state_change.toggled_on); break; } default: @@ -598,8 +594,8 @@ TEST(KeyboardTest, ShiftLeftUnhandled) { // US Keyboard layout // Press ShiftLeft - tester.SetKeyState(VK_LSHIFT, true, false); tester.InjectKeyboardChanges(std::vector{ + KeyStateChange{VK_LSHIFT, true, false}, WmKeyDownInfo{VK_SHIFT, kScanCodeShiftLeft, kNotExtended, kWasUp}.Build( kWmResultZero)}); @@ -610,8 +606,8 @@ TEST(KeyboardTest, ShiftLeftUnhandled) { clear_key_calls(); // Release ShiftLeft - tester.SetKeyState(VK_LSHIFT, false, true); tester.InjectKeyboardChanges(std::vector{ + KeyStateChange{VK_LSHIFT, false, true}, WmKeyUpInfo{VK_SHIFT, kScanCodeShiftLeft, kNotExtended}.Build( kWmResultZero)}); @@ -628,8 +624,8 @@ TEST(KeyboardTest, ShiftRightUnhandled) { // US Keyboard layout // Press ShiftRight - tester.SetKeyState(VK_RSHIFT, true, false); tester.InjectKeyboardChanges(std::vector{ + KeyStateChange{VK_RSHIFT, true, false}, WmKeyDownInfo{VK_SHIFT, kScanCodeShiftRight, kNotExtended, kWasUp}.Build( kWmResultZero)}); @@ -640,8 +636,8 @@ TEST(KeyboardTest, ShiftRightUnhandled) { clear_key_calls(); // Release ShiftRight - tester.SetKeyState(VK_RSHIFT, false, true); tester.InjectKeyboardChanges(std::vector{ + KeyStateChange{VK_RSHIFT, false, true}, WmKeyUpInfo{VK_SHIFT, kScanCodeShiftRight, kNotExtended}.Build( kWmResultZero)}); @@ -659,8 +655,8 @@ TEST(KeyboardTest, CtrlLeftUnhandled) { // US Keyboard layout // Press CtrlLeft - tester.SetKeyState(VK_LCONTROL, true, false); tester.InjectKeyboardChanges(std::vector{ + KeyStateChange{VK_LCONTROL, true, false}, WmKeyDownInfo{VK_CONTROL, kScanCodeControl, kNotExtended, kWasUp}.Build( kWmResultZero)}); @@ -671,8 +667,8 @@ TEST(KeyboardTest, CtrlLeftUnhandled) { clear_key_calls(); // Release CtrlLeft - tester.SetKeyState(VK_LCONTROL, false, true); tester.InjectKeyboardChanges(std::vector{ + KeyStateChange{VK_LCONTROL, false, true}, WmKeyUpInfo{VK_SHIFT, kScanCodeControl, kNotExtended}.Build( kWmResultZero)}); @@ -690,8 +686,8 @@ TEST(KeyboardTest, CtrlRightUnhandled) { // US Keyboard layout // Press CtrlRight - tester.SetKeyState(VK_RCONTROL, true, false); tester.InjectKeyboardChanges(std::vector{ + KeyStateChange{VK_RCONTROL, true, false}, WmKeyDownInfo{VK_CONTROL, kScanCodeControl, kExtended, kWasUp}.Build( kWmResultZero)}); @@ -702,8 +698,8 @@ TEST(KeyboardTest, CtrlRightUnhandled) { clear_key_calls(); // Release CtrlRight - tester.SetKeyState(VK_RCONTROL, false, true); tester.InjectKeyboardChanges(std::vector{ + KeyStateChange{VK_RCONTROL, false, true}, WmKeyUpInfo{VK_CONTROL, kScanCodeControl, kExtended}.Build( kWmResultZero)}); @@ -721,8 +717,8 @@ TEST(KeyboardTest, AltLeftUnhandled) { // US Keyboard layout // Press AltLeft. AltLeft is a SysKeyDown event. - tester.SetKeyState(VK_LMENU, true, false); tester.InjectKeyboardChanges(std::vector{ + KeyStateChange{VK_LMENU, true, false}, WmSysKeyDownInfo{VK_MENU, kScanCodeAlt, kNotExtended, kWasUp}.Build( kWmResultDefault)}); // Always pass to the default WndProc. @@ -732,8 +728,8 @@ TEST(KeyboardTest, AltLeftUnhandled) { clear_key_calls(); // Release AltLeft. AltLeft is a SysKeyUp event. - tester.SetKeyState(VK_LMENU, false, true); tester.InjectKeyboardChanges(std::vector{ + KeyStateChange{VK_LMENU, false, true}, WmSysKeyUpInfo{VK_MENU, kScanCodeAlt, kNotExtended}.Build( kWmResultDefault)}); // Always pass to the default WndProc. @@ -750,8 +746,8 @@ TEST(KeyboardTest, AltRightUnhandled) { // US Keyboard layout // Press AltRight. AltRight is a SysKeyDown event. - tester.SetKeyState(VK_RMENU, true, false); tester.InjectKeyboardChanges(std::vector{ + KeyStateChange{VK_RMENU, true, false}, WmSysKeyDownInfo{VK_MENU, kScanCodeAlt, kExtended, kWasUp}.Build( kWmResultDefault)}); // Always pass to the default WndProc. @@ -762,8 +758,8 @@ TEST(KeyboardTest, AltRightUnhandled) { clear_key_calls(); // Release AltRight. AltRight is a SysKeyUp event. - tester.SetKeyState(VK_RMENU, false, true); tester.InjectKeyboardChanges(std::vector{ + KeyStateChange{VK_RMENU, false, true}, WmSysKeyUpInfo{VK_MENU, kScanCodeAlt, kExtended}.Build( kWmResultDefault)}); // Always pass to the default WndProc. @@ -780,8 +776,8 @@ TEST(KeyboardTest, MetaLeftUnhandled) { // US Keyboard layout // Press MetaLeft - tester.SetKeyState(VK_LWIN, true, false); tester.InjectKeyboardChanges(std::vector{ + KeyStateChange{VK_LWIN, true, false}, WmKeyDownInfo{VK_LWIN, kScanCodeMetaLeft, kExtended, kWasUp}.Build( kWmResultZero)}); @@ -792,8 +788,8 @@ TEST(KeyboardTest, MetaLeftUnhandled) { clear_key_calls(); // Release MetaLeft - tester.SetKeyState(VK_LWIN, false, true); tester.InjectKeyboardChanges(std::vector{ + KeyStateChange{VK_LWIN, false, true}, WmKeyUpInfo{VK_LWIN, kScanCodeMetaLeft, kExtended}.Build(kWmResultZero)}); EXPECT_EQ(key_calls.size(), 1); @@ -809,8 +805,8 @@ TEST(KeyboardTest, MetaRightUnhandled) { // US Keyboard layout // Press MetaRight - tester.SetKeyState(VK_RWIN, true, false); tester.InjectKeyboardChanges(std::vector{ + KeyStateChange{VK_RWIN, true, false}, WmKeyDownInfo{VK_RWIN, kScanCodeMetaRight, kExtended, kWasUp}.Build( kWmResultZero)}); @@ -821,8 +817,8 @@ TEST(KeyboardTest, MetaRightUnhandled) { clear_key_calls(); // Release MetaRight - tester.SetKeyState(VK_RWIN, false, true); tester.InjectKeyboardChanges(std::vector{ + KeyStateChange{VK_RWIN, false, true}, WmKeyUpInfo{VK_RWIN, kScanCodeMetaRight, kExtended}.Build( kWmResultZero)}); @@ -841,8 +837,8 @@ TEST(KeyboardTest, ShiftLeftKeyA) { // US Keyboard layout // Press ShiftLeft - tester.SetKeyState(VK_LSHIFT, true, true); tester.InjectKeyboardChanges(std::vector{ + KeyStateChange{VK_LSHIFT, true, true}, WmKeyDownInfo{VK_SHIFT, kScanCodeShiftLeft, kNotExtended, kWasUp}.Build( kWmResultZero)}); @@ -866,8 +862,8 @@ TEST(KeyboardTest, ShiftLeftKeyA) { clear_key_calls(); // Release ShiftLeft - tester.SetKeyState(VK_LSHIFT, false, true); tester.InjectKeyboardChanges(std::vector{ + KeyStateChange{VK_LSHIFT, false, true}, WmKeyUpInfo{VK_SHIFT, kScanCodeShiftLeft, kNotExtended}.Build( kWmResultZero)}); @@ -896,8 +892,8 @@ TEST(KeyboardTest, CtrlLeftKeyA) { // US Keyboard layout // Press ControlLeft - tester.SetKeyState(VK_LCONTROL, true, true); tester.InjectKeyboardChanges(std::vector{ + KeyStateChange{VK_LCONTROL, true, true}, WmKeyDownInfo{VK_CONTROL, kScanCodeControl, kNotExtended, kWasUp}.Build( kWmResultZero)}); @@ -930,8 +926,8 @@ TEST(KeyboardTest, CtrlLeftKeyA) { clear_key_calls(); // Release ControlLeft - tester.SetKeyState(VK_LCONTROL, false, true); tester.InjectKeyboardChanges(std::vector{ + KeyStateChange{VK_LCONTROL, false, true}, WmKeyUpInfo{VK_CONTROL, kScanCodeControl, kNotExtended}.Build( kWmResultZero)}); @@ -950,8 +946,8 @@ TEST(KeyboardTest, CtrlLeftDigit1) { // US Keyboard layout // Press ControlLeft - tester.SetKeyState(VK_LCONTROL, true, true); tester.InjectKeyboardChanges(std::vector{ + KeyStateChange{VK_LCONTROL, true, true}, WmKeyDownInfo{VK_CONTROL, kScanCodeControl, kNotExtended, kWasUp}.Build( kWmResultZero)}); @@ -982,8 +978,8 @@ TEST(KeyboardTest, CtrlLeftDigit1) { clear_key_calls(); // Release ControlLeft - tester.SetKeyState(VK_LCONTROL, false, true); tester.InjectKeyboardChanges(std::vector{ + KeyStateChange{VK_LCONTROL, false, true}, WmKeyUpInfo{VK_CONTROL, kScanCodeControl, kNotExtended}.Build( kWmResultZero)}); @@ -1034,8 +1030,8 @@ TEST(KeyboardTest, AltGrModifiedKey) { // German Keyboard layout // Press AltGr, which Win32 precedes with a ContrlLeft down. - tester.SetKeyState(VK_LCONTROL, true, true); tester.InjectKeyboardChanges(std::vector{ + KeyStateChange{VK_LCONTROL, true, true}, WmKeyDownInfo{VK_LCONTROL, kScanCodeControl, kNotExtended, kWasUp}.Build( kWmResultZero), WmKeyDownInfo{VK_MENU, kScanCodeAlt, kExtended, kWasUp}.Build( @@ -1076,8 +1072,8 @@ TEST(KeyboardTest, AltGrModifiedKey) { // Release AltGr. Win32 doesn't dispatch ControlLeft up. Instead // Flutter will dispatch one. The AltGr is a system key, therefore // will be handled by Win32's default WndProc. - tester.SetKeyState(VK_LCONTROL, false, true); tester.InjectKeyboardChanges(std::vector{ + KeyStateChange{VK_LCONTROL, false, true}, WmSysKeyUpInfo{VK_MENU, kScanCodeAlt, kExtended}.Build( kWmResultDefault)}); @@ -1111,8 +1107,8 @@ TEST(KeyboardTest, AltGrTwice) { // The key down event causes a ControlLeft down and a AltRight // (extended AltLeft) down. - tester.SetKeyState(VK_LCONTROL, true, true); tester.InjectKeyboardChanges(std::vector{ + KeyStateChange{VK_LCONTROL, true, true}, WmKeyDownInfo{VK_LCONTROL, kScanCodeControl, kNotExtended, kWasUp}.Build( kWmResultZero), WmKeyDownInfo{VK_MENU, kScanCodeAlt, kExtended, kWasUp}.Build( @@ -1130,9 +1126,9 @@ TEST(KeyboardTest, AltGrTwice) { // 2. AltGr up. // The key up event only causes a AltRight (extended AltLeft) up. - tester.SetKeyState(VK_RMENU, false, true); - tester.SetKeyState(VK_LCONTROL, false, true); tester.InjectKeyboardChanges(std::vector{ + KeyStateChange{VK_LCONTROL, false, true}, + KeyStateChange{VK_RMENU, false, true}, WmSysKeyUpInfo{VK_MENU, kScanCodeAlt, kExtended}.Build( kWmResultDefault)}); EXPECT_EQ(key_calls.size(), 2); @@ -1145,8 +1141,8 @@ TEST(KeyboardTest, AltGrTwice) { // 3. AltGr down (or: ControlLeft down then AltRight down.) - tester.SetKeyState(VK_LCONTROL, true, false); tester.InjectKeyboardChanges(std::vector{ + KeyStateChange{VK_LCONTROL, true, false}, WmKeyDownInfo{VK_LCONTROL, kScanCodeControl, kNotExtended, kWasUp}.Build( kWmResultZero), WmKeyDownInfo{VK_MENU, kScanCodeAlt, kExtended, kWasUp}.Build( @@ -1164,9 +1160,9 @@ TEST(KeyboardTest, AltGrTwice) { // 4. AltGr up. // The key up event only causes a AltRight (extended AltLeft) up. - tester.SetKeyState(VK_RMENU, false, false); - tester.SetKeyState(VK_LCONTROL, false, false); tester.InjectKeyboardChanges(std::vector{ + KeyStateChange{VK_RMENU, false, false}, + KeyStateChange{VK_LCONTROL, false, false}, WmSysKeyUpInfo{VK_MENU, kScanCodeAlt, kExtended}.Build( kWmResultDefault)}); EXPECT_EQ(key_calls.size(), 2); @@ -1253,8 +1249,8 @@ TEST(KeyboardTest, DeadKeyWithoutDeadMaskThatCombines) { tester.Responding(false); // Press ShiftLeft - tester.SetKeyState(VK_LSHIFT, true, true); tester.InjectKeyboardChanges(std::vector{ + KeyStateChange{VK_LSHIFT, true, true}, WmKeyDownInfo{VK_SHIFT, kScanCodeShiftLeft, kNotExtended, kWasUp}.Build( kWmResultZero)}); @@ -1286,8 +1282,8 @@ TEST(KeyboardTest, DeadKeyWithoutDeadMaskThatCombines) { clear_key_calls(); // Release ShiftLeft - tester.SetKeyState(VK_LSHIFT, false, true); tester.InjectKeyboardChanges(std::vector{ + KeyStateChange{VK_LSHIFT, false, true}, WmKeyUpInfo{VK_SHIFT, kScanCodeShiftLeft, kNotExtended}.Build( kWmResultZero)}); @@ -1502,8 +1498,8 @@ TEST(KeyboardTest, NeverRedispatchShiftRightKeyDown) { tester.Responding(false); // Press ShiftRight and the delegate responds false. - tester.SetKeyState(VK_RSHIFT, true, true); tester.InjectKeyboardChanges(std::vector{ + KeyStateChange{VK_RSHIFT, true, true}, WmKeyDownInfo{VK_SHIFT, kScanCodeShiftRight, kNotExtended, kWasUp}.Build( kWmResultZero)}); @@ -1526,8 +1522,8 @@ TEST(KeyboardTest, ImeModifierEventsAreIgnored) { // this test since they don't seem significant. // Press CtrlRight in IME mode. - tester.SetKeyState(VK_RCONTROL, true, false); tester.InjectKeyboardChanges(std::vector{ + KeyStateChange{VK_RCONTROL, true, false}, WmKeyDownInfo{VK_PROCESSKEY, kScanCodeControl, kExtended, kWasUp}.Build( kWmResultZero)}); From c09b7b91b365073da49d0c726bc0dacafa02efdd Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 7 Feb 2022 05:08:21 -0800 Subject: [PATCH 06/22] Revert comment changes --- .../windows/keyboard_win32_unittests.cc | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/shell/platform/windows/keyboard_win32_unittests.cc b/shell/platform/windows/keyboard_win32_unittests.cc index 4e8c86b454233..1d790894430bf 100644 --- a/shell/platform/windows/keyboard_win32_unittests.cc +++ b/shell/platform/windows/keyboard_win32_unittests.cc @@ -1069,9 +1069,9 @@ TEST(KeyboardTest, AltGrModifiedKey) { kLogicalKeyQ, "", kNotSynthesized); clear_key_calls(); - // Release AltGr. Win32 doesn't dispatch ControlLeft up. Instead - // Flutter will dispatch one. The AltGr is a system key, therefore - // will be handled by Win32's default WndProc. + // Release AltGr. Win32 doesn't dispatch ControlLeft up. Instead Flutter will + // dispatch one. The AltGr is a system key, therefore will be handled by + // Win32's default WndProc. tester.InjectKeyboardChanges(std::vector{ KeyStateChange{VK_LCONTROL, false, true}, WmSysKeyUpInfo{VK_MENU, kScanCodeAlt, kExtended}.Build( @@ -1105,8 +1105,8 @@ TEST(KeyboardTest, AltGrTwice) { // 1. AltGr down. - // The key down event causes a ControlLeft down and a AltRight - // (extended AltLeft) down. + // The key down event causes a ControlLeft down and a AltRight (extended + // AltLeft) down. tester.InjectKeyboardChanges(std::vector{ KeyStateChange{VK_LCONTROL, true, true}, WmKeyDownInfo{VK_LCONTROL, kScanCodeControl, kNotExtended, kWasUp}.Build( @@ -1457,11 +1457,10 @@ TEST(KeyboardTest, MultibyteCharacter) { KeyboardTester tester; tester.Responding(false); - // Gothic Keyboard layout. (We need a layout that yields non-BMP - // characters without IME, which is actually very rare.) + // Gothic Keyboard layout. (We need a layout that yields non-BMP characters + // without IME, which is actually very rare.) - // Press key W of a US keyboard, which should yield character - // '𐍅'. + // Press key W of a US keyboard, which should yield character '𐍅'. tester.InjectKeyboardChanges(std::vector{ WmKeyDownInfo{kVirtualKeyW, kScanCodeKeyW, kNotExtended, kWasUp}.Build( kWmResultZero), @@ -1517,9 +1516,9 @@ TEST(KeyboardTest, ImeModifierEventsAreIgnored) { // US Keyboard layout. - // To make the keyboard into IME mode, there should have been - // events like letter key down with VK_PROCESSKEY. Omit them in - // this test since they don't seem significant. + // To make the keyboard into IME mode, there should have been events like + // letter key down with VK_PROCESSKEY. Omit them in this test since they don't + // seem significant. // Press CtrlRight in IME mode. tester.InjectKeyboardChanges(std::vector{ @@ -1747,8 +1746,7 @@ TEST(KeyboardTest, TextInputSubmit) { // Make sure OnText is not obstructed after pressing Enter. // - // Regression test for - // https://github.com/flutter/flutter/issues/97706. + // Regression test for https://github.com/flutter/flutter/issues/97706. // Press A tester.InjectKeyboardChanges(std::vector{ From 0d2860961bf207e1e001033f9ecd3c655fde32e9 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 7 Feb 2022 05:11:51 -0800 Subject: [PATCH 07/22] protected queue --- shell/platform/windows/keyboard_win32_unittests.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/platform/windows/keyboard_win32_unittests.cc b/shell/platform/windows/keyboard_win32_unittests.cc index 1d790894430bf..facbade373ef1 100644 --- a/shell/platform/windows/keyboard_win32_unittests.cc +++ b/shell/platform/windows/keyboard_win32_unittests.cc @@ -124,7 +124,7 @@ class TestKeystate { class MockKeyboardManagerWin32Delegate : public KeyboardManagerWin32::WindowDelegate, - public MockMessageQueue { + protected MockMessageQueue { public: MockKeyboardManagerWin32Delegate(WindowBindingHandlerDelegate* view) : view_(view), map_vk_to_char_(LayoutDefault) { From 0630cad619df8f07a8739f588e74425a42d79bf3 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 7 Feb 2022 05:13:26 -0800 Subject: [PATCH 08/22] Remove assert --- shell/platform/windows/keyboard_win32_unittests.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/shell/platform/windows/keyboard_win32_unittests.cc b/shell/platform/windows/keyboard_win32_unittests.cc index facbade373ef1..9788ef9dd1fee 100644 --- a/shell/platform/windows/keyboard_win32_unittests.cc +++ b/shell/platform/windows/keyboard_win32_unittests.cc @@ -256,7 +256,6 @@ class TestFlutterWindowsView : public FlutterWindowsView { std::unique_ptr CreateKeyboardKeyHandler( BinaryMessenger* messenger, KeyboardKeyEmbedderHandler::GetKeyStateHandler get_key_state) override { - assert(get_keyboard_state_); return FlutterWindowsView::CreateKeyboardKeyHandler( messenger, [this](int virtual_key) { return get_keyboard_state_(virtual_key); }); From 19d94358de299ac5630e95369a16a6601c7c57bb Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 7 Feb 2022 15:51:01 -0800 Subject: [PATCH 09/22] Move InjectKeyboardChanges to window --- .../windows/keyboard_win32_unittests.cc | 58 +++++++++---------- 1 file changed, 26 insertions(+), 32 deletions(-) diff --git a/shell/platform/windows/keyboard_win32_unittests.cc b/shell/platform/windows/keyboard_win32_unittests.cc index 9788ef9dd1fee..e10fb4bf28883 100644 --- a/shell/platform/windows/keyboard_win32_unittests.cc +++ b/shell/platform/windows/keyboard_win32_unittests.cc @@ -152,18 +152,35 @@ class MockKeyboardManagerWin32Delegate map_vk_to_char == nullptr ? LayoutDefault : map_vk_to_char; } - void SetKeyState(uint32_t key, bool pressed, bool toggled_on) { - key_state_.Set(key, pressed, toggled_on); - } - SHORT GetKeyState(int virtual_key) { return key_state_.Get(virtual_key); } - void PushBackMessage(const flutter::testing::Win32Message* message) { - PushBack(message); + void InjectKeyboardChanges(std::vector changes) { + for (const KeyboardChange& change : changes) { + switch (change.type) { + case KeyboardChange::kMessage: + PushBack(&change.content.message); + break; + default: + break; + } + } + for (const KeyboardChange& change : changes) { + switch (change.type) { + case KeyboardChange::kMessage: + DispatchFront(); + break; + case KeyboardChange::kStateChange: { + const KeyStateChange& state_change = change.content.state_change; + key_state_.Set(state_change.key, state_change.pressed, + state_change.toggled_on); + break; + } + default: + assert(false); + } + } } - LRESULT DispatchFrontMessage() { return DispatchFront(); } - protected: BOOL Win32PeekMessage(LPMSG lpMsg, UINT wMsgFilterMin, @@ -348,30 +365,7 @@ class KeyboardTester { void SetLayout(MapVkToCharHandler layout) { window_->SetLayout(layout); } void InjectKeyboardChanges(std::vector changes) { - for (const KeyboardChange& change : changes) { - switch (change.type) { - case KeyboardChange::kMessage: - window_->PushBackMessage(&change.content.message); - break; - default: - break; - } - } - for (const KeyboardChange& change : changes) { - switch (change.type) { - case KeyboardChange::kMessage: - window_->DispatchFrontMessage(); - break; - case KeyboardChange::kStateChange: { - const KeyStateChange& state_change = change.content.state_change; - window_->SetKeyState(state_change.key, state_change.pressed, - state_change.toggled_on); - break; - } - default: - assert(false); - } - } + window_->InjectKeyboardChanges(changes); } private: From 0f83ffc184997aa15becb09916fec36233509d75 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 7 Feb 2022 15:53:10 -0800 Subject: [PATCH 10/22] Rename to kKeyStateChange --- .../windows/keyboard_win32_unittests.cc | 23 +++++-------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/shell/platform/windows/keyboard_win32_unittests.cc b/shell/platform/windows/keyboard_win32_unittests.cc index e10fb4bf28883..a946fd5f8fe8c 100644 --- a/shell/platform/windows/keyboard_win32_unittests.cc +++ b/shell/platform/windows/keyboard_win32_unittests.cc @@ -36,17 +36,6 @@ namespace { constexpr SHORT kStateMaskToggled = 0x01; constexpr SHORT kStateMaskPressed = 0x80; -static LPARAM CreateKeyEventLparam(USHORT scancode, - bool extended, - bool was_down, - USHORT repeat_count = 1, - bool context_code = 0, - bool transition_state = 0) { - return ((LPARAM(transition_state) << 31) | (LPARAM(was_down) << 30) | - (LPARAM(context_code) << 29) | (LPARAM(extended ? 0x1 : 0x0) << 24) | - (LPARAM(scancode) << 16) | LPARAM(repeat_count)); -} - typedef uint32_t (*MapVkToCharHandler)(uint32_t virtual_key); uint32_t LayoutDefault(uint32_t virtual_key) { @@ -94,18 +83,18 @@ struct KeyboardChange { content.message = message; } - KeyboardChange(KeyStateChange change) : type(kStateChange) { - content.state_change = change; + KeyboardChange(KeyStateChange change) : type(kKeyStateChange) { + content.key_state_change = change; } enum Type { kMessage, - kStateChange, + kKeyStateChange, } type; union { Win32Message message; - KeyStateChange state_change; + KeyStateChange key_state_change; } content; }; @@ -169,8 +158,8 @@ class MockKeyboardManagerWin32Delegate case KeyboardChange::kMessage: DispatchFront(); break; - case KeyboardChange::kStateChange: { - const KeyStateChange& state_change = change.content.state_change; + case KeyboardChange::kKeyStateChange: { + const KeyStateChange& state_change = change.content.key_state_change; key_state_.Set(state_change.key, state_change.pressed, state_change.toggled_on); break; From 0a5dcaad3be9916e3c944ab07cf9c3327ff71984 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 7 Feb 2022 04:43:22 -0800 Subject: [PATCH 11/22] Split MockMessageQueue messages. Remove WMsg.hWnd Fix embedder test Implement and finish tests --- .../windows/keyboard_key_embedder_handler.cc | 8 ++ ...keyboard_key_embedder_handler_unittests.cc | 8 +- .../windows/keyboard_manager_win32.cc | 4 +- .../windows/keyboard_win32_unittests.cc | 76 +++++++++++++++++-- shell/platform/windows/testing/wm_builders.cc | 18 ++--- shell/platform/windows/testing/wm_builders.h | 26 ++----- 6 files changed, 99 insertions(+), 41 deletions(-) diff --git a/shell/platform/windows/keyboard_key_embedder_handler.cc b/shell/platform/windows/keyboard_key_embedder_handler.cc index bc4632877e963..4ba42fdeece60 100644 --- a/shell/platform/windows/keyboard_key_embedder_handler.cc +++ b/shell/platform/windows/keyboard_key_embedder_handler.cc @@ -459,6 +459,14 @@ void KeyboardKeyEmbedderHandler::InitCriticalKeys() { createCheckedKey(VK_LCONTROL, false, true, false)); critical_keys_.emplace(VK_RCONTROL, createCheckedKey(VK_RCONTROL, true, true, false)); + critical_keys_.emplace(VK_LMENU, + createCheckedKey(VK_LMENU, false, true, false)); + critical_keys_.emplace(VK_RMENU, + createCheckedKey(VK_RMENU, true, true, false)); + critical_keys_.emplace(VK_LWIN, + createCheckedKey(VK_LWIN, false, true, false)); + critical_keys_.emplace(VK_RWIN, + createCheckedKey(VK_RWIN, false, true, false)); critical_keys_.emplace(VK_CAPITAL, createCheckedKey(VK_CAPITAL, false, true, true)); diff --git a/shell/platform/windows/keyboard_key_embedder_handler_unittests.cc b/shell/platform/windows/keyboard_key_embedder_handler_unittests.cc index 0345f7c81a9ff..4a916735a0ba2 100644 --- a/shell/platform/windows/keyboard_key_embedder_handler_unittests.cc +++ b/shell/platform/windows/keyboard_key_embedder_handler_unittests.cc @@ -80,7 +80,6 @@ constexpr uint64_t kScanCodeShiftLeft = 0x2a; constexpr uint64_t kScanCodeShiftRight = 0x36; constexpr uint64_t kVirtualKeyA = 0x41; -constexpr uint64_t kVirtualAltLeft = 0xa4; using namespace ::flutter::testing::keycodes; } // namespace @@ -1021,8 +1020,9 @@ TEST(KeyboardKeyEmbedderHandlerTest, SysKeyPress) { key_state.Getter()); // Press KeyAltLeft. + key_state.Set(VK_LMENU, true); handler->KeyboardHook( - kVirtualAltLeft, kScanCodeAltLeft, WM_SYSKEYDOWN, 0, false, false, + VK_LMENU, kScanCodeAltLeft, WM_SYSKEYDOWN, 0, false, false, [&last_handled](bool handled) { last_handled = handled; }); EXPECT_EQ(last_handled, false); EXPECT_EQ(results.size(), 1); @@ -1036,11 +1036,11 @@ TEST(KeyboardKeyEmbedderHandlerTest, SysKeyPress) { event->callback(true, event->user_data); EXPECT_EQ(last_handled, true); results.clear(); - key_state.Set(kVirtualAltLeft, true); // Release KeyAltLeft. + key_state.Set(VK_LMENU, false); handler->KeyboardHook( - kVirtualAltLeft, kScanCodeAltLeft, WM_SYSKEYUP, 0, false, true, + VK_LMENU, kScanCodeAltLeft, WM_SYSKEYUP, 0, false, true, [&last_handled](bool handled) { last_handled = handled; }); EXPECT_EQ(results.size(), 1); event = results.data(); diff --git a/shell/platform/windows/keyboard_manager_win32.cc b/shell/platform/windows/keyboard_manager_win32.cc index ab14f120483c0..58a4196183269 100644 --- a/shell/platform/windows/keyboard_manager_win32.cc +++ b/shell/platform/windows/keyboard_manager_win32.cc @@ -32,8 +32,8 @@ static constexpr int kMaxPendingEvents = 1000; // the Flutter framework thinking that CtrlLeft is still pressed. // // To resolve this, Flutter recognizes this fake CtrlLeft down event using the -// following AltRight down event. Flutter then synthesizes a CtrlLeft key up -// event immediately after the corresponding AltRight key up event. +// following AltRight down event. Flutter then forges a CtrlLeft key up event +// immediately after the corresponding AltRight key up event. // // One catch is that it is impossible to distinguish the fake CtrlLeft down // from a normal CtrlLeft down (followed by a AltRight down), since they diff --git a/shell/platform/windows/keyboard_win32_unittests.cc b/shell/platform/windows/keyboard_win32_unittests.cc index a946fd5f8fe8c..90b2f771bcf33 100644 --- a/shell/platform/windows/keyboard_win32_unittests.cc +++ b/shell/platform/windows/keyboard_win32_unittests.cc @@ -22,6 +22,7 @@ #include #include +#include using testing::_; using testing::Invoke; @@ -70,12 +71,24 @@ class TestKeyboardManagerWin32 : public KeyboardManagerWin32 { bool during_redispatch_ = false; }; +// Injecting this kind of keyboard change means that a key state (the true +// state for a key, typically a modifier) should be changed. struct KeyStateChange { uint32_t key; bool pressed; bool toggled_on; }; +// Injecting this kind of keyboard change means that a forged event is expected, +// and `KeyStateChange`s after this will be applied only after the forged event. +// +// See `IsKeyDownAltRight` for explaination for foged events. +struct ExpectForgedMessage { + explicit ExpectForgedMessage(Win32Message message) : message(message){}; + + Win32Message message; +}; + struct KeyboardChange { // The constructors are intentionally for implicit conversion. @@ -87,14 +100,21 @@ struct KeyboardChange { content.key_state_change = change; } + KeyboardChange(ExpectForgedMessage forged_message) + : type(kExpectForgedMessage) { + content.expected_forged_message = forged_message.message; + } + enum Type { kMessage, kKeyStateChange, + kExpectForgedMessage, } type; union { Win32Message message; KeyStateChange key_state_change; + Win32Message expected_forged_message; } content; }; @@ -144,6 +164,7 @@ class MockKeyboardManagerWin32Delegate SHORT GetKeyState(int virtual_key) { return key_state_.Get(virtual_key); } void InjectKeyboardChanges(std::vector changes) { + // First queue all messages for peeking to work. for (const KeyboardChange& change : changes) { switch (change.type) { case KeyboardChange::kMessage: @@ -158,10 +179,20 @@ class MockKeyboardManagerWin32Delegate case KeyboardChange::kMessage: DispatchFront(); break; + case KeyboardChange::kExpectForgedMessage: + forged_message_expectations_.push_back(ForgedMessageExpectation{ + .message = change.content.expected_forged_message, + }); + break; case KeyboardChange::kKeyStateChange: { const KeyStateChange& state_change = change.content.key_state_change; - key_state_.Set(state_change.key, state_change.pressed, + if (forged_message_expectations_.empty()) { + key_state_.Set(state_change.key, state_change.pressed, state_change.toggled_on); + } else { + forged_message_expectations_.back() + .state_changes_afterwards.push_back(state_change); + } break; } default: @@ -194,18 +225,40 @@ class MockKeyboardManagerWin32Delegate } // This method is called when the keyboard manager redispatches messages - // or dispatches CtrlLeft up for AltGr. + // or forges messages (such as CtrlLeft up right before AltGr up). UINT Win32DispatchMessage(UINT Msg, WPARAM wParam, LPARAM lParam) override { bool handled = keyboard_manager_->HandleMessage(Msg, wParam, lParam); if (keyboard_manager_->DuringRedispatch()) { EXPECT_FALSE(handled); + } else { + EXPECT_FALSE(forged_message_expectations_.empty()); + ForgedMessageExpectation expectation = + forged_message_expectations_.front(); + forged_message_expectations_.pop_front(); + EXPECT_EQ(expectation.message.message, Msg); + EXPECT_EQ(expectation.message.wParam, wParam & 0xffffffff); + EXPECT_EQ(expectation.message.lParam, lParam & 0xffffffff); + if (expectation.message.expected_result != kWmResultDontCheck) { + EXPECT_EQ(expectation.message.expected_result, + handled ? kWmResultZero : kWmResultDefault); + } + for (const KeyStateChange& change : + expectation.state_changes_afterwards) { + key_state_.Set(change.key, change.pressed, change.toggled_on); + } } return 0; } private: + struct ForgedMessageExpectation { + Win32Message message; + std::list state_changes_afterwards; + }; + WindowBindingHandlerDelegate* view_; std::unique_ptr keyboard_manager_; + std::list forged_message_expectations_; MapVkToCharHandler map_vk_to_char_; TestKeystate key_state_; }; @@ -1016,6 +1069,7 @@ TEST(KeyboardTest, AltGrModifiedKey) { KeyStateChange{VK_LCONTROL, true, true}, WmKeyDownInfo{VK_LCONTROL, kScanCodeControl, kNotExtended, kWasUp}.Build( kWmResultZero), + KeyStateChange{VK_RMENU, true, true}, WmKeyDownInfo{VK_MENU, kScanCodeAlt, kExtended, kWasUp}.Build( kWmResultZero)}); @@ -1052,10 +1106,14 @@ TEST(KeyboardTest, AltGrModifiedKey) { clear_key_calls(); // Release AltGr. Win32 doesn't dispatch ControlLeft up. Instead Flutter will - // dispatch one. The AltGr is a system key, therefore will be handled by - // Win32's default WndProc. + // forge one. The AltGr is a system key, therefore will be handled by Win32's + // default WndProc. tester.InjectKeyboardChanges(std::vector{ KeyStateChange{VK_LCONTROL, false, true}, + ExpectForgedMessage{ + WmKeyUpInfo{VK_LCONTROL, kScanCodeControl, kNotExtended}.Build( + kWmResultZero)}, + KeyStateChange{VK_RMENU, false, true}, WmSysKeyUpInfo{VK_MENU, kScanCodeAlt, kExtended}.Build( kWmResultDefault)}); @@ -1093,6 +1151,7 @@ TEST(KeyboardTest, AltGrTwice) { KeyStateChange{VK_LCONTROL, true, true}, WmKeyDownInfo{VK_LCONTROL, kScanCodeControl, kNotExtended, kWasUp}.Build( kWmResultZero), + KeyStateChange{VK_RMENU, true, true}, WmKeyDownInfo{VK_MENU, kScanCodeAlt, kExtended, kWasUp}.Build( kWmResultZero)}); @@ -1110,6 +1169,9 @@ TEST(KeyboardTest, AltGrTwice) { // The key up event only causes a AltRight (extended AltLeft) up. tester.InjectKeyboardChanges(std::vector{ KeyStateChange{VK_LCONTROL, false, true}, + ExpectForgedMessage{ + WmKeyUpInfo{VK_LCONTROL, kScanCodeControl, kNotExtended}.Build( + kWmResultZero)}, KeyStateChange{VK_RMENU, false, true}, WmSysKeyUpInfo{VK_MENU, kScanCodeAlt, kExtended}.Build( kWmResultDefault)}); @@ -1127,6 +1189,7 @@ TEST(KeyboardTest, AltGrTwice) { KeyStateChange{VK_LCONTROL, true, false}, WmKeyDownInfo{VK_LCONTROL, kScanCodeControl, kNotExtended, kWasUp}.Build( kWmResultZero), + KeyStateChange{VK_RMENU, true, true}, WmKeyDownInfo{VK_MENU, kScanCodeAlt, kExtended, kWasUp}.Build( kWmResultZero)}); @@ -1143,8 +1206,11 @@ TEST(KeyboardTest, AltGrTwice) { // The key up event only causes a AltRight (extended AltLeft) up. tester.InjectKeyboardChanges(std::vector{ - KeyStateChange{VK_RMENU, false, false}, KeyStateChange{VK_LCONTROL, false, false}, + ExpectForgedMessage{ + WmKeyUpInfo{VK_LCONTROL, kScanCodeControl, kNotExtended}.Build( + kWmResultZero)}, + KeyStateChange{VK_RMENU, false, false}, WmSysKeyUpInfo{VK_MENU, kScanCodeAlt, kExtended}.Build( kWmResultDefault)}); EXPECT_EQ(key_calls.size(), 2); diff --git a/shell/platform/windows/testing/wm_builders.cc b/shell/platform/windows/testing/wm_builders.cc index 396aca2ddd069..bc69c51be7b09 100644 --- a/shell/platform/windows/testing/wm_builders.cc +++ b/shell/platform/windows/testing/wm_builders.cc @@ -7,7 +7,7 @@ namespace flutter { namespace testing { -Win32Message WmKeyDownInfo::Build(LRESULT expected_result, HWND hWnd) { +Win32Message WmKeyDownInfo::Build(LRESULT expected_result) { uint32_t lParam = (repeat_count << 0) | (scan_code << 16) | (extended << 24) | (prev_state << 30); return Win32Message{ @@ -15,11 +15,10 @@ Win32Message WmKeyDownInfo::Build(LRESULT expected_result, HWND hWnd) { .wParam = key, .lParam = lParam, .expected_result = expected_result, - .hWnd = hWnd, }; } -Win32Message WmKeyUpInfo::Build(LRESULT expected_result, HWND hWnd) { +Win32Message WmKeyUpInfo::Build(LRESULT expected_result) { uint32_t lParam = (1 /* repeat_count */ << 0) | (scan_code << 16) | (extended << 24) | (1 /* prev_state */ << 30) | (1 /* transition */ << 31); @@ -28,11 +27,10 @@ Win32Message WmKeyUpInfo::Build(LRESULT expected_result, HWND hWnd) { .wParam = key, .lParam = lParam, .expected_result = expected_result, - .hWnd = hWnd, }; } -Win32Message WmCharInfo::Build(LRESULT expected_result, HWND hWnd) { +Win32Message WmCharInfo::Build(LRESULT expected_result) { uint32_t lParam = (repeat_count << 0) | (scan_code << 16) | (extended << 24) | (bit25 << 25) | (context << 29) | (prev_state << 30) | (transition << 31); @@ -41,11 +39,10 @@ Win32Message WmCharInfo::Build(LRESULT expected_result, HWND hWnd) { .wParam = char_code, .lParam = lParam, .expected_result = expected_result, - .hWnd = hWnd, }; } -Win32Message WmSysKeyDownInfo::Build(LRESULT expected_result, HWND hWnd) { +Win32Message WmSysKeyDownInfo::Build(LRESULT expected_result) { uint32_t lParam = (repeat_count << 0) | (scan_code << 16) | (extended << 24) | (context << 29) | (prev_state << 30) | (0 /* transition */ << 31); @@ -54,11 +51,10 @@ Win32Message WmSysKeyDownInfo::Build(LRESULT expected_result, HWND hWnd) { .wParam = key, .lParam = lParam, .expected_result = expected_result, - .hWnd = hWnd, }; } -Win32Message WmSysKeyUpInfo::Build(LRESULT expected_result, HWND hWnd) { +Win32Message WmSysKeyUpInfo::Build(LRESULT expected_result) { uint32_t lParam = (1 /* repeat_count */ << 0) | (scan_code << 16) | (extended << 24) | (context << 29) | (1 /* prev_state */ << 30) | (1 /* transition */ << 31); @@ -67,11 +63,10 @@ Win32Message WmSysKeyUpInfo::Build(LRESULT expected_result, HWND hWnd) { .wParam = key, .lParam = lParam, .expected_result = expected_result, - .hWnd = hWnd, }; } -Win32Message WmDeadCharInfo::Build(LRESULT expected_result, HWND hWnd) { +Win32Message WmDeadCharInfo::Build(LRESULT expected_result) { uint32_t lParam = (repeat_count << 0) | (scan_code << 16) | (extended << 24) | (context << 30) | (prev_state << 30) | (transition << 31); return Win32Message{ @@ -79,7 +74,6 @@ Win32Message WmDeadCharInfo::Build(LRESULT expected_result, HWND hWnd) { .wParam = char_code, .lParam = lParam, .expected_result = expected_result, - .hWnd = hWnd, }; } diff --git a/shell/platform/windows/testing/wm_builders.h b/shell/platform/windows/testing/wm_builders.h index fd3b8914388db..de2551dccbcd9 100644 --- a/shell/platform/windows/testing/wm_builders.h +++ b/shell/platform/windows/testing/wm_builders.h @@ -16,14 +16,13 @@ constexpr LRESULT kWmResultZero = 0; constexpr LRESULT kWmResultDefault = 0xDEADC0DE; constexpr LRESULT kWmResultDontCheck = 0xFFFF1234; -// A struc to hold simulated events that will be delivered after the framework +// A struct to hold simulated events that will be delivered after the framework // response is handled. struct Win32Message { UINT message; WPARAM wParam; LPARAM lParam; LRESULT expected_result; - HWND hWnd; }; typedef enum WmFieldExtended { @@ -64,13 +63,9 @@ typedef struct WmKeyDownInfo { uint16_t repeat_count = 1; - Win32Message Build(LRESULT expected_result = kWmResultDontCheck, - HWND hWnd = NULL); + Win32Message Build(LRESULT expected_result = kWmResultDontCheck); } WmKeyDownInfo; -// Win32Message BuildMessage(WmKeyDownInfo info, LRESULT expected_result = -// kWmResultDontCheck, HWND hWnd = NULL); - // WM_KEYUP messages. // // See https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-keyup. @@ -89,8 +84,7 @@ typedef struct WmKeyUpInfo { // uint16_t repeat_count; // Always 1. - Win32Message Build(LRESULT expected_result = kWmResultDontCheck, - HWND hWnd = NULL); + Win32Message Build(LRESULT expected_result = kWmResultDontCheck); } WmKeyUpInfo; // WM_CHAR messages. @@ -116,8 +110,7 @@ typedef struct WmCharInfo { // Some messages are sent with bit25 set. Its meaning is yet unknown. bool bit25 = 0; - Win32Message Build(LRESULT expected_result = kWmResultDontCheck, - HWND hWnd = NULL); + Win32Message Build(LRESULT expected_result = kWmResultDontCheck); } WmCharInfo; // WM_SYSKEYDOWN messages. @@ -136,10 +129,9 @@ typedef struct WmSysKeyDownInfo { WmFieldContext context; - uint16_t repeat_count; + uint16_t repeat_count = 1; - Win32Message Build(LRESULT expected_result = kWmResultDontCheck, - HWND hWnd = NULL); + Win32Message Build(LRESULT expected_result = kWmResultDontCheck); } WmSysKeyDownInfo; // WM_SYSKEYUP messages. @@ -160,8 +152,7 @@ typedef struct WmSysKeyUpInfo { // uint16_t repeat_count; // Always 1. - Win32Message Build(LRESULT expected_result = kWmResultDontCheck, - HWND hWnd = NULL); + Win32Message Build(LRESULT expected_result = kWmResultDontCheck); } WmSysKeyUpInfo; // WM_DEADCHAR messages. @@ -182,8 +173,7 @@ typedef struct WmDeadCharInfo { uint16_t repeat_count = 1; - Win32Message Build(LRESULT expected_result = kWmResultDontCheck, - HWND hWnd = NULL); + Win32Message Build(LRESULT expected_result = kWmResultDontCheck); } WmDeadCharInfo; } // namespace testing From 73a3189ce5d4c0f88471132d85355f836d29e573 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 7 Feb 2022 15:59:00 -0800 Subject: [PATCH 12/22] Format --- shell/platform/windows/keyboard_win32_unittests.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/platform/windows/keyboard_win32_unittests.cc b/shell/platform/windows/keyboard_win32_unittests.cc index a946fd5f8fe8c..82c51c979a3fb 100644 --- a/shell/platform/windows/keyboard_win32_unittests.cc +++ b/shell/platform/windows/keyboard_win32_unittests.cc @@ -161,7 +161,7 @@ class MockKeyboardManagerWin32Delegate case KeyboardChange::kKeyStateChange: { const KeyStateChange& state_change = change.content.key_state_change; key_state_.Set(state_change.key, state_change.pressed, - state_change.toggled_on); + state_change.toggled_on); break; } default: From e5233ebc27e2e7ee445fb2755cda57005d98875f Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 7 Feb 2022 16:31:47 -0800 Subject: [PATCH 13/22] Better doc --- shell/platform/windows/keyboard_win32_unittests.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/shell/platform/windows/keyboard_win32_unittests.cc b/shell/platform/windows/keyboard_win32_unittests.cc index 90b2f771bcf33..377554180816c 100644 --- a/shell/platform/windows/keyboard_win32_unittests.cc +++ b/shell/platform/windows/keyboard_win32_unittests.cc @@ -79,8 +79,10 @@ struct KeyStateChange { bool toggled_on; }; -// Injecting this kind of keyboard change means that a forged event is expected, -// and `KeyStateChange`s after this will be applied only after the forged event. +// Injecting this kind of keyboard change does not make any changes to the +// keyboard system, but indicates that a forged event is expected here, and +// that `KeyStateChange`s after this will be applied only after the forged +// event. // // See `IsKeyDownAltRight` for explaination for foged events. struct ExpectForgedMessage { From b76d1e04732a8791520a09548f78f966711679aa Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 8 Feb 2022 04:33:31 -0800 Subject: [PATCH 14/22] Impl --- .../windows/keyboard_manager_win32.cc | 26 ++++++++++++------- .../platform/windows/keyboard_manager_win32.h | 1 + 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/shell/platform/windows/keyboard_manager_win32.cc b/shell/platform/windows/keyboard_manager_win32.cc index 58a4196183269..6fcb8c59a2c9e 100644 --- a/shell/platform/windows/keyboard_manager_win32.cc +++ b/shell/platform/windows/keyboard_manager_win32.cc @@ -228,20 +228,21 @@ void KeyboardManagerWin32::HandleOnKeyResult( IsKeyDownShiftRight(event->key, event->was_down); // For handled events, that's all. - if (real_handled) { - if (pending_text != pending_texts_.end()) { - pending_texts_.erase(pending_text); - } - return; - } - // For unhandled events, dispatch them to OnText. if (pending_text != pending_texts_.end()) { - pending_text->ready = true; + if (pending_text->placeholder || real_handled) { + pending_texts_.erase(pending_text); + } else { + pending_text->ready = true; + } DispatchReadyTexts(); } + if (real_handled) { + return; + } + RedispatchEvent(std::move(event)); } @@ -327,10 +328,12 @@ bool KeyboardManagerWin32::HandleMessage(UINT const action, // // Checking `character` filters out non-printable event characters. std::list::iterator pending_text; - if (action == WM_CHAR && character != 0) { + if (action == WM_CHAR) { + bool valid = character != 0 && IsPrintable(wparam); pending_texts_.push_back(PendingText{ .ready = false, .content = text, + .placeholder = !valid, }); pending_text = std::prev(pending_texts_.end()); } else { @@ -358,7 +361,7 @@ bool KeyboardManagerWin32::HandleMessage(UINT const action, // Also filter out ASCII control characters, which are sent as WM_CHAR // events for all control key shortcuts. current_session_.clear(); - if (action == WM_CHAR && IsPrintable(wparam)) { + if (action == WM_CHAR) { pending_texts_.push_back(PendingText{ .ready = true, .content = text, @@ -372,6 +375,9 @@ bool KeyboardManagerWin32::HandleMessage(UINT const action, case WM_SYSKEYDOWN: case WM_KEYUP: case WM_SYSKEYUP: { + if (wparam == VK_PACKET) { + return false; + } current_session_.clear(); current_session_.push_back( Win32Message{.action = action, .wparam = wparam, .lparam = lparam}); diff --git a/shell/platform/windows/keyboard_manager_win32.h b/shell/platform/windows/keyboard_manager_win32.h index 5cfac739a2713..66da479454754 100644 --- a/shell/platform/windows/keyboard_manager_win32.h +++ b/shell/platform/windows/keyboard_manager_win32.h @@ -138,6 +138,7 @@ class KeyboardManagerWin32 { struct PendingText { bool ready; std::u16string content; + bool placeholder = false; }; // Returns true if it's a new event, or false if it's a redispatched event. From ad39cd8dab4b9c1c63c0eccc69fbef0f0607e0ae Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 8 Feb 2022 18:10:06 -0800 Subject: [PATCH 15/22] KeyUp overwrite_prev_state_0 --- shell/platform/windows/testing/wm_builders.cc | 2 +- shell/platform/windows/testing/wm_builders.h | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/shell/platform/windows/testing/wm_builders.cc b/shell/platform/windows/testing/wm_builders.cc index bc69c51be7b09..520ac00d45147 100644 --- a/shell/platform/windows/testing/wm_builders.cc +++ b/shell/platform/windows/testing/wm_builders.cc @@ -20,7 +20,7 @@ Win32Message WmKeyDownInfo::Build(LRESULT expected_result) { Win32Message WmKeyUpInfo::Build(LRESULT expected_result) { uint32_t lParam = (1 /* repeat_count */ << 0) | (scan_code << 16) | - (extended << 24) | (1 /* prev_state */ << 30) | + (extended << 24) | (!overwrite_prev_state_0 << 30) | (1 /* transition */ << 31); return Win32Message{ .message = WM_KEYUP, diff --git a/shell/platform/windows/testing/wm_builders.h b/shell/platform/windows/testing/wm_builders.h index de2551dccbcd9..6f93b13d1c61a 100644 --- a/shell/platform/windows/testing/wm_builders.h +++ b/shell/platform/windows/testing/wm_builders.h @@ -84,6 +84,11 @@ typedef struct WmKeyUpInfo { // uint16_t repeat_count; // Always 1. + // Set this flag to enforce prev_state to be 0. + // + // This occurs in rare cases when the message is synthesized. + bool overwrite_prev_state_0; + Win32Message Build(LRESULT expected_result = kWmResultDontCheck); } WmKeyUpInfo; From 5620489cc2b59716488e9a2e49ded0dc00be3b26 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Wed, 9 Feb 2022 04:44:25 -0800 Subject: [PATCH 16/22] Tests --- .../windows/keyboard_win32_unittests.cc | 209 ++++++++++++++++-- 1 file changed, 194 insertions(+), 15 deletions(-) diff --git a/shell/platform/windows/keyboard_win32_unittests.cc b/shell/platform/windows/keyboard_win32_unittests.cc index 377554180816c..efd234c555c1e 100644 --- a/shell/platform/windows/keyboard_win32_unittests.cc +++ b/shell/platform/windows/keyboard_win32_unittests.cc @@ -327,14 +327,12 @@ class TestFlutterWindowsView : public FlutterWindowsView { KeyboardKeyEmbedderHandler::GetKeyStateHandler get_keyboard_state_; }; -typedef enum { - kKeyCallOnKey, - kKeyCallOnText, - kKeyCallTextMethodCall, -} KeyCallType; - -typedef struct { - KeyCallType type; +struct { + enum { + kKeyCallOnKey, + kKeyCallOnText, + kKeyCallTextMethodCall, + } type; // Only one of the following fields should be assigned. FlutterKeyEvent key_event; // For kKeyCallOnKey @@ -346,7 +344,7 @@ static std::vector key_calls; void clear_key_calls() { for (KeyCall& key_call : key_calls) { - if (key_call.type == kKeyCallOnKey && + if (key_call.type == KeyCall::kKeyCallOnKey && key_call.key_event.character != nullptr) { delete[] key_call.key_event.character; } @@ -363,7 +361,7 @@ class KeyboardTester { view_ = std::make_unique( [](const std::u16string& text) { key_calls.push_back(KeyCall{ - .type = kKeyCallOnText, + .type = KeyCall::kKeyCallOnText, .text = text, }); }, @@ -381,7 +379,7 @@ class KeyboardTester { ? nullptr : clone_string(event->character); key_calls.push_back(KeyCall{ - .type = kKeyCallOnKey, + .type = KeyCall::kKeyCallOnKey, .key_event = clone_event, }); callback_handler(event, callback); @@ -442,7 +440,7 @@ class KeyboardTester { rapidjson::Writer writer(buffer); document->Accept(writer); key_calls.push_back(KeyCall{ - .type = kKeyCallTextMethodCall, + .type = KeyCall::kKeyCallTextMethodCall, .text_method_call = buffer.GetString(), }); }); @@ -466,6 +464,8 @@ constexpr uint64_t kScanCodeBackquote = 0x29; constexpr uint64_t kScanCodeKeyA = 0x1e; constexpr uint64_t kScanCodeKeyB = 0x30; constexpr uint64_t kScanCodeKeyE = 0x12; +constexpr uint64_t kScanCodeKeyF = 0x21; +constexpr uint64_t kScanCodeKeyO = 0x18; constexpr uint64_t kScanCodeKeyQ = 0x10; constexpr uint64_t kScanCodeKeyW = 0x11; constexpr uint64_t kScanCodeDigit1 = 0x02; @@ -481,11 +481,14 @@ constexpr uint64_t kScanCodeShiftRight = 0x36; constexpr uint64_t kScanCodeBracketLeft = 0x1a; constexpr uint64_t kScanCodeArrowLeft = 0x4b; constexpr uint64_t kScanCodeEnter = 0x1c; +constexpr uint64_t kScanCodeBackspace = 0x0e; constexpr uint64_t kVirtualDigit1 = 0x31; constexpr uint64_t kVirtualKeyA = 0x41; constexpr uint64_t kVirtualKeyB = 0x42; constexpr uint64_t kVirtualKeyE = 0x45; +constexpr uint64_t kVirtualKeyF = 0x46; +constexpr uint64_t kVirtualKeyO = 0x4f; constexpr uint64_t kVirtualKeyQ = 0x51; constexpr uint64_t kVirtualKeyW = 0x57; @@ -498,15 +501,15 @@ constexpr bool kNotSynthesized = false; // stacktrace wouldn't print where the function is called in the unit tests. #define EXPECT_CALL_IS_EVENT(_key_call, ...) \ - EXPECT_EQ(_key_call.type, kKeyCallOnKey); \ + EXPECT_EQ(_key_call.type, KeyCall::kKeyCallOnKey); \ EXPECT_EVENT_EQUALS(_key_call.key_event, __VA_ARGS__); #define EXPECT_CALL_IS_TEXT(_key_call, u16_string) \ - EXPECT_EQ(_key_call.type, kKeyCallOnText); \ + EXPECT_EQ(_key_call.type, KeyCall::kKeyCallOnText); \ EXPECT_EQ(_key_call.text, u16_string); #define EXPECT_CALL_IS_TEXT_METHOD_CALL(_key_call, json_string) \ - EXPECT_EQ(_key_call.type, kKeyCallTextMethodCall); \ + EXPECT_EQ(_key_call.type, KeyCall::kKeyCallTextMethodCall); \ EXPECT_STREQ(_key_call.text_method_call.c_str(), json_string); TEST(KeyboardTest, LowerCaseAHandled) { @@ -1822,5 +1825,181 @@ TEST(KeyboardTest, TextInputSubmit) { clear_key_calls(); } +TEST(KeyboardTest, VietnameseTelexAddDiacriticWithFastResponse) { + // In this test, the user presses the folloing keys: + // + // Key Current text + // =========================== + // A a + // F à + // + // And the Backspace event is responded immediately. + + KeyboardTester tester; + tester.Responding(false); + + // US Keyboard layout + + // Press A + tester.InjectKeyboardChanges(std::vector{ + WmKeyDownInfo{kVirtualKeyA, kScanCodeKeyA, kNotExtended, kWasUp}.Build( + kWmResultZero), + WmCharInfo{'a', kScanCodeKeyA, kNotExtended, kWasUp}.Build( + kWmResultZero)}); + + EXPECT_EQ(key_calls.size(), 2); + EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, kPhysicalKeyA, + kLogicalKeyA, "a", kNotSynthesized); + EXPECT_CALL_IS_TEXT(key_calls[1], u"a"); + clear_key_calls(); + + // Release A + tester.InjectKeyboardChanges(std::vector{ + WmKeyUpInfo{kVirtualKeyA, kScanCodeKeyA, kNotExtended}.Build( + kWmResultZero)}); + + EXPECT_EQ(key_calls.size(), 1); + EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalKeyA, + kLogicalKeyA, "", kNotSynthesized); + clear_key_calls(); + + // Press F, which is translated to: + // + // Backspace down, char & up, then VK_PACKET('à'). + tester.InjectKeyboardChanges(std::vector{ + WmKeyDownInfo{VK_BACK, kScanCodeBackspace, kNotExtended, kWasUp}.Build( + kWmResultZero), + WmCharInfo{0x8, kScanCodeBackspace, kNotExtended, kWasUp}.Build( + kWmResultZero), + WmKeyUpInfo{VK_BACK, kScanCodeBackspace, kNotExtended}.Build( + kWmResultZero), + WmKeyDownInfo{VK_PACKET, 0, kNotExtended, kWasUp}.Build(kWmResultDefault), + WmCharInfo{0xe0/*'à'*/, 0, kNotExtended, kWasUp}.Build(kWmResultZero), + WmKeyUpInfo{VK_PACKET, 0, kNotExtended}.Build(kWmResultDefault) + }); + + EXPECT_EQ(key_calls.size(), 3); + EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, kPhysicalBackspace, + kLogicalBackspace, "", kNotSynthesized); + EXPECT_CALL_IS_EVENT(key_calls[1], kFlutterKeyEventTypeUp, kPhysicalBackspace, + kLogicalBackspace, "", kNotSynthesized); + EXPECT_CALL_IS_TEXT(key_calls[2], u"à"); + clear_key_calls(); + + // Release F + tester.InjectKeyboardChanges(std::vector{ + WmKeyUpInfo{kVirtualKeyF, kScanCodeKeyF, kNotExtended, + /* overwrite_prev_state_0 */ true}.Build(kWmResultZero)}); + + EXPECT_EQ(key_calls.size(), 1); + EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, 0, 0, "", + kNotSynthesized); + clear_key_calls(); +} + +void VietnameseTelexAddDiacriticWithSlowResponse(bool backspace_response) { + // In this test, the user presses the folloing keys: + // + // Key Current text + // =========================== + // A a + // F à + // + // And the Backspace down event is responded slowly with `backspace_response`. + + KeyboardTester tester; + tester.Responding(false); + + // US Keyboard layout + + // Press A + tester.InjectKeyboardChanges(std::vector{ + WmKeyDownInfo{kVirtualKeyA, kScanCodeKeyA, kNotExtended, kWasUp}.Build( + kWmResultZero), + WmCharInfo{'a', kScanCodeKeyA, kNotExtended, kWasUp}.Build( + kWmResultZero)}); + + EXPECT_EQ(key_calls.size(), 2); + EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, kPhysicalKeyA, + kLogicalKeyA, "a", kNotSynthesized); + EXPECT_CALL_IS_TEXT(key_calls[1], u"a"); + clear_key_calls(); + + // Release A + tester.InjectKeyboardChanges(std::vector{ + WmKeyUpInfo{kVirtualKeyA, kScanCodeKeyA, kNotExtended}.Build( + kWmResultZero)}); + + EXPECT_EQ(key_calls.size(), 1); + EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalKeyA, + kLogicalKeyA, "", kNotSynthesized); + clear_key_calls(); + + std::vector recorded_callbacks; + tester.LateResponding( + [&recorded_callbacks]( + const FlutterKeyEvent* event, + MockKeyResponseController::ResponseCallback callback) { + recorded_callbacks.push_back(callback); + }); + + // Press F, which is translated to: + // + // Backspace down, char & up, VK_PACKET('à'). + tester.InjectKeyboardChanges(std::vector{ + WmKeyDownInfo{VK_BACK, kScanCodeBackspace, kNotExtended, kWasUp}.Build( + kWmResultZero), + WmCharInfo{0x8, kScanCodeBackspace, kNotExtended, kWasUp}.Build( + kWmResultZero), + WmKeyUpInfo{VK_BACK, kScanCodeBackspace, kNotExtended}.Build( + kWmResultZero), + WmKeyDownInfo{VK_PACKET, 0, kNotExtended, kWasUp}.Build(kWmResultDefault), + WmCharInfo{0xe0/*'à'*/, 0, kNotExtended, kWasUp}.Build(kWmResultZero), + WmKeyUpInfo{VK_PACKET, 0, kNotExtended}.Build(kWmResultDefault) + }); + + // The Backspace event has not responded yet, therefore the char message must + // hold. This is because when the framework is handling the Backspace event, + // it will send a setEditingState message that updates the text state that has + // the last character deleted (denoted by `string1`). Processing the char + // message before then will cause the final text to set to `string1`. + EXPECT_EQ(key_calls.size(), 2); + EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, kPhysicalBackspace, + kLogicalBackspace, "", kNotSynthesized); + EXPECT_CALL_IS_EVENT(key_calls[1], kFlutterKeyEventTypeUp, kPhysicalBackspace, + kLogicalBackspace, "", kNotSynthesized); + clear_key_calls(); + + EXPECT_EQ(recorded_callbacks.size(), 2); + recorded_callbacks[0](true); + + EXPECT_EQ(key_calls.size(), 1); + EXPECT_CALL_IS_TEXT(key_calls[0], u"à"); + clear_key_calls(); + + recorded_callbacks[1](backspace_response); + EXPECT_EQ(key_calls.size(), 0); + + tester.Responding(false); + + // Release F + tester.InjectKeyboardChanges(std::vector{ + WmKeyUpInfo{kVirtualKeyF, kScanCodeKeyF, kNotExtended, + /* overwrite_prev_state_0 */ true}.Build(kWmResultZero)}); + + EXPECT_EQ(key_calls.size(), 1); + EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, 0, 0, "", + kNotSynthesized); + clear_key_calls(); +} + +TEST(KeyboardTest, VietnameseTelexAddDiacriticWithSlowFalseResponse) { + VietnameseTelexAddDiacriticWithSlowResponse(false); +} + +TEST(KeyboardTest, VietnameseTelexAddDiacriticWithSlowTrueResponse) { + VietnameseTelexAddDiacriticWithSlowResponse(true); +} + } // namespace testing } // namespace flutter From 671a244af78303781062f423f1b59b827bd4ae88 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Thu, 10 Feb 2022 14:11:03 -0800 Subject: [PATCH 17/22] Remove ShiftRight check and check redis count. RedispatchedMessageCountAndClear Add more tests. Problem with `handled` patching. Remove ComputeEventHash --- .../windows/keyboard_manager_win32.cc | 32 +------- .../platform/windows/keyboard_manager_win32.h | 17 ----- .../windows/keyboard_win32_unittests.cc | 75 +++++++++++++++++++ 3 files changed, 78 insertions(+), 46 deletions(-) diff --git a/shell/platform/windows/keyboard_manager_win32.cc b/shell/platform/windows/keyboard_manager_win32.cc index 6fcb8c59a2c9e..75ec2fff3958a 100644 --- a/shell/platform/windows/keyboard_manager_win32.cc +++ b/shell/platform/windows/keyboard_manager_win32.cc @@ -75,23 +75,6 @@ static bool IsKeyDownCtrlLeft(int action, int virtual_key) { #endif } -// Returns true if this key is a key down event of ShiftRight. -// -// This is a temporary solution to -// https://github.com/flutter/flutter/issues/81674, and forces ShiftRight -// KeyDown events to not be redispatched regardless of the framework's response. -// -// If a ShiftRight KeyDown event is not handled by the framework and is -// redispatched, Win32 will not send its following KeyUp event and keeps -// recording ShiftRight as being pressed. -static bool IsKeyDownShiftRight(int virtual_key, bool was_down) { -#ifdef WINUWP - return false; -#else - return virtual_key == VK_RSHIFT && !was_down; -#endif -} - // Returns if a character sent by Win32 is a dead key. static bool IsDeadKey(uint32_t ch) { return (ch & kDeadKeyCharMask) != 0; @@ -219,13 +202,12 @@ void KeyboardManagerWin32::HandleOnKeyResult( // and redispatches a normal character without combining it with the // next letter key. // - // Redispatching sys events is impossible due to the limitation of - // |SendInput|. + // Never redispatch sys keys, because their original messages are always + // passed to the system default processor. const bool is_syskey = event->action == WM_SYSKEYDOWN || event->action == WM_SYSKEYUP; const bool real_handled = handled || IsDeadKey(event->character) || - is_syskey || - IsKeyDownShiftRight(event->key, event->was_down); + is_syskey; // For handled events, that's all. // For unhandled events, dispatch them to OnText. @@ -447,12 +429,4 @@ UINT KeyboardManagerWin32::PeekNextMessageType(UINT wMsgFilterMin, return next_message.message; } -uint64_t KeyboardManagerWin32::ComputeEventHash(const PendingEvent& event) { - // Calculate a key event ID based on the scan code of the key pressed, - // and the flags we care about. - return event.scancode | (((event.action == WM_KEYUP ? KEYEVENTF_KEYUP : 0x0) | - (event.extended ? KEYEVENTF_EXTENDEDKEY : 0x0)) - << 16); -} - } // namespace flutter diff --git a/shell/platform/windows/keyboard_manager_win32.h b/shell/platform/windows/keyboard_manager_win32.h index 66da479454754..2af5ab72fdc95 100644 --- a/shell/platform/windows/keyboard_manager_win32.h +++ b/shell/platform/windows/keyboard_manager_win32.h @@ -205,23 +205,6 @@ class KeyboardManagerWin32 { // The queue of messages that have been redispatched to the system but have // not yet been received for a second time. std::deque pending_redispatches_; - - // Calculate a hash based on event data for fast comparison for a redispatched - // event. - // - // This uses event data instead of generating a serial number because - // information can't be attached to the redispatched events, so it has to be - // possible to compute an ID from the identifying data in the event when it is - // received again in order to differentiate between events that are new, and - // events that have been redispatched. - // - // Another alternative would be to compute a checksum from all the data in the - // event (just compute it over the bytes in the struct, probably skipping - // timestamps), but the fields used are enough to differentiate them, and - // since Windows does some processing on the events (coming up with virtual - // key codes, setting timestamps, etc.), it's not clear that the redispatched - // events would have the same checksums. - static uint64_t ComputeEventHash(const PendingEvent& event); }; } // namespace flutter diff --git a/shell/platform/windows/keyboard_win32_unittests.cc b/shell/platform/windows/keyboard_win32_unittests.cc index efd234c555c1e..1ddc9ace029a3 100644 --- a/shell/platform/windows/keyboard_win32_unittests.cc +++ b/shell/platform/windows/keyboard_win32_unittests.cc @@ -203,6 +203,10 @@ class MockKeyboardManagerWin32Delegate } } + std::list& RedispatchedMessages() { + return redispatched_messages_; + } + protected: BOOL Win32PeekMessage(LPMSG lpMsg, UINT wMsgFilterMin, @@ -231,6 +235,11 @@ class MockKeyboardManagerWin32Delegate UINT Win32DispatchMessage(UINT Msg, WPARAM wParam, LPARAM lParam) override { bool handled = keyboard_manager_->HandleMessage(Msg, wParam, lParam); if (keyboard_manager_->DuringRedispatch()) { + redispatched_messages_.push_back(Win32Message{ + .message = Msg, + .wParam = wParam, + .lParam = lParam, + }); EXPECT_FALSE(handled); } else { EXPECT_FALSE(forged_message_expectations_.empty()); @@ -263,6 +272,7 @@ class MockKeyboardManagerWin32Delegate std::list forged_message_expectations_; MapVkToCharHandler map_vk_to_char_; TestKeystate key_state_; + std::list redispatched_messages_; }; // A FlutterWindowsView that overrides the RegisterKeyboardHandlers function @@ -410,6 +420,13 @@ class KeyboardTester { window_->InjectKeyboardChanges(changes); } + size_t RedispatchedMessageCountAndClear() { + auto& messages = window_->RedispatchedMessages(); + size_t count = messages.size(); + messages.clear(); + return count; + } + private: std::unique_ptr view_; std::unique_ptr window_; @@ -529,6 +546,7 @@ TEST(KeyboardTest, LowerCaseAHandled) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, kPhysicalKeyA, kLogicalKeyA, "a", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0); // Release A tester.InjectKeyboardChanges(std::vector{ @@ -539,6 +557,7 @@ TEST(KeyboardTest, LowerCaseAHandled) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalKeyA, kLogicalKeyA, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0); } TEST(KeyboardTest, LowerCaseAUnhandled) { @@ -559,6 +578,7 @@ TEST(KeyboardTest, LowerCaseAUnhandled) { kLogicalKeyA, "a", kNotSynthesized); EXPECT_CALL_IS_TEXT(key_calls[1], u"a"); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2); // Release A tester.InjectKeyboardChanges(std::vector{ @@ -569,6 +589,7 @@ TEST(KeyboardTest, LowerCaseAUnhandled) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalKeyA, kLogicalKeyA, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); } TEST(KeyboardTest, ArrowLeftHandled) { @@ -587,6 +608,7 @@ TEST(KeyboardTest, ArrowLeftHandled) { kPhysicalArrowLeft, kLogicalArrowLeft, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0); // Release ArrowLeft tester.InjectKeyboardChanges(std::vector{ @@ -597,6 +619,7 @@ TEST(KeyboardTest, ArrowLeftHandled) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalArrowLeft, kLogicalArrowLeft, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0); } TEST(KeyboardTest, ArrowLeftUnhandled) { @@ -615,6 +638,7 @@ TEST(KeyboardTest, ArrowLeftUnhandled) { kPhysicalArrowLeft, kLogicalArrowLeft, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); // Release ArrowLeft tester.InjectKeyboardChanges(std::vector{ @@ -625,6 +649,7 @@ TEST(KeyboardTest, ArrowLeftUnhandled) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalArrowLeft, kLogicalArrowLeft, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); } TEST(KeyboardTest, ShiftLeftUnhandled) { @@ -644,6 +669,7 @@ TEST(KeyboardTest, ShiftLeftUnhandled) { kPhysicalShiftLeft, kLogicalShiftLeft, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); // Release ShiftLeft tester.InjectKeyboardChanges(std::vector{ @@ -655,6 +681,7 @@ TEST(KeyboardTest, ShiftLeftUnhandled) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalShiftLeft, kLogicalShiftLeft, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); } TEST(KeyboardTest, ShiftRightUnhandled) { @@ -674,6 +701,7 @@ TEST(KeyboardTest, ShiftRightUnhandled) { kPhysicalShiftRight, kLogicalShiftRight, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); // Release ShiftRight tester.InjectKeyboardChanges(std::vector{ @@ -686,6 +714,7 @@ TEST(KeyboardTest, ShiftRightUnhandled) { kPhysicalShiftRight, kLogicalShiftRight, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); } TEST(KeyboardTest, CtrlLeftUnhandled) { @@ -705,6 +734,7 @@ TEST(KeyboardTest, CtrlLeftUnhandled) { kPhysicalControlLeft, kLogicalControlLeft, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); // Release CtrlLeft tester.InjectKeyboardChanges(std::vector{ @@ -717,6 +747,7 @@ TEST(KeyboardTest, CtrlLeftUnhandled) { kPhysicalControlLeft, kLogicalControlLeft, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); } TEST(KeyboardTest, CtrlRightUnhandled) { @@ -736,6 +767,7 @@ TEST(KeyboardTest, CtrlRightUnhandled) { kPhysicalControlRight, kLogicalControlRight, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); // Release CtrlRight tester.InjectKeyboardChanges(std::vector{ @@ -748,6 +780,7 @@ TEST(KeyboardTest, CtrlRightUnhandled) { kPhysicalControlRight, kLogicalControlRight, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); } TEST(KeyboardTest, AltLeftUnhandled) { @@ -766,6 +799,8 @@ TEST(KeyboardTest, AltLeftUnhandled) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, kPhysicalAltLeft, kLogicalAltLeft, "", kNotSynthesized); clear_key_calls(); + // Don't redispatch sys messages. + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0); // Release AltLeft. AltLeft is a SysKeyUp event. tester.InjectKeyboardChanges(std::vector{ @@ -777,6 +812,8 @@ TEST(KeyboardTest, AltLeftUnhandled) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalAltLeft, kLogicalAltLeft, "", kNotSynthesized); clear_key_calls(); + // Don't redispatch sys messages. + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0); } TEST(KeyboardTest, AltRightUnhandled) { @@ -796,6 +833,8 @@ TEST(KeyboardTest, AltRightUnhandled) { kPhysicalAltRight, kLogicalAltRight, "", kNotSynthesized); clear_key_calls(); + // Don't redispatch sys messages. + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0); // Release AltRight. AltRight is a SysKeyUp event. tester.InjectKeyboardChanges(std::vector{ @@ -807,6 +846,8 @@ TEST(KeyboardTest, AltRightUnhandled) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalAltRight, kLogicalAltRight, "", kNotSynthesized); clear_key_calls(); + // Don't redispatch sys messages. + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0); } TEST(KeyboardTest, MetaLeftUnhandled) { @@ -826,6 +867,7 @@ TEST(KeyboardTest, MetaLeftUnhandled) { kPhysicalMetaLeft, kLogicalMetaLeft, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); // Release MetaLeft tester.InjectKeyboardChanges(std::vector{ @@ -836,6 +878,7 @@ TEST(KeyboardTest, MetaLeftUnhandled) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalMetaLeft, kLogicalMetaLeft, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); } TEST(KeyboardTest, MetaRightUnhandled) { @@ -855,6 +898,7 @@ TEST(KeyboardTest, MetaRightUnhandled) { kPhysicalMetaRight, kLogicalMetaRight, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); // Release MetaRight tester.InjectKeyboardChanges(std::vector{ @@ -866,6 +910,7 @@ TEST(KeyboardTest, MetaRightUnhandled) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalMetaRight, kLogicalMetaRight, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); } // Press Shift-A. This is special because Win32 gives 'A' as character for the @@ -887,6 +932,7 @@ TEST(KeyboardTest, ShiftLeftKeyA) { kPhysicalShiftLeft, kLogicalShiftLeft, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); // Press A tester.InjectKeyboardChanges(std::vector{ @@ -900,6 +946,7 @@ TEST(KeyboardTest, ShiftLeftKeyA) { kLogicalKeyA, "A", kNotSynthesized); EXPECT_CALL_IS_TEXT(key_calls[1], u"A"); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2); // Release ShiftLeft tester.InjectKeyboardChanges(std::vector{ @@ -911,6 +958,7 @@ TEST(KeyboardTest, ShiftLeftKeyA) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalShiftLeft, kLogicalShiftLeft, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); // Release A tester.InjectKeyboardChanges(std::vector{ @@ -921,6 +969,7 @@ TEST(KeyboardTest, ShiftLeftKeyA) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalKeyA, kLogicalKeyA, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); } // Press Ctrl-A. This is special because Win32 gives 0x01 as character for the @@ -942,6 +991,7 @@ TEST(KeyboardTest, CtrlLeftKeyA) { kPhysicalControlLeft, kLogicalControlLeft, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); // Press A tester.InjectKeyboardChanges(std::vector{ @@ -954,6 +1004,7 @@ TEST(KeyboardTest, CtrlLeftKeyA) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, kPhysicalKeyA, kLogicalKeyA, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2); // Release A tester.InjectKeyboardChanges(std::vector{ @@ -964,6 +1015,7 @@ TEST(KeyboardTest, CtrlLeftKeyA) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalKeyA, kLogicalKeyA, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); // Release ControlLeft tester.InjectKeyboardChanges(std::vector{ @@ -976,6 +1028,7 @@ TEST(KeyboardTest, CtrlLeftKeyA) { kPhysicalControlLeft, kLogicalControlLeft, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); } // Press Ctrl-1. This is special because it yields no WM_CHAR for the 1. @@ -996,6 +1049,7 @@ TEST(KeyboardTest, CtrlLeftDigit1) { kPhysicalControlLeft, kLogicalControlLeft, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); // Press 1 tester.InjectKeyboardChanges(std::vector{ @@ -1006,6 +1060,7 @@ TEST(KeyboardTest, CtrlLeftDigit1) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, kPhysicalDigit1, kLogicalDigit1, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); // Release 1 tester.InjectKeyboardChanges(std::vector{ @@ -1016,6 +1071,7 @@ TEST(KeyboardTest, CtrlLeftDigit1) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalDigit1, kLogicalDigit1, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); // Release ControlLeft tester.InjectKeyboardChanges(std::vector{ @@ -1028,6 +1084,7 @@ TEST(KeyboardTest, CtrlLeftDigit1) { kPhysicalControlLeft, kLogicalControlLeft, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); } // Press 1 on a French keyboard. This is special because it yields WM_CHAR @@ -1050,6 +1107,7 @@ TEST(KeyboardTest, Digit1OnFrenchLayout) { kLogicalDigit1, "&", kNotSynthesized); EXPECT_CALL_IS_TEXT(key_calls[1], u"&"); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2); // Release 1 tester.InjectKeyboardChanges(std::vector{ @@ -1060,6 +1118,7 @@ TEST(KeyboardTest, Digit1OnFrenchLayout) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalDigit1, kLogicalDigit1, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); } // This tests AltGr-Q on a German keyboard, which should print '@'. @@ -1086,6 +1145,7 @@ TEST(KeyboardTest, AltGrModifiedKey) { kPhysicalAltRight, kLogicalAltRight, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2); // Press Q tester.InjectKeyboardChanges(std::vector{ @@ -1099,6 +1159,7 @@ TEST(KeyboardTest, AltGrModifiedKey) { kLogicalKeyQ, "@", kNotSynthesized); EXPECT_CALL_IS_TEXT(key_calls[1], u"@"); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2); // Release Q tester.InjectKeyboardChanges(std::vector{ @@ -1109,6 +1170,7 @@ TEST(KeyboardTest, AltGrModifiedKey) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalKeyQ, kLogicalKeyQ, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); // Release AltGr. Win32 doesn't dispatch ControlLeft up. Instead Flutter will // forge one. The AltGr is a system key, therefore will be handled by Win32's @@ -1129,6 +1191,8 @@ TEST(KeyboardTest, AltGrModifiedKey) { EXPECT_CALL_IS_EVENT(key_calls[1], kFlutterKeyEventTypeUp, kPhysicalAltRight, kLogicalAltRight, "", kNotSynthesized); clear_key_calls(); + // The sys key up must not be redispatched. The forged ControlLeft up will. + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); } // Test the following two key sequences at the same time: @@ -1168,6 +1232,7 @@ TEST(KeyboardTest, AltGrTwice) { kPhysicalAltRight, kLogicalAltRight, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2); // 2. AltGr up. @@ -1187,6 +1252,8 @@ TEST(KeyboardTest, AltGrTwice) { EXPECT_CALL_IS_EVENT(key_calls[1], kFlutterKeyEventTypeUp, kPhysicalAltRight, kLogicalAltRight, "", kNotSynthesized); clear_key_calls(); + // The sys key up must not be redispatched. The forged ControlLeft up will. + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); // 3. AltGr down (or: ControlLeft down then AltRight down.) @@ -1206,6 +1273,7 @@ TEST(KeyboardTest, AltGrTwice) { kPhysicalAltRight, kLogicalAltRight, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2); // 4. AltGr up. @@ -1225,6 +1293,8 @@ TEST(KeyboardTest, AltGrTwice) { EXPECT_CALL_IS_EVENT(key_calls[1], kFlutterKeyEventTypeUp, kPhysicalAltRight, kLogicalAltRight, "", kNotSynthesized); clear_key_calls(); + // The sys key up must not be redispatched. The forged ControlLeft up will. + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); // 5. For key sequence 2: a real ControlLeft up. tester.InjectKeyboardChanges(std::vector{ @@ -1234,6 +1304,7 @@ TEST(KeyboardTest, AltGrTwice) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, 0, 0, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0); } // This tests dead key ^ then E on a French keyboard, which should be combined @@ -1256,6 +1327,7 @@ TEST(KeyboardTest, DeadKeyThatCombines) { kPhysicalBracketLeft, kLogicalBracketRight, "^", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2); // Release ^¨ tester.InjectKeyboardChanges(std::vector{ @@ -1267,6 +1339,7 @@ TEST(KeyboardTest, DeadKeyThatCombines) { kPhysicalBracketLeft, kLogicalBracketRight, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); // Press E tester.InjectKeyboardChanges(std::vector{ @@ -1280,6 +1353,7 @@ TEST(KeyboardTest, DeadKeyThatCombines) { kLogicalKeyE, "ê", kNotSynthesized); EXPECT_CALL_IS_TEXT(key_calls[1], u"ê"); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2); // Release E tester.InjectKeyboardChanges(std::vector{ @@ -1290,6 +1364,7 @@ TEST(KeyboardTest, DeadKeyThatCombines) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalKeyE, kLogicalKeyE, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); } // This tests dead key ^ then E on a US INTL keyboard, which should be combined From 036415d8d76e5568d3baa1913d678f35e319fe4b Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Fri, 11 Feb 2022 18:07:56 -0800 Subject: [PATCH 18/22] Fix compile --- shell/platform/windows/keyboard_win32_unittests.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/platform/windows/keyboard_win32_unittests.cc b/shell/platform/windows/keyboard_win32_unittests.cc index 1ddc9ace029a3..4d59571633281 100644 --- a/shell/platform/windows/keyboard_win32_unittests.cc +++ b/shell/platform/windows/keyboard_win32_unittests.cc @@ -337,7 +337,7 @@ class TestFlutterWindowsView : public FlutterWindowsView { KeyboardKeyEmbedderHandler::GetKeyStateHandler get_keyboard_state_; }; -struct { +typedef struct { enum { kKeyCallOnKey, kKeyCallOnText, From e3a58629a71d95edf09eafbdb78cc691196ce228 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Fri, 11 Feb 2022 18:20:54 -0800 Subject: [PATCH 19/22] Move sys filter. Remove dead key filter. --- .../windows/keyboard_manager_win32.cc | 28 ++++++------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/shell/platform/windows/keyboard_manager_win32.cc b/shell/platform/windows/keyboard_manager_win32.cc index 75ec2fff3958a..d6b5a5410bd7e 100644 --- a/shell/platform/windows/keyboard_manager_win32.cc +++ b/shell/platform/windows/keyboard_manager_win32.cc @@ -119,6 +119,13 @@ KeyboardManagerWin32::KeyboardManagerWin32(WindowDelegate* delegate) void KeyboardManagerWin32::RedispatchEvent( std::unique_ptr event) { for (const Win32Message& message : event->session) { + // Never redispatch sys keys, because their original messages have been + // passed to the system default processor. + const bool is_syskey = + message.action == WM_SYSKEYDOWN || message.action == WM_SYSKEYUP; + if (is_syskey) { + continue; + } pending_redispatches_.push_back(message); UINT result = window_delegate_->Win32DispatchMessage( message.action, message.wparam, message.lparam); @@ -195,25 +202,8 @@ void KeyboardManagerWin32::HandleOnKeyResult( std::unique_ptr event, bool handled, std::list::iterator pending_text) { - // First, patch |handled|, because some key events must always be treated as - // handled. - // - // Redispatching dead keys events makes Win32 ignore the dead key state - // and redispatches a normal character without combining it with the - // next letter key. - // - // Never redispatch sys keys, because their original messages are always - // passed to the system default processor. - const bool is_syskey = - event->action == WM_SYSKEYDOWN || event->action == WM_SYSKEYUP; - const bool real_handled = handled || IsDeadKey(event->character) || - is_syskey; - - // For handled events, that's all. - // For unhandled events, dispatch them to OnText. - if (pending_text != pending_texts_.end()) { - if (pending_text->placeholder || real_handled) { + if (pending_text->placeholder || handled) { pending_texts_.erase(pending_text); } else { pending_text->ready = true; @@ -221,7 +211,7 @@ void KeyboardManagerWin32::HandleOnKeyResult( DispatchReadyTexts(); } - if (real_handled) { + if (handled) { return; } From cc058b3330fa589a98666ec27ac3d1a1977217ab Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Sat, 12 Feb 2022 05:40:52 -0800 Subject: [PATCH 20/22] Complete tests --- .../windows/keyboard_win32_unittests.cc | 92 +++++++++++++------ 1 file changed, 66 insertions(+), 26 deletions(-) diff --git a/shell/platform/windows/keyboard_win32_unittests.cc b/shell/platform/windows/keyboard_win32_unittests.cc index 4d59571633281..e9c69256dea41 100644 --- a/shell/platform/windows/keyboard_win32_unittests.cc +++ b/shell/platform/windows/keyboard_win32_unittests.cc @@ -420,6 +420,8 @@ class KeyboardTester { window_->InjectKeyboardChanges(changes); } + // Get the number of redispatched messages since the last clear, then clear + // the counter. size_t RedispatchedMessageCountAndClear() { auto& messages = window_->RedispatchedMessages(); size_t count = messages.size(); @@ -1387,6 +1389,7 @@ TEST(KeyboardTest, DeadKeyWithoutDeadMaskThatCombines) { kPhysicalShiftLeft, kLogicalShiftLeft, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); // Press 6^ tester.InjectKeyboardChanges(std::vector{ @@ -1399,6 +1402,7 @@ TEST(KeyboardTest, DeadKeyWithoutDeadMaskThatCombines) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, kPhysicalDigit6, kLogicalDigit6, "6", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2); // Release 6^ tester.InjectKeyboardChanges(std::vector{ @@ -1408,6 +1412,7 @@ TEST(KeyboardTest, DeadKeyWithoutDeadMaskThatCombines) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalDigit6, kLogicalDigit6, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); // Release ShiftLeft tester.InjectKeyboardChanges(std::vector{ @@ -1419,6 +1424,7 @@ TEST(KeyboardTest, DeadKeyWithoutDeadMaskThatCombines) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalShiftLeft, kLogicalShiftLeft, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); // Press E tester.InjectKeyboardChanges(std::vector{ @@ -1432,6 +1438,7 @@ TEST(KeyboardTest, DeadKeyWithoutDeadMaskThatCombines) { kLogicalKeyE, "ê", kNotSynthesized); EXPECT_CALL_IS_TEXT(key_calls[1], u"ê"); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2); // Release E tester.InjectKeyboardChanges(std::vector{ @@ -1442,6 +1449,7 @@ TEST(KeyboardTest, DeadKeyWithoutDeadMaskThatCombines) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalKeyE, kLogicalKeyE, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); } // This tests dead key ^ then & (US: 1) on a French keyboard, which do not @@ -1464,6 +1472,7 @@ TEST(KeyboardTest, DeadKeyThatDoesNotCombine) { kPhysicalBracketLeft, kLogicalBracketRight, "^", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2); // Release ^¨ tester.InjectKeyboardChanges(std::vector{ @@ -1475,6 +1484,7 @@ TEST(KeyboardTest, DeadKeyThatDoesNotCombine) { kPhysicalBracketLeft, kLogicalBracketRight, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); // Press 1 tester.InjectKeyboardChanges(std::vector{ @@ -1491,6 +1501,12 @@ TEST(KeyboardTest, DeadKeyThatDoesNotCombine) { EXPECT_CALL_IS_TEXT(key_calls[1], u"^"); EXPECT_CALL_IS_TEXT(key_calls[2], u"&"); clear_key_calls(); + // TODO(dkwingsmt): This count should probably be 3. Currently the '^' + // message is redispatched due to being part of the KeyDown session, which is + // not handled by the framework, while the '&' message is not redispatched + // for being a standalone message. We should resolve this inconsistency. + // https://github.com/flutter/flutter/issues/98306 + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2); // Release 1 tester.InjectKeyboardChanges(std::vector{ @@ -1501,6 +1517,7 @@ TEST(KeyboardTest, DeadKeyThatDoesNotCombine) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalDigit1, kLogicalDigit1, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); } // This tests dead key `, then dead key `, then e. @@ -1524,6 +1541,7 @@ TEST(KeyboardTest, DeadKeyTwiceThenLetter) { kPhysicalBackquote, kLogicalBackquote, "`", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2); // Release ` tester.InjectKeyboardChanges(std::vector{ @@ -1534,6 +1552,7 @@ TEST(KeyboardTest, DeadKeyTwiceThenLetter) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalBackquote, kLogicalBackquote, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); // Press ` again. // The response should be slow. @@ -1566,6 +1585,10 @@ TEST(KeyboardTest, DeadKeyTwiceThenLetter) { EXPECT_CALL_IS_TEXT(key_calls[0], u"`"); EXPECT_CALL_IS_TEXT(key_calls[1], u"`"); clear_key_calls(); + // TODO(dkwingsmt): This count should probably be 3. See the comment above + // that is marked with the same issue. + // https://github.com/flutter/flutter/issues/98306 + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2); tester.Responding(false); @@ -1578,6 +1601,7 @@ TEST(KeyboardTest, DeadKeyTwiceThenLetter) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalBackquote, kLogicalBackquote, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); } // This tests when the resulting character needs to be combined with surrogates. @@ -1604,6 +1628,7 @@ TEST(KeyboardTest, MultibyteCharacter) { kLogicalKeyW, "𐍅", kNotSynthesized); EXPECT_CALL_IS_TEXT(key_calls[1], u"𐍅"); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 3); // Release W tester.InjectKeyboardChanges(std::vector{ @@ -1614,39 +1639,21 @@ TEST(KeyboardTest, MultibyteCharacter) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalKeyW, kLogicalKeyW, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); } -// A key down event for shift right must not be redispatched even if -// the framework returns unhandled. -// -// The reason for this test is documented in |IsKeyDownShiftRight|. -TEST(KeyboardTest, NeverRedispatchShiftRightKeyDown) { - KeyboardTester tester; - tester.Responding(false); - - // Press ShiftRight and the delegate responds false. - tester.InjectKeyboardChanges(std::vector{ - KeyStateChange{VK_RSHIFT, true, true}, - WmKeyDownInfo{VK_SHIFT, kScanCodeShiftRight, kNotExtended, kWasUp}.Build( - kWmResultZero)}); - - EXPECT_EQ(key_calls.size(), 1); - clear_key_calls(); -} - -// Pressing modifiers during IME events should work properly by not sending any -// events. +// Pressing extended keys during IME events should work properly by not sending +// any events. // // Regression test for https://github.com/flutter/flutter/issues/95888 . -TEST(KeyboardTest, ImeModifierEventsAreIgnored) { +TEST(KeyboardTest, ImeExtendedEventsAreIgnored) { KeyboardTester tester; tester.Responding(false); // US Keyboard layout. - // To make the keyboard into IME mode, there should have been events like - // letter key down with VK_PROCESSKEY. Omit them in this test since they don't - // seem significant. + // There should be preceding key events to make the keyboard into IME mode. + // Omit them in this test since they are not relavent. // Press CtrlRight in IME mode. tester.InjectKeyboardChanges(std::vector{ @@ -1658,6 +1665,7 @@ TEST(KeyboardTest, ImeModifierEventsAreIgnored) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, 0, 0, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0); } TEST(KeyboardTest, DisorderlyRespondedEvents) { @@ -1689,12 +1697,17 @@ TEST(KeyboardTest, DisorderlyRespondedEvents) { EXPECT_EQ(key_calls.size(), 2); EXPECT_EQ(recorded_callbacks.size(), 2); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0); // Resolve the second event first to test disordered responses. recorded_callbacks.back()(false); EXPECT_EQ(key_calls.size(), 0); clear_key_calls(); + // TODO(dkwingsmt): This should probably be 0. Redispatching the messages of + // the second event this early means that the messages are not redispatched + // in the order of arrival. https://github.com/flutter/flutter/issues/98308 + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2); // Resolve the first event. recorded_callbacks.front()(false); @@ -1703,6 +1716,7 @@ TEST(KeyboardTest, DisorderlyRespondedEvents) { EXPECT_CALL_IS_TEXT(key_calls[0], u"a"); EXPECT_CALL_IS_TEXT(key_calls[1], u"b"); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2); } // Regression test for a crash in an earlier implementation. @@ -1741,6 +1755,7 @@ TEST(KeyboardTest, SlowFrameworkResponse) { EXPECT_EQ(key_calls.size(), 2); EXPECT_EQ(recorded_callbacks.size(), 2); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0); // The first response. recorded_callbacks.front()(false); @@ -1748,6 +1763,7 @@ TEST(KeyboardTest, SlowFrameworkResponse) { EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_TEXT(key_calls[0], u"a"); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2); // The second response. recorded_callbacks.back()(false); @@ -1755,6 +1771,7 @@ TEST(KeyboardTest, SlowFrameworkResponse) { EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_TEXT(key_calls[0], u"a"); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2); } // Regression test for https://github.com/flutter/flutter/issues/84210. @@ -1792,6 +1809,7 @@ TEST(KeyboardTest, SlowFrameworkResponseForIdenticalEvents) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, kPhysicalKeyA, kLogicalKeyA, "a", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0); // Release A tester.InjectKeyboardChanges(std::vector{ @@ -1802,6 +1820,7 @@ TEST(KeyboardTest, SlowFrameworkResponseForIdenticalEvents) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalKeyA, kLogicalKeyA, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0); // The first down event responded with false. EXPECT_EQ(recorded_callbacks.size(), 2); @@ -1810,6 +1829,7 @@ TEST(KeyboardTest, SlowFrameworkResponseForIdenticalEvents) { EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_TEXT(key_calls[0], u"a"); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2); // Press A again tester.InjectKeyboardChanges(std::vector{ @@ -1822,6 +1842,7 @@ TEST(KeyboardTest, SlowFrameworkResponseForIdenticalEvents) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, kPhysicalKeyA, kLogicalKeyA, "a", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0); // Release A again tester.InjectKeyboardChanges(std::vector{ @@ -1832,6 +1853,7 @@ TEST(KeyboardTest, SlowFrameworkResponseForIdenticalEvents) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalKeyA, kLogicalKeyA, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0); } TEST(KeyboardTest, TextInputSubmit) { @@ -1861,6 +1883,7 @@ TEST(KeyboardTest, TextInputSubmit) { R"|("args":[108,"TextInputAction.none"])|" "}"); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2); // Release Enter tester.InjectKeyboardChanges(std::vector{ @@ -1871,6 +1894,7 @@ TEST(KeyboardTest, TextInputSubmit) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalEnter, kLogicalEnter, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); // Make sure OnText is not obstructed after pressing Enter. // @@ -1888,6 +1912,7 @@ TEST(KeyboardTest, TextInputSubmit) { kLogicalKeyA, "a", kNotSynthesized); EXPECT_CALL_IS_TEXT(key_calls[1], u"a"); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2); // Release A tester.InjectKeyboardChanges(std::vector{ @@ -1898,6 +1923,7 @@ TEST(KeyboardTest, TextInputSubmit) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalKeyA, kLogicalKeyA, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); } TEST(KeyboardTest, VietnameseTelexAddDiacriticWithFastResponse) { @@ -1921,6 +1947,7 @@ TEST(KeyboardTest, VietnameseTelexAddDiacriticWithFastResponse) { kWmResultZero), WmCharInfo{'a', kScanCodeKeyA, kNotExtended, kWasUp}.Build( kWmResultZero)}); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2); EXPECT_EQ(key_calls.size(), 2); EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, kPhysicalKeyA, @@ -1937,6 +1964,7 @@ TEST(KeyboardTest, VietnameseTelexAddDiacriticWithFastResponse) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalKeyA, kLogicalKeyA, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); // Press F, which is translated to: // @@ -1960,6 +1988,8 @@ TEST(KeyboardTest, VietnameseTelexAddDiacriticWithFastResponse) { kLogicalBackspace, "", kNotSynthesized); EXPECT_CALL_IS_TEXT(key_calls[2], u"à"); clear_key_calls(); + // The VK_PACKET messages and the standalone WM_CHAR are not redispatched. + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 3); // Release F tester.InjectKeyboardChanges(std::vector{ @@ -1970,6 +2000,7 @@ TEST(KeyboardTest, VietnameseTelexAddDiacriticWithFastResponse) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, 0, 0, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0); } void VietnameseTelexAddDiacriticWithSlowResponse(bool backspace_response) { @@ -1999,6 +2030,7 @@ void VietnameseTelexAddDiacriticWithSlowResponse(bool backspace_response) { kLogicalKeyA, "a", kNotSynthesized); EXPECT_CALL_IS_TEXT(key_calls[1], u"a"); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 2); // Release A tester.InjectKeyboardChanges(std::vector{ @@ -2009,6 +2041,7 @@ void VietnameseTelexAddDiacriticWithSlowResponse(bool backspace_response) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeUp, kPhysicalKeyA, kLogicalKeyA, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); std::vector recorded_callbacks; tester.LateResponding( @@ -2044,16 +2077,22 @@ void VietnameseTelexAddDiacriticWithSlowResponse(bool backspace_response) { EXPECT_CALL_IS_EVENT(key_calls[1], kFlutterKeyEventTypeUp, kPhysicalBackspace, kLogicalBackspace, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0); + // The two pending callbacks are Backspace keydown and Backspace keyup + // respectively. EXPECT_EQ(recorded_callbacks.size(), 2); - recorded_callbacks[0](true); + recorded_callbacks[0](backspace_response); EXPECT_EQ(key_calls.size(), 1); EXPECT_CALL_IS_TEXT(key_calls[0], u"à"); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), + backspace_response ? 0 : 2); - recorded_callbacks[1](backspace_response); + recorded_callbacks[1](false); EXPECT_EQ(key_calls.size(), 0); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); tester.Responding(false); @@ -2066,6 +2105,7 @@ void VietnameseTelexAddDiacriticWithSlowResponse(bool backspace_response) { EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeDown, 0, 0, "", kNotSynthesized); clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 0); } TEST(KeyboardTest, VietnameseTelexAddDiacriticWithSlowFalseResponse) { From ed4967a6781cca43fe0be13912eb08e2dba6dabd Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 14 Feb 2022 14:06:18 -0800 Subject: [PATCH 21/22] Comment --- shell/platform/windows/keyboard_win32_unittests.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/shell/platform/windows/keyboard_win32_unittests.cc b/shell/platform/windows/keyboard_win32_unittests.cc index 82c51c979a3fb..531b71e2409ca 100644 --- a/shell/platform/windows/keyboard_win32_unittests.cc +++ b/shell/platform/windows/keyboard_win32_unittests.cc @@ -354,6 +354,7 @@ class KeyboardTester { void SetLayout(MapVkToCharHandler layout) { window_->SetLayout(layout); } void InjectKeyboardChanges(std::vector changes) { + assert(window_ != null, "Window not initialized yet."); window_->InjectKeyboardChanges(changes); } From b565eb54a93439273c4f6171a4d91b760c49f2da Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 15 Feb 2022 01:47:46 -0800 Subject: [PATCH 22/22] Remove unnecessary changes --- shell/platform/windows/keyboard_key_embedder_handler.cc | 8 -------- shell/platform/windows/keyboard_win32_unittests.cc | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/shell/platform/windows/keyboard_key_embedder_handler.cc b/shell/platform/windows/keyboard_key_embedder_handler.cc index a5f3a7f3e477e..ca8e5a9cdadfd 100644 --- a/shell/platform/windows/keyboard_key_embedder_handler.cc +++ b/shell/platform/windows/keyboard_key_embedder_handler.cc @@ -457,14 +457,6 @@ void KeyboardKeyEmbedderHandler::InitCriticalKeys() { createCheckedKey(VK_LCONTROL, false, true, false)); critical_keys_.emplace(VK_RCONTROL, createCheckedKey(VK_RCONTROL, true, true, false)); - critical_keys_.emplace(VK_LMENU, - createCheckedKey(VK_LMENU, false, true, false)); - critical_keys_.emplace(VK_RMENU, - createCheckedKey(VK_RMENU, true, true, false)); - critical_keys_.emplace(VK_LWIN, - createCheckedKey(VK_LWIN, false, true, false)); - critical_keys_.emplace(VK_RWIN, - createCheckedKey(VK_RWIN, false, true, false)); critical_keys_.emplace(VK_CAPITAL, createCheckedKey(VK_CAPITAL, false, true, true)); diff --git a/shell/platform/windows/keyboard_win32_unittests.cc b/shell/platform/windows/keyboard_win32_unittests.cc index 031ef22d8d76a..d2f68a77be157 100644 --- a/shell/platform/windows/keyboard_win32_unittests.cc +++ b/shell/platform/windows/keyboard_win32_unittests.cc @@ -21,8 +21,8 @@ #include "rapidjson/writer.h" #include -#include #include +#include using testing::_; using testing::Invoke;