Move FlKeyboardManager and FlKeyboardHandler from FlView to FlEngine. (#161925)

There can only be one handler that is shared between the views.

Move event redispatch matcher back into FlKeyboardManager - if a
redispatched event was moved between views due to a focus change it
would not be matched against.
This commit is contained in:
Robert Ancell 2025-01-23 09:07:11 +13:00 committed by GitHub
parent 391fecdfac
commit 2d3beadffe
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 92 additions and 48 deletions

View File

@ -14,6 +14,7 @@
#include "flutter/shell/platform/linux/fl_dart_project_private.h"
#include "flutter/shell/platform/linux/fl_display_monitor.h"
#include "flutter/shell/platform/linux/fl_engine_private.h"
#include "flutter/shell/platform/linux/fl_keyboard_handler.h"
#include "flutter/shell/platform/linux/fl_pixel_buffer_texture_private.h"
#include "flutter/shell/platform/linux/fl_platform_handler.h"
#include "flutter/shell/platform/linux/fl_plugin_registrar_private.h"
@ -57,6 +58,12 @@ struct _FlEngine {
// Implements the flutter/platform channel.
FlPlatformHandler* platform_handler;
// Process keyboard events.
FlKeyboardManager* keyboard_manager;
// Implements the flutter/keyboard channel.
FlKeyboardHandler* keyboard_handler;
// Implements the flutter/mousecursor channel.
FlMouseCursorHandler* mouse_cursor_handler;
@ -381,6 +388,14 @@ static void fl_engine_update_semantics_cb(const FlutterSemanticsUpdate2* update,
}
}
static void setup_keyboard(FlEngine* self) {
g_clear_object(&self->keyboard_manager);
self->keyboard_manager = fl_keyboard_manager_new(self);
g_clear_object(&self->keyboard_handler);
self->keyboard_handler =
fl_keyboard_handler_new(self->binary_messenger, self->keyboard_manager);
}
// Called right before the engine is restarted.
//
// This method should reset states to as if the engine has just been started,
@ -389,6 +404,8 @@ static void fl_engine_update_semantics_cb(const FlutterSemanticsUpdate2* update,
static void fl_engine_on_pre_engine_restart_cb(void* user_data) {
FlEngine* self = FL_ENGINE(user_data);
setup_keyboard(self);
g_signal_emit(self, fl_engine_signals[SIGNAL_ON_PRE_ENGINE_RESTART], 0);
}
@ -455,6 +472,8 @@ static void fl_engine_dispose(GObject* object) {
g_clear_object(&self->binary_messenger);
g_clear_object(&self->settings_handler);
g_clear_object(&self->platform_handler);
g_clear_object(&self->keyboard_manager);
g_clear_object(&self->keyboard_handler);
g_clear_object(&self->mouse_cursor_handler);
g_clear_object(&self->task_runner);
@ -646,6 +665,8 @@ gboolean fl_engine_start(FlEngine* self, GError** error) {
self->mouse_cursor_handler =
fl_mouse_cursor_handler_new(self->binary_messenger);
setup_keyboard(self);
result = self->embedder_api.UpdateSemanticsEnabled(self->engine, TRUE);
if (result != kSuccess) {
g_warning("Failed to enable accessibility features on Flutter engine");
@ -1238,6 +1259,11 @@ void fl_engine_request_app_exit(FlEngine* self) {
fl_platform_handler_request_app_exit(self->platform_handler);
}
FlKeyboardManager* fl_engine_get_keyboard_manager(FlEngine* self) {
g_return_val_if_fail(FL_IS_ENGINE(self), nullptr);
return self->keyboard_manager;
}
FlMouseCursorHandler* fl_engine_get_mouse_cursor_handler(FlEngine* self) {
g_return_val_if_fail(FL_IS_ENGINE(self), nullptr);
return self->mouse_cursor_handler;

View File

@ -9,6 +9,7 @@
#include "flutter/shell/platform/embedder/embedder.h"
#include "flutter/shell/platform/linux/fl_display_monitor.h"
#include "flutter/shell/platform/linux/fl_keyboard_manager.h"
#include "flutter/shell/platform/linux/fl_mouse_cursor_handler.h"
#include "flutter/shell/platform/linux/fl_renderer.h"
#include "flutter/shell/platform/linux/fl_task_runner.h"
@ -563,6 +564,16 @@ void fl_engine_update_accessibility_features(FlEngine* engine, int32_t flags);
*/
void fl_engine_request_app_exit(FlEngine* engine);
/**
* fl_engine_get_keyboard_manager:
* @engine: an #FlEngine.
*
* Gets the keyboard manager used by this engine.
*
* Returns: a #FlKeyboardManager.
*/
FlKeyboardManager* fl_engine_get_keyboard_manager(FlEngine* engine);
/**
* fl_engine_get_mouse_cursor_handler:
* @engine: an #FlEngine.

View File

@ -95,6 +95,9 @@ struct _FlKeyboardManager {
FlKeyboardManagerGetPressedStateHandler get_pressed_state_handler;
gpointer get_pressed_state_handler_user_data;
// Key events that have been redispatched.
GPtrArray* redispatched_key_events;
FlKeyEmbedderResponder* key_embedder_responder;
FlKeyChannelResponder* key_channel_responder;
@ -126,6 +129,25 @@ struct _FlKeyboardManager {
G_DEFINE_TYPE(FlKeyboardManager, fl_keyboard_manager, G_TYPE_OBJECT);
static gboolean event_is_redispatched(FlKeyboardManager* self,
FlKeyEvent* event) {
guint32 time = fl_key_event_get_time(event);
gboolean is_press = !!fl_key_event_get_is_press(event);
guint16 keycode = fl_key_event_get_keycode(event);
for (guint i = 0; i < self->redispatched_key_events->len; i++) {
FlKeyEvent* e =
FL_KEY_EVENT(g_ptr_array_index(self->redispatched_key_events, i));
if (fl_key_event_get_time(e) == time &&
!!fl_key_event_get_is_press(e) == is_press &&
fl_key_event_get_keycode(e) == keycode) {
g_ptr_array_remove_index(self->redispatched_key_events, i);
return TRUE;
}
}
return FALSE;
}
static void keymap_keys_changed_cb(FlKeyboardManager* self) {
g_clear_object(&self->derived_layout);
self->derived_layout = fl_keyboard_layout_new();
@ -292,6 +314,7 @@ static void fl_keyboard_manager_dispose(GObject* object) {
self->keycode_to_goals.reset();
self->logical_to_mandatory_goals.reset();
g_clear_pointer(&self->redispatched_key_events, g_ptr_array_unref);
g_clear_object(&self->key_embedder_responder);
g_clear_object(&self->key_channel_responder);
g_clear_object(&self->derived_layout);
@ -309,6 +332,8 @@ static void fl_keyboard_manager_class_init(FlKeyboardManagerClass* klass) {
}
static void fl_keyboard_manager_init(FlKeyboardManager* self) {
self->redispatched_key_events =
g_ptr_array_new_with_free_func(g_object_unref);
self->derived_layout = fl_keyboard_layout_new();
self->keycode_to_goals =
@ -383,6 +408,13 @@ FlKeyboardManager* fl_keyboard_manager_new(FlEngine* engine) {
return self;
}
void fl_keyboard_manager_add_redispatched_event(FlKeyboardManager* self,
FlKeyEvent* event) {
g_return_if_fail(FL_IS_KEYBOARD_MANAGER(self));
g_ptr_array_add(self->redispatched_key_events, g_object_ref(event));
}
void fl_keyboard_manager_handle_event(FlKeyboardManager* self,
FlKeyEvent* event,
GCancellable* cancellable,
@ -399,6 +431,14 @@ void fl_keyboard_manager_handle_event(FlKeyboardManager* self,
task, handle_event_data_new(event),
reinterpret_cast<GDestroyNotify>(handle_event_data_free));
if (event_is_redispatched(self, event)) {
HandleEventData* data =
static_cast<HandleEventData*>(g_task_get_task_data(task));
data->handled = TRUE;
g_task_return_boolean(task, TRUE);
return;
}
uint64_t specified_logical_key = fl_keyboard_layout_get_logical_key(
self->derived_layout, fl_key_event_get_group(event),
fl_key_event_get_keycode(event));

View File

@ -45,6 +45,16 @@ G_DECLARE_FINAL_TYPE(FlKeyboardManager,
*/
FlKeyboardManager* fl_keyboard_manager_new(FlEngine* engine);
/** fl_keyboard_manager_add_redispatched_event:
* @manager: an #FlKeyboardManager.
* @event: an event that will be handled by the manager in the future.
*
* Add an event that will be redispatched and handled by the manager in the
* future. When that event is received it will be ignored.
*/
void fl_keyboard_manager_add_redispatched_event(FlKeyboardManager* manager,
FlKeyEvent* event);
/**
* fl_keyboard_manager_handle_event:
* @manager: an #FlKeyboardManager.

View File

@ -13,8 +13,6 @@
#include "flutter/shell/platform/linux/fl_accessible_node.h"
#include "flutter/shell/platform/linux/fl_engine_private.h"
#include "flutter/shell/platform/linux/fl_key_event.h"
#include "flutter/shell/platform/linux/fl_keyboard_handler.h"
#include "flutter/shell/platform/linux/fl_keyboard_manager.h"
#include "flutter/shell/platform/linux/fl_plugin_registrar_private.h"
#include "flutter/shell/platform/linux/fl_pointer_manager.h"
#include "flutter/shell/platform/linux/fl_renderer_gdk.h"
@ -64,14 +62,7 @@ struct _FlView {
// Manages touch events.
FlTouchManager* touch_manager;
// Manages keyboard events.
FlKeyboardManager* keyboard_manager;
// Key events that have been redispatched.
GPtrArray* redispatched_key_events;
// Flutter system channel handlers.
FlKeyboardHandler* keyboard_handler;
FlTextInputHandler* text_input_handler;
// Accessible tree from Flutter, exposed as an AtkPlug.
@ -134,12 +125,6 @@ static void init_keyboard(FlView* self) {
g_clear_object(&self->text_input_handler);
self->text_input_handler = fl_text_input_handler_new(
messenger, im_context, FL_TEXT_INPUT_VIEW_DELEGATE(self));
g_clear_object(&self->keyboard_manager);
self->keyboard_manager = fl_keyboard_manager_new(self->engine);
g_ptr_array_set_size(self->redispatched_key_events, 0);
g_clear_object(&self->keyboard_handler);
self->keyboard_handler =
fl_keyboard_handler_new(messenger, self->keyboard_manager);
}
static void init_scrolling(FlView* self) {
@ -345,8 +330,8 @@ static void sync_modifier_if_needed(FlView* self, GdkEvent* event) {
guint event_time = gdk_event_get_time(event);
GdkModifierType event_state = static_cast<GdkModifierType>(0);
gdk_event_get_state(event, &event_state);
fl_keyboard_manager_sync_modifier_if_needed(self->keyboard_manager,
event_state, event_time);
fl_keyboard_manager_sync_modifier_if_needed(
fl_engine_get_keyboard_manager(self->engine), event_state, event_time);
}
static void set_scrolling_position(FlView* self, gdouble x, gdouble y) {
@ -642,9 +627,6 @@ static void fl_view_dispose(GObject* object) {
g_clear_object(&self->scrolling_manager);
g_clear_object(&self->pointer_manager);
g_clear_object(&self->touch_manager);
g_clear_object(&self->keyboard_manager);
g_clear_pointer(&self->redispatched_key_events, g_ptr_array_unref);
g_clear_object(&self->keyboard_handler);
g_clear_object(&self->view_accessible);
g_clear_object(&self->cancellable);
@ -661,34 +643,12 @@ static void fl_view_realize(GtkWidget* widget) {
gtk_widget_realize(GTK_WIDGET(self->gl_area));
}
static gboolean event_is_redispatched(FlView* self, FlKeyEvent* event) {
guint32 time = fl_key_event_get_time(event);
gboolean is_press = !!fl_key_event_get_is_press(event);
guint16 keycode = fl_key_event_get_keycode(event);
for (guint i = 0; i < self->redispatched_key_events->len; i++) {
FlKeyEvent* e =
FL_KEY_EVENT(g_ptr_array_index(self->redispatched_key_events, i));
if (fl_key_event_get_time(e) == time &&
!!fl_key_event_get_is_press(e) == is_press &&
fl_key_event_get_keycode(e) == keycode) {
g_ptr_array_remove_index(self->redispatched_key_events, i);
return TRUE;
}
}
return FALSE;
}
static gboolean handle_key_event(FlView* self, GdkEventKey* key_event) {
g_autoptr(FlKeyEvent) event = fl_key_event_new_from_gdk_event(
gdk_event_copy(reinterpret_cast<GdkEvent*>(key_event)));
if (event_is_redispatched(self, event)) {
return FALSE;
}
fl_keyboard_manager_handle_event(
self->keyboard_manager, event, self->cancellable,
fl_engine_get_keyboard_manager(self->engine), event, self->cancellable,
[](GObject* object, GAsyncResult* result, gpointer user_data) {
FlView* self = FL_VIEW(user_data);
@ -707,8 +667,8 @@ static gboolean handle_key_event(FlView* self, GdkEventKey* key_event) {
if (redispatch_event != nullptr) {
if (!fl_text_input_handler_filter_keypress(self->text_input_handler,
redispatch_event)) {
g_ptr_array_add(self->redispatched_key_events,
g_object_ref(redispatch_event));
fl_keyboard_manager_add_redispatched_event(
fl_engine_get_keyboard_manager(self->engine), redispatch_event);
gdk_event_put(fl_key_event_get_origin(redispatch_event));
}
}
@ -761,9 +721,6 @@ static void fl_view_init(FlView* self) {
.red = 0.0, .green = 0.0, .blue = 0.0, .alpha = 1.0};
self->background_color = gdk_rgba_copy(&default_background);
self->redispatched_key_events =
g_ptr_array_new_with_free_func(g_object_unref);
GtkWidget* event_box = gtk_event_box_new();
gtk_widget_set_hexpand(event_box, TRUE);
gtk_widget_set_vexpand(event_box, TRUE);