Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

[Windows] Prepare keyboard & text input plugins for multi-view #39464

Merged
merged 4 commits into from
Feb 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 53 additions & 1 deletion shell/platform/windows/flutter_windows_engine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "flutter/shell/platform/common/path_utils.h"
#include "flutter/shell/platform/windows/accessibility_bridge_windows.h"
#include "flutter/shell/platform/windows/flutter_windows_view.h"
#include "flutter/shell/platform/windows/keyboard_key_channel_handler.h"
#include "flutter/shell/platform/windows/system_utils.h"
#include "flutter/shell/platform/windows/task_runner.h"
#include "flutter/third_party/accessibility/ax/ax_node.h"
Expand Down Expand Up @@ -206,6 +207,8 @@ FlutterWindowsEngine::FlutterWindowsEngine(
// Set up internal channels.
// TODO: Replace this with an embedder.h API. See
// https://github.com/flutter/flutter/issues/71099
internal_plugin_registrar_ =
std::make_unique<PluginRegistrar>(plugin_registrar_.get());
cursor_handler_ =
std::make_unique<CursorHandler>(messenger_wrapper_.get(), this);
platform_handler_ =
Expand Down Expand Up @@ -322,7 +325,7 @@ bool FlutterWindowsEngine::Run(std::string_view entrypoint) {
};
args.on_pre_engine_restart_callback = [](void* user_data) {
auto host = static_cast<FlutterWindowsEngine*>(user_data);
host->view()->OnPreEngineRestart();
host->OnPreEngineRestart();
};
args.update_semantics_callback = [](const FlutterSemanticsUpdate* update,
void* user_data) {
Expand Down Expand Up @@ -401,6 +404,7 @@ bool FlutterWindowsEngine::Stop() {

void FlutterWindowsEngine::SetView(FlutterWindowsView* view) {
view_ = view;
InitializeKeyboard();
}

void FlutterWindowsEngine::OnVsync(intptr_t baton) {
Expand Down Expand Up @@ -561,6 +565,47 @@ void FlutterWindowsEngine::SendSystemLocales() {
flutter_locale_list.size());
}

void FlutterWindowsEngine::InitializeKeyboard() {
if (view_ == nullptr) {
FML_LOG(ERROR) << "Cannot initialize keyboard on Windows headless mode.";
}

auto internal_plugin_messenger = internal_plugin_registrar_->messenger();
KeyboardKeyEmbedderHandler::GetKeyStateHandler get_key_state = GetKeyState;
KeyboardKeyEmbedderHandler::MapVirtualKeyToScanCode map_vk_to_scan =
[](UINT virtual_key, bool extended) {
return MapVirtualKey(virtual_key,
extended ? MAPVK_VK_TO_VSC_EX : MAPVK_VK_TO_VSC);
};
keyboard_key_handler_ = std::move(CreateKeyboardKeyHandler(
internal_plugin_messenger, get_key_state, map_vk_to_scan));
text_input_plugin_ =
std::move(CreateTextInputPlugin(internal_plugin_messenger));
}

std::unique_ptr<KeyboardHandlerBase>
FlutterWindowsEngine::CreateKeyboardKeyHandler(
BinaryMessenger* messenger,
KeyboardKeyEmbedderHandler::GetKeyStateHandler get_key_state,
KeyboardKeyEmbedderHandler::MapVirtualKeyToScanCode map_vk_to_scan) {
auto keyboard_key_handler = std::make_unique<KeyboardKeyHandler>();
keyboard_key_handler->AddDelegate(
std::make_unique<KeyboardKeyEmbedderHandler>(
[this](const FlutterKeyEvent& event, FlutterKeyEventCallback callback,
void* user_data) {
return SendKeyEvent(event, callback, user_data);
},
get_key_state, map_vk_to_scan));
keyboard_key_handler->AddDelegate(
std::make_unique<KeyboardKeyChannelHandler>(messenger));
return keyboard_key_handler;
}

std::unique_ptr<TextInputPlugin> FlutterWindowsEngine::CreateTextInputPlugin(
BinaryMessenger* messenger) {
return std::make_unique<TextInputPlugin>(messenger, view_);
}

bool FlutterWindowsEngine::RegisterExternalTexture(int64_t texture_id) {
return (embedder_api_.RegisterExternalTexture(engine_, texture_id) ==
kSuccess);
Expand Down Expand Up @@ -625,6 +670,13 @@ FlutterWindowsEngine::CreateAccessibilityBridge(FlutterWindowsEngine* engine,
return std::make_shared<AccessibilityBridgeWindows>(engine, view);
}

void FlutterWindowsEngine::OnPreEngineRestart() {
// Reset the keyboard's state on hot restart.
if (view_) {
InitializeKeyboard();
}
}

gfx::NativeViewAccessible FlutterWindowsEngine::GetNativeAccessibleFromId(
AccessibilityNodeId id) {
if (!accessibility_bridge_) {
Expand Down
45 changes: 45 additions & 0 deletions shell/platform/windows/flutter_windows_engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,13 @@
#include "flutter/shell/platform/windows/flutter_desktop_messenger.h"
#include "flutter/shell/platform/windows/flutter_project_bundle.h"
#include "flutter/shell/platform/windows/flutter_windows_texture_registrar.h"
#include "flutter/shell/platform/windows/keyboard_handler_base.h"
#include "flutter/shell/platform/windows/keyboard_key_embedder_handler.h"
#include "flutter/shell/platform/windows/platform_handler.h"
#include "flutter/shell/platform/windows/public/flutter_windows.h"
#include "flutter/shell/platform/windows/settings_plugin.h"
#include "flutter/shell/platform/windows/task_runner.h"
#include "flutter/shell/platform/windows/text_input_plugin.h"
#include "flutter/shell/platform/windows/window_proc_delegate_manager.h"
#include "flutter/shell/platform/windows/window_state.h"
#include "flutter/shell/platform/windows/windows_registry.h"
Expand Down Expand Up @@ -163,6 +166,11 @@ class FlutterWindowsEngine {
FlutterKeyEventCallback callback,
void* user_data);

KeyboardHandlerBase* keyboard_key_handler() {
return keyboard_key_handler_.get();
}
TextInputPlugin* text_input_plugin() { return text_input_plugin_.get(); }

// Sends the given message to the engine, calling |reply| with |user_data|
// when a response is received from the engine if they are non-null.
bool SendPlatformMessage(const char* channel,
Expand Down Expand Up @@ -249,6 +257,22 @@ class FlutterWindowsEngine {
void UpdateAccessibilityFeatures(FlutterAccessibilityFeature flags);

protected:
// Creates the keyboard key handler.
//
// Exposing this method allows unit tests to override in order to
// capture information.
virtual std::unique_ptr<KeyboardHandlerBase> CreateKeyboardKeyHandler(
BinaryMessenger* messenger,
KeyboardKeyEmbedderHandler::GetKeyStateHandler get_key_state,
KeyboardKeyEmbedderHandler::MapVirtualKeyToScanCode map_vk_to_scan);

// Creates the text input plugin.
//
// Exposing this method allows unit tests to override in order to
// capture information.
virtual std::unique_ptr<TextInputPlugin> CreateTextInputPlugin(
BinaryMessenger* messenger);

// Creates an accessibility bridge with the provided parameters.
//
// By default this method calls AccessibilityBridge's constructor. Exposing
Expand All @@ -257,6 +281,12 @@ class FlutterWindowsEngine {
FlutterWindowsEngine* engine,
FlutterWindowsView* view);

// Invoked by the engine right before the engine is restarted.
//
// This should reset necessary states to as if the engine has just been
// created. This is typically caused by a hot restart (Shift-R in CLI.)
void OnPreEngineRestart();

private:
// Allows swapping out embedder_api_ calls in tests.
friend class EngineModifier;
Expand All @@ -267,6 +297,12 @@ class FlutterWindowsEngine {
// system changes.
void SendSystemLocales();

// Create the keyboard & text input sub-systems.
//
// This requires that a view is attached to the engine.
// Calling this method again resets the keyboard state.
void InitializeKeyboard();

void HandleAccessibilityMessage(FlutterDesktopMessengerRef messenger,
const FlutterDesktopMessage* message);

Expand Down Expand Up @@ -309,12 +345,21 @@ class FlutterWindowsEngine {
// May be nullptr if ANGLE failed to initialize.
std::unique_ptr<AngleSurfaceManager> surface_manager_;

// The plugin registrar managing internal plugins.
std::unique_ptr<PluginRegistrar> internal_plugin_registrar_;

// Handler for cursor events.
std::unique_ptr<CursorHandler> cursor_handler_;

// Handler for the flutter/platform channel.
std::unique_ptr<PlatformHandler> platform_handler_;

// Handlers for keyboard events from Windows.
std::unique_ptr<KeyboardHandlerBase> keyboard_key_handler_;

// Handlers for text events from Windows.
std::unique_ptr<TextInputPlugin> text_input_plugin_;

// The settings plugin.
std::unique_ptr<SettingsPlugin> settings_plugin_;

Expand Down
67 changes: 9 additions & 58 deletions shell/platform/windows/flutter_windows_view.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
#include "flutter/fml/platform/win/wstring_conversion.h"
#include "flutter/shell/platform/common/accessibility_bridge.h"
#include "flutter/shell/platform/windows/keyboard_key_channel_handler.h"
#include "flutter/shell/platform/windows/keyboard_key_embedder_handler.h"
#include "flutter/shell/platform/windows/text_input_plugin.h"
#include "flutter/third_party/accessibility/ax/platform/ax_platform_node_win.h"

Expand Down Expand Up @@ -59,42 +58,12 @@ void FlutterWindowsView::SetEngine(

engine_->SetView(this);

internal_plugin_registrar_ =
std::make_unique<PluginRegistrar>(engine_->GetRegistrar());

// Set up the system channel handlers.
auto internal_plugin_messenger = internal_plugin_registrar_->messenger();
InitializeKeyboard();

PhysicalWindowBounds bounds = binding_handler_->GetPhysicalWindowBounds();

SendWindowMetrics(bounds.width, bounds.height,
binding_handler_->GetDpiScale());
}

std::unique_ptr<KeyboardHandlerBase>
FlutterWindowsView::CreateKeyboardKeyHandler(
BinaryMessenger* messenger,
KeyboardKeyEmbedderHandler::GetKeyStateHandler get_key_state,
KeyboardKeyEmbedderHandler::MapVirtualKeyToScanCode map_vk_to_scan) {
auto keyboard_key_handler = std::make_unique<KeyboardKeyHandler>();
keyboard_key_handler->AddDelegate(
std::make_unique<KeyboardKeyEmbedderHandler>(
[this](const FlutterKeyEvent& event, FlutterKeyEventCallback callback,
void* user_data) {
return engine_->SendKeyEvent(event, callback, user_data);
},
get_key_state, map_vk_to_scan));
keyboard_key_handler->AddDelegate(
std::make_unique<KeyboardKeyChannelHandler>(messenger));
return keyboard_key_handler;
}

std::unique_ptr<TextInputPlugin> FlutterWindowsView::CreateTextInputPlugin(
BinaryMessenger* messenger) {
return std::make_unique<TextInputPlugin>(messenger, this);
}

uint32_t FlutterWindowsView::GetFrameBufferId(size_t width, size_t height) {
// Called on an engine-controlled (non-platform) thread.
std::unique_lock<std::mutex> lock(resize_mutex_);
Expand Down Expand Up @@ -129,10 +98,6 @@ void FlutterWindowsView::ForceRedraw() {
}
}

void FlutterWindowsView::OnPreEngineRestart() {
InitializeKeyboard();
}

void FlutterWindowsView::OnWindowSizeChanged(size_t width, size_t height) {
// Called on the platform thread.
std::unique_lock<std::mutex> lock(resize_mutex_);
Expand Down Expand Up @@ -176,7 +141,7 @@ void FlutterWindowsView::OnPointerMove(double x,
FlutterPointerDeviceKind device_kind,
int32_t device_id,
int modifiers_state) {
keyboard_key_handler_->SyncModifiersIfNeeded(modifiers_state);
engine_->keyboard_key_handler()->SyncModifiersIfNeeded(modifiers_state);
SendPointerMove(x, y, GetOrCreatePointerState(device_kind, device_id));
}

Expand Down Expand Up @@ -293,20 +258,6 @@ void FlutterWindowsView::OnResetImeComposing() {
binding_handler_->OnResetImeComposing();
}

void FlutterWindowsView::InitializeKeyboard() {
auto internal_plugin_messenger = internal_plugin_registrar_->messenger();
KeyboardKeyEmbedderHandler::GetKeyStateHandler get_key_state = GetKeyState;
KeyboardKeyEmbedderHandler::MapVirtualKeyToScanCode map_vk_to_scan =
[](UINT virtual_key, bool extended) {
return MapVirtualKey(virtual_key,
extended ? MAPVK_VK_TO_VSC_EX : MAPVK_VK_TO_VSC);
};
keyboard_key_handler_ = std::move(CreateKeyboardKeyHandler(
internal_plugin_messenger, get_key_state, map_vk_to_scan));
text_input_plugin_ =
std::move(CreateTextInputPlugin(internal_plugin_messenger));
}

// Sends new size information to FlutterEngine.
void FlutterWindowsView::SendWindowMetrics(size_t width,
size_t height,
Expand Down Expand Up @@ -454,7 +405,7 @@ void FlutterWindowsView::SendPointerPanZoomEnd(int32_t device_id) {
}

void FlutterWindowsView::SendText(const std::u16string& text) {
text_input_plugin_->TextHook(text);
engine_->text_input_plugin()->TextHook(text);
}

void FlutterWindowsView::SendKey(int key,
Expand All @@ -464,32 +415,32 @@ void FlutterWindowsView::SendKey(int key,
bool extended,
bool was_down,
KeyEventCallback callback) {
keyboard_key_handler_->KeyboardHook(
engine_->keyboard_key_handler()->KeyboardHook(
key, scancode, action, character, extended, was_down,
[=, callback = std::move(callback)](bool handled) {
if (!handled) {
text_input_plugin_->KeyboardHook(key, scancode, action, character,
extended, was_down);
engine_->text_input_plugin()->KeyboardHook(
key, scancode, action, character, extended, was_down);
}
callback(handled);
});
}

void FlutterWindowsView::SendComposeBegin() {
text_input_plugin_->ComposeBeginHook();
engine_->text_input_plugin()->ComposeBeginHook();
}

void FlutterWindowsView::SendComposeCommit() {
text_input_plugin_->ComposeCommitHook();
engine_->text_input_plugin()->ComposeCommitHook();
}

void FlutterWindowsView::SendComposeEnd() {
text_input_plugin_->ComposeEndHook();
engine_->text_input_plugin()->ComposeEndHook();
}

void FlutterWindowsView::SendComposeChange(const std::u16string& text,
int cursor_pos) {
text_input_plugin_->ComposeChangeHook(text, cursor_pos);
engine_->text_input_plugin()->ComposeChangeHook(text, cursor_pos);
}

void FlutterWindowsView::SendScroll(double x,
Expand Down
Loading