diff --git a/shell/platform/windows/flutter_windows_engine.cc b/shell/platform/windows/flutter_windows_engine.cc index 19fd30d41783b..71897bc727f68 100644 --- a/shell/platform/windows/flutter_windows_engine.cc +++ b/shell/platform/windows/flutter_windows_engine.cc @@ -257,6 +257,10 @@ bool FlutterWindowsEngine::RunWithEntrypoint(const char* entrypoint) { auto host = static_cast(user_data); return host->HandlePlatformMessage(engine_message); }; + args.on_pre_engine_restart_callback = [](void* user_data) { + auto host = static_cast(user_data); + host->view()->OnPreEngineRestart(); + }; args.custom_task_runners = &custom_task_runners; diff --git a/shell/platform/windows/flutter_windows_view.cc b/shell/platform/windows/flutter_windows_view.cc index ac4e0e5e1341e..268fa29606387 100644 --- a/shell/platform/windows/flutter_windows_view.cc +++ b/shell/platform/windows/flutter_windows_view.cc @@ -55,17 +55,7 @@ void FlutterWindowsView::SetEngine( // Set up the system channel handlers. auto internal_plugin_messenger = internal_plugin_registrar_->messenger(); -#ifdef WINUWP - flutter::KeyboardKeyHandler::EventDispatcher dispatch_event = nullptr; - flutter::KeyboardKeyEmbedderHandler::GetKeyStateHandler get_key_state = - nullptr; -#else - flutter::KeyboardKeyHandler::EventDispatcher dispatch_event = SendInput; - flutter::KeyboardKeyEmbedderHandler::GetKeyStateHandler get_key_state = - GetKeyState; -#endif - RegisterKeyboardHandlers(internal_plugin_messenger, dispatch_event, - get_key_state); + InitializeKeyboard(); platform_handler_ = PlatformHandler::Create(internal_plugin_messenger, this); cursor_handler_ = std::make_unique( internal_plugin_messenger, binding_handler_.get()); @@ -137,6 +127,11 @@ void FlutterWindowsView::ForceRedraw() { } } +void FlutterWindowsView::OnPreEngineRestart() { + keyboard_handlers_.clear(); + InitializeKeyboard(); +} + void FlutterWindowsView::OnWindowSizeChanged(size_t width, size_t height) { // Called on the platform thread. std::unique_lock lock(resize_mutex_); @@ -257,6 +252,21 @@ void FlutterWindowsView::OnCursorRectUpdated(const Rect& rect) { binding_handler_->OnCursorRectUpdated(rect); } +void FlutterWindowsView::InitializeKeyboard() { + auto internal_plugin_messenger = internal_plugin_registrar_->messenger(); +#ifdef WINUWP + flutter::KeyboardKeyHandler::EventDispatcher dispatch_event = nullptr; + flutter::KeyboardKeyEmbedderHandler::GetKeyStateHandler get_key_state = + nullptr; +#else + flutter::KeyboardKeyHandler::EventDispatcher dispatch_event = SendInput; + flutter::KeyboardKeyEmbedderHandler::GetKeyStateHandler get_key_state = + GetKeyState; +#endif + RegisterKeyboardHandlers(internal_plugin_messenger, dispatch_event, + get_key_state); +} + // Sends new size information to FlutterEngine. void FlutterWindowsView::SendWindowMetrics(size_t width, size_t height, diff --git a/shell/platform/windows/flutter_windows_view.h b/shell/platform/windows/flutter_windows_view.h index a50e908ef3102..2fc4a83af7219 100644 --- a/shell/platform/windows/flutter_windows_view.h +++ b/shell/platform/windows/flutter_windows_view.h @@ -90,6 +90,12 @@ class FlutterWindowsView : public WindowBindingHandlerDelegate, // Returns the frame buffer id for the engine to render to. uint32_t GetFrameBufferId(size_t width, size_t height); + // Called when the engine is restarted. + // + // This should reset necessary states to as if the view has just been + // created. This is typically caused by a hot restart (Shift-R in CLI.) + void OnPreEngineRestart(); + // |WindowBindingHandlerDelegate| void OnWindowSizeChanged(size_t width, size_t height) override; @@ -207,6 +213,11 @@ class FlutterWindowsView : public WindowBindingHandlerDelegate, kDone, }; + // Initialize states related to keyboard. + // + // This is called when the view is first created, or restarted. + void InitializeKeyboard(); + // Sends a window metrics update to the Flutter engine using current window // dimensions in physical void SendWindowMetrics(size_t width, size_t height, double dpiscale) const; diff --git a/shell/platform/windows/flutter_windows_view_unittests.cc b/shell/platform/windows/flutter_windows_view_unittests.cc index 331ede8960976..72a4671638e5f 100644 --- a/shell/platform/windows/flutter_windows_view_unittests.cc +++ b/shell/platform/windows/flutter_windows_view_unittests.cc @@ -34,7 +34,7 @@ struct TestResponseHandle { void* user_data; }; -static const bool test_response = false; +static bool test_response = false; constexpr uint64_t kKeyEventFromChannel = 0x11; constexpr uint64_t kKeyEventFromEmbedder = 0x22; @@ -80,6 +80,8 @@ std::unique_ptr GetTestEngine() { TEST(FlutterWindowsViewTest, KeySequence) { std::unique_ptr engine = GetTestEngine(); + test_response = false; + auto window_binding_handler = std::make_unique<::testing::NiceMock>(); FlutterWindowsView view(std::move(window_binding_handler)); @@ -94,5 +96,35 @@ TEST(FlutterWindowsViewTest, KeySequence) { key_event_logs.clear(); } +TEST(FlutterWindowsViewTest, RestartClearsKeyboardState) { + std::unique_ptr engine = GetTestEngine(); + + auto window_binding_handler = + std::make_unique<::testing::NiceMock>(); + FlutterWindowsView view(std::move(window_binding_handler)); + view.SetEngine(std::move(engine)); + + test_response = false; + + // Receives a KeyA down. Events are dispatched and decided unhandled. Now the + // keyboard key handler is waiting for the redispatched event. + view.OnKey(kVirtualKeyA, kScanCodeKeyA, WM_KEYDOWN, 'a', false, false); + EXPECT_EQ(key_event_logs.size(), 2); + EXPECT_EQ(key_event_logs[0], kKeyEventFromEmbedder); + EXPECT_EQ(key_event_logs[1], kKeyEventFromChannel); + key_event_logs.clear(); + + // Resets state so that the keyboard key handler is no longer waiting. + view.OnPreEngineRestart(); + + // Receives another KeyA down. If the state had not been cleared, this event + // will be considered the redispatched event and ignored. + view.OnKey(kVirtualKeyA, kScanCodeKeyA, WM_KEYDOWN, 'a', false, false); + EXPECT_EQ(key_event_logs.size(), 2); + EXPECT_EQ(key_event_logs[0], kKeyEventFromEmbedder); + EXPECT_EQ(key_event_logs[1], kKeyEventFromChannel); + key_event_logs.clear(); +} + } // namespace testing } // namespace flutter