diff --git a/engine/src/flutter/shell/platform/linux/fl_engine.cc b/engine/src/flutter/shell/platform/linux/fl_engine.cc index 01329cfe9b..0b7727a39f 100644 --- a/engine/src/flutter/shell/platform/linux/fl_engine.cc +++ b/engine/src/flutter/shell/platform/linux/fl_engine.cc @@ -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; diff --git a/engine/src/flutter/shell/platform/linux/fl_engine_private.h b/engine/src/flutter/shell/platform/linux/fl_engine_private.h index 419073a4e8..3a4b1ef174 100644 --- a/engine/src/flutter/shell/platform/linux/fl_engine_private.h +++ b/engine/src/flutter/shell/platform/linux/fl_engine_private.h @@ -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. diff --git a/engine/src/flutter/shell/platform/linux/fl_keyboard_manager.cc b/engine/src/flutter/shell/platform/linux/fl_keyboard_manager.cc index 5b7abecf19..9406eda257 100644 --- a/engine/src/flutter/shell/platform/linux/fl_keyboard_manager.cc +++ b/engine/src/flutter/shell/platform/linux/fl_keyboard_manager.cc @@ -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(handle_event_data_free)); + if (event_is_redispatched(self, event)) { + HandleEventData* data = + static_cast(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)); diff --git a/engine/src/flutter/shell/platform/linux/fl_keyboard_manager.h b/engine/src/flutter/shell/platform/linux/fl_keyboard_manager.h index ca125fde7e..3321b7044a 100644 --- a/engine/src/flutter/shell/platform/linux/fl_keyboard_manager.h +++ b/engine/src/flutter/shell/platform/linux/fl_keyboard_manager.h @@ -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. diff --git a/engine/src/flutter/shell/platform/linux/fl_view.cc b/engine/src/flutter/shell/platform/linux/fl_view.cc index 92eafd772d..ef0ede9046 100644 --- a/engine/src/flutter/shell/platform/linux/fl_view.cc +++ b/engine/src/flutter/shell/platform/linux/fl_view.cc @@ -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(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(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);