From 84397b1a6c431e2277ead4124550e6216c4cce78 Mon Sep 17 00:00:00 2001 From: Bruno Leroux Date: Fri, 26 May 2023 16:49:56 +0200 Subject: [PATCH 1/2] [Linux] Return keyboard pressed state --- ci/licenses_golden/licenses_flutter | 10 ++ shell/platform/linux/BUILD.gn | 4 + .../linux/fl_key_embedder_responder.cc | 5 + .../linux/fl_key_embedder_responder.h | 9 ++ shell/platform/linux/fl_keyboard_manager.cc | 12 ++ shell/platform/linux/fl_keyboard_manager.h | 8 ++ .../linux/fl_keyboard_manager_test.cc | 19 +++ shell/platform/linux/fl_keyboard_plugin.cc | 111 ++++++++++++++++ shell/platform/linux/fl_keyboard_plugin.h | 47 +++++++ .../platform/linux/fl_keyboard_plugin_test.cc | 125 ++++++++++++++++++ .../linux/fl_keyboard_plugin_view_delegate.cc | 20 +++ .../linux/fl_keyboard_plugin_view_delegate.h | 40 ++++++ shell/platform/linux/fl_view.cc | 29 +++- shell/platform/linux/fl_view_private.h | 8 ++ 14 files changed, 446 insertions(+), 1 deletion(-) create mode 100644 shell/platform/linux/fl_keyboard_plugin.cc create mode 100644 shell/platform/linux/fl_keyboard_plugin.h create mode 100644 shell/platform/linux/fl_keyboard_plugin_test.cc create mode 100644 shell/platform/linux/fl_keyboard_plugin_view_delegate.cc create mode 100644 shell/platform/linux/fl_keyboard_plugin_view_delegate.h diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 893d479e0dbe4..539b14962ae00 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -3028,6 +3028,11 @@ ORIGIN: ../../../flutter/shell/platform/linux/fl_key_responder.h + ../../../flut ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_manager.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_manager.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_manager_test.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_plugin.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_plugin.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_plugin_test.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_plugin_view_delegate.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_plugin_view_delegate.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_view_delegate.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_view_delegate.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_message_codec.cc + ../../../flutter/LICENSE @@ -5704,6 +5709,11 @@ FILE: ../../../flutter/shell/platform/linux/fl_key_responder.h FILE: ../../../flutter/shell/platform/linux/fl_keyboard_manager.cc FILE: ../../../flutter/shell/platform/linux/fl_keyboard_manager.h FILE: ../../../flutter/shell/platform/linux/fl_keyboard_manager_test.cc +FILE: ../../../flutter/shell/platform/linux/fl_keyboard_plugin.cc +FILE: ../../../flutter/shell/platform/linux/fl_keyboard_plugin.h +FILE: ../../../flutter/shell/platform/linux/fl_keyboard_plugin_test.cc +FILE: ../../../flutter/shell/platform/linux/fl_keyboard_plugin_view_delegate.cc +FILE: ../../../flutter/shell/platform/linux/fl_keyboard_plugin_view_delegate.h FILE: ../../../flutter/shell/platform/linux/fl_keyboard_view_delegate.cc FILE: ../../../flutter/shell/platform/linux/fl_keyboard_view_delegate.h FILE: ../../../flutter/shell/platform/linux/fl_message_codec.cc diff --git a/shell/platform/linux/BUILD.gn b/shell/platform/linux/BUILD.gn index 5cb9f2839aaa8..89d76df7a0fb5 100644 --- a/shell/platform/linux/BUILD.gn +++ b/shell/platform/linux/BUILD.gn @@ -80,6 +80,7 @@ source_set("flutter_linux_sources") { "fl_dart_project_private.h", "fl_engine_private.h", "fl_keyboard_manager.h", + "fl_keyboard_plugin_view_delegate.h", "fl_keyboard_view_delegate.h", "fl_key_event.h", "fl_key_responder.h", @@ -116,6 +117,8 @@ source_set("flutter_linux_sources") { "fl_key_event.cc", "fl_key_responder.cc", "fl_keyboard_manager.cc", + "fl_keyboard_plugin.cc", + "fl_keyboard_plugin_view_delegate.cc", "fl_keyboard_view_delegate.cc", "fl_message_codec.cc", "fl_method_call.cc", @@ -207,6 +210,7 @@ executable("flutter_linux_unittests") { "fl_key_channel_responder_test.cc", "fl_key_embedder_responder_test.cc", "fl_keyboard_manager_test.cc", + "fl_keyboard_plugin_test.cc", "fl_message_codec_test.cc", "fl_method_channel_test.cc", "fl_method_codec_test.cc", diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index 6c9c91f102a0d..925c530a71348 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -885,3 +885,8 @@ void fl_key_embedder_responder_sync_modifiers_if_needed( synchronize_pressed_states_loop_body, &sync_state_context); } + +GHashTable* fl_key_embedder_responder_get_pressed_state( + FlKeyEmbedderResponder* self) { + return self->pressing_records; +} diff --git a/shell/platform/linux/fl_key_embedder_responder.h b/shell/platform/linux/fl_key_embedder_responder.h index d7b3af8c0b410..025eabde7975e 100644 --- a/shell/platform/linux/fl_key_embedder_responder.h +++ b/shell/platform/linux/fl_key_embedder_responder.h @@ -64,6 +64,15 @@ void fl_key_embedder_responder_sync_modifiers_if_needed( guint state, double event_time); +/** + * fl_key_embedder_responder_get_pressed_state: + * @responder: the #FlKeyEmbedderResponder self. + * + * Returns the keyboard pressed state. + */ +GHashTable* fl_key_embedder_responder_get_pressed_state( + FlKeyEmbedderResponder* responder); + G_END_DECLS #endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_KEY_EMBEDDER_RESPONDER_H_ diff --git a/shell/platform/linux/fl_keyboard_manager.cc b/shell/platform/linux/fl_keyboard_manager.cc index fc3c8ca31b38a..4073e54a4dca0 100644 --- a/shell/platform/linux/fl_keyboard_manager.cc +++ b/shell/platform/linux/fl_keyboard_manager.cc @@ -614,6 +614,8 @@ gboolean fl_keyboard_manager_is_state_clear(FlKeyboardManager* self) { void fl_keyboard_manager_sync_modifier_if_needed(FlKeyboardManager* self, guint state, double event_time) { + g_return_if_fail(FL_IS_KEYBOARD_MANAGER(self)); + // The embedder responder is the first element in // FlKeyboardManager.responder_list. FlKeyEmbedderResponder* responder = @@ -621,3 +623,13 @@ void fl_keyboard_manager_sync_modifier_if_needed(FlKeyboardManager* self, fl_key_embedder_responder_sync_modifiers_if_needed(responder, state, event_time); } + +GHashTable* fl_keyboard_manager_get_pressed_state(FlKeyboardManager* self) { + g_return_val_if_fail(FL_IS_KEYBOARD_MANAGER(self), nullptr); + + // The embedder responder is the first element in + // FlKeyboardManager.responder_list. + FlKeyEmbedderResponder* responder = + FL_KEY_EMBEDDER_RESPONDER(g_ptr_array_index(self->responder_list, 0)); + return fl_key_embedder_responder_get_pressed_state(responder); +} diff --git a/shell/platform/linux/fl_keyboard_manager.h b/shell/platform/linux/fl_keyboard_manager.h index 688e49f972a92..0361ed87c57fb 100644 --- a/shell/platform/linux/fl_keyboard_manager.h +++ b/shell/platform/linux/fl_keyboard_manager.h @@ -83,6 +83,14 @@ void fl_keyboard_manager_sync_modifier_if_needed(FlKeyboardManager* manager, guint state, double event_time); +/** + * fl_keyboard_manager_get_pressed_state: + * @manager: the #FlKeyboardManager self. + * + * Returns the keyboard pressed state. + */ +GHashTable* fl_keyboard_manager_get_pressed_state(FlKeyboardManager* responder); + G_END_DECLS #endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_KEYBOARD_MANAGER_H_ diff --git a/shell/platform/linux/fl_keyboard_manager_test.cc b/shell/platform/linux/fl_keyboard_manager_test.cc index b408cb89eac00..0017e6d89aa79 100644 --- a/shell/platform/linux/fl_keyboard_manager_test.cc +++ b/shell/platform/linux/fl_keyboard_manager_test.cc @@ -8,6 +8,7 @@ #include #include "flutter/shell/platform/embedder/test_utils/key_codes.g.h" +#include "flutter/shell/platform/linux/key_mapping.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_json_message_codec.h" #include "flutter/shell/platform/linux/testing/mock_text_input_plugin.h" #include "gtest/gtest.h" @@ -926,6 +927,24 @@ TEST(FlKeyboardManagerTest, SynthesizeModifiersIfNeeded) { kLogicalShiftLeft); } +TEST(FlKeyboardManagerTest, GetPressedState) { + KeyboardTester tester; + tester.respondToTextInputWith(true); + + // Dispatch a key event. + fl_keyboard_manager_handle_event( + tester.manager(), + fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA, 0, false)); + + GHashTable* pressedState = + fl_keyboard_manager_get_pressed_state(tester.manager()); + EXPECT_EQ(g_hash_table_size(pressedState), 1u); + + gpointer physical_key = + g_hash_table_lookup(pressedState, uint64_to_gpointer(kPhysicalKeyA)); + EXPECT_EQ(gpointer_to_uint64(physical_key), kLogicalKeyA); +} + // The following layout data is generated using DEBUG_PRINT_LAYOUT. const MockGroupLayoutData kLayoutUs0{{ diff --git a/shell/platform/linux/fl_keyboard_plugin.cc b/shell/platform/linux/fl_keyboard_plugin.cc new file mode 100644 index 0000000000000..bf60f6870730c --- /dev/null +++ b/shell/platform/linux/fl_keyboard_plugin.cc @@ -0,0 +1,111 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/platform/linux/fl_keyboard_plugin.h" + +#include +#include + +#include "flutter/shell/platform/linux/public/flutter_linux/fl_method_channel.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_standard_method_codec.h" + +static constexpr char kChannelName[] = "flutter/keyboard"; +static constexpr char kGetKeyboardStateMethod[] = "getKeyboardState"; + +struct _FlKeyboardPlugin { + GObject parent_instance; + + FlMethodChannel* channel; + + FlKeyboardPluginViewDelegate* view_delegate; +}; + +G_DEFINE_TYPE(FlKeyboardPlugin, fl_keyboard_plugin, G_TYPE_OBJECT) + +// Returns the keyboard pressed state. +FlMethodResponse* get_keyboard_state(FlKeyboardPlugin* self) { + g_autoptr(FlValue) result = fl_value_new_map(); + + GHashTable* pressing_records = + fl_keyboard_plugin_view_delegate_get_keyboard_state(self->view_delegate); + + g_hash_table_foreach( + pressing_records, + [](gpointer key, gpointer value, gpointer user_data) { + int64_t physical_key = reinterpret_cast(key); + int64_t logical_key = reinterpret_cast(value); + FlValue* fl_value_map = reinterpret_cast(user_data); + + fl_value_set_take(fl_value_map, fl_value_new_int(physical_key), + fl_value_new_int(logical_key)); + }, + result); + return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); +} + +// Called when a method call is received from Flutter. +static void method_call_cb(FlMethodChannel* channel, + FlMethodCall* method_call, + gpointer user_data) { + FlKeyboardPlugin* self = FL_KEYBOARD_PLUGIN(user_data); + + const gchar* method = fl_method_call_get_name(method_call); + + g_autoptr(FlMethodResponse) response = nullptr; + if (strcmp(method, kGetKeyboardStateMethod) == 0) { + response = get_keyboard_state(self); + } else { + response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new()); + } + + g_autoptr(GError) error = nullptr; + if (!fl_method_call_respond(method_call, response, &error)) { + g_warning("Failed to send method call response: %s", error->message); + } +} + +static void fl_keyboard_plugin_dispose(GObject* object); + +static void fl_keyboard_plugin_class_init(FlKeyboardPluginClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_keyboard_plugin_dispose; +} + +static void fl_keyboard_plugin_init(FlKeyboardPlugin* self) {} + +FlKeyboardPlugin* fl_keyboard_plugin_new( + FlBinaryMessenger* messenger, + FlKeyboardPluginViewDelegate* view_delegate) { + g_return_val_if_fail(FL_IS_BINARY_MESSENGER(messenger), nullptr); + g_return_val_if_fail(FL_IS_KEYBOARD_PLUGIN_VIEW_DELEGATE(view_delegate), + nullptr); + + FlKeyboardPlugin* self = + FL_KEYBOARD_PLUGIN(g_object_new(fl_keyboard_plugin_get_type(), nullptr)); + + g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); + self->channel = + fl_method_channel_new(messenger, kChannelName, FL_METHOD_CODEC(codec)); + fl_method_channel_set_method_call_handler(self->channel, method_call_cb, self, + nullptr); + self->view_delegate = view_delegate; + g_object_add_weak_pointer( + G_OBJECT(view_delegate), + reinterpret_cast(&(self->view_delegate))); + + return self; +} + +static void fl_keyboard_plugin_dispose(GObject* object) { + FlKeyboardPlugin* self = FL_KEYBOARD_PLUGIN(object); + + g_clear_object(&self->channel); + if (self->view_delegate != nullptr) { + g_object_remove_weak_pointer( + G_OBJECT(self->view_delegate), + reinterpret_cast(&(self->view_delegate))); + self->view_delegate = nullptr; + } + + G_OBJECT_CLASS(fl_keyboard_plugin_parent_class)->dispose(object); +} diff --git a/shell/platform/linux/fl_keyboard_plugin.h b/shell/platform/linux/fl_keyboard_plugin.h new file mode 100644 index 0000000000000..1d0d6c5da8e66 --- /dev/null +++ b/shell/platform/linux/fl_keyboard_plugin.h @@ -0,0 +1,47 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_LINUX_FL_KEYBOARD_PLUGIN_H_ +#define FLUTTER_SHELL_PLATFORM_LINUX_FL_KEYBOARD_PLUGIN_H_ + +#include + +#include "flutter/shell/platform/linux/fl_keyboard_plugin_view_delegate.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_view.h" + +G_BEGIN_DECLS + +#define FL_TYPE_KEYBOARD_PLUGIN fl_keyboard_plugin_get_type() +G_DECLARE_FINAL_TYPE(FlKeyboardPlugin, + fl_keyboard_plugin, + FL, + KEYBOARD_PLUGIN, + GObject); + +/** + * FlKeyboardPlugin: + * + * #FlKeyboardPlugin is a keyboard channel that implements the shell side + * of SystemChannels.keyboard from the Flutter services library. + */ + +/** + * fl_keyboard_plugin_new: + * @messenger: an #FlBinaryMessenger. + * @view_delegate: An interface that the plugin requires to communicate with + * the platform. Usually implemented by FlView. + * + * Creates a new plugin that implements SystemChannels.keyboard from the + * Flutter services library. + * + * Returns: a new #FlKeyboardPlugin. + */ +FlKeyboardPlugin* fl_keyboard_plugin_new( + FlBinaryMessenger* messenger, + FlKeyboardPluginViewDelegate* view_delegate); + +G_END_DECLS + +#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_KEYBOARD_PLUGIN_H_ diff --git a/shell/platform/linux/fl_keyboard_plugin_test.cc b/shell/platform/linux/fl_keyboard_plugin_test.cc new file mode 100644 index 0000000000000..0274618a0d312 --- /dev/null +++ b/shell/platform/linux/fl_keyboard_plugin_test.cc @@ -0,0 +1,125 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/platform/linux/fl_keyboard_plugin.h" +#include "flutter/shell/platform/linux/fl_binary_messenger_private.h" +#include "flutter/shell/platform/linux/fl_method_codec_private.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_method_codec.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_standard_method_codec.h" +#include "flutter/shell/platform/linux/testing/fl_test.h" +#include "flutter/shell/platform/linux/testing/mock_binary_messenger.h" +#include "flutter/testing/testing.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +static constexpr char kChannelName[] = "flutter/keyboard"; +static constexpr char kGetKeyboardStateMethod[] = "getKeyboardState"; +static constexpr uint64_t kMockPhysicalKey = 42; +static constexpr uint64_t kMockLogicalKey = 42; + +G_BEGIN_DECLS + +G_DECLARE_FINAL_TYPE(FlMockKeyboardPluginViewDelegate, + fl_mock_keyboard_plugin_view_delegate, + FL, + MOCK_KEYBOARD_PLUGIN_VIEW_DELEGATE, + GObject); + +G_END_DECLS + +MATCHER_P(MethodSuccessResponse, result, "") { + g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); + g_autoptr(FlMethodResponse) response = + fl_method_codec_decode_response(FL_METHOD_CODEC(codec), arg, nullptr); + fl_method_response_get_result(response, nullptr); + if (fl_value_equal(fl_method_response_get_result(response, nullptr), + result)) { + return true; + } + *result_listener << ::testing::PrintToString(response); + return false; +} + +struct _FlMockKeyboardPluginViewDelegate { + GObject parent_instance; +}; + +static void fl_mock_view_keyboard_plugin_delegate_iface_init( + FlKeyboardPluginViewDelegateInterface* iface); + +G_DEFINE_TYPE_WITH_CODE( + FlMockKeyboardPluginViewDelegate, + fl_mock_keyboard_plugin_view_delegate, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE(fl_keyboard_plugin_view_delegate_get_type(), + fl_mock_view_keyboard_plugin_delegate_iface_init)) + +static void fl_mock_keyboard_plugin_view_delegate_init( + FlMockKeyboardPluginViewDelegate* self) {} + +static void fl_mock_keyboard_plugin_view_delegate_dispose(GObject* object) { + G_OBJECT_CLASS(fl_mock_keyboard_plugin_view_delegate_parent_class) + ->dispose(object); +} + +static void fl_mock_keyboard_plugin_view_delegate_class_init( + FlMockKeyboardPluginViewDelegateClass* klass) { + G_OBJECT_CLASS(klass)->dispose = + fl_mock_keyboard_plugin_view_delegate_dispose; +} + +static GHashTable* fl_mock_keyboard_plugin_view_delegate_get_keyboard_state( + FlKeyboardPluginViewDelegate* view_delegate); + +static void fl_mock_view_keyboard_plugin_delegate_iface_init( + FlKeyboardPluginViewDelegateInterface* iface) { + iface->get_keyboard_state = + fl_mock_keyboard_plugin_view_delegate_get_keyboard_state; +} + +static FlMockKeyboardPluginViewDelegate* +fl_mock_keyboard_plugin_view_delegate_new() { + FlMockKeyboardPluginViewDelegate* self = + FL_MOCK_KEYBOARD_PLUGIN_VIEW_DELEGATE(g_object_new( + fl_mock_keyboard_plugin_view_delegate_get_type(), nullptr)); + + // Added to stop compiler complaining about an unused function. + FL_IS_MOCK_KEYBOARD_PLUGIN_VIEW_DELEGATE(self); + + return self; +} + +static GHashTable* fl_mock_keyboard_plugin_view_delegate_get_keyboard_state( + FlKeyboardPluginViewDelegate* view_delegate) { + GHashTable* result = g_hash_table_new(g_direct_hash, g_direct_equal); + g_hash_table_insert(result, reinterpret_cast(kMockPhysicalKey), + reinterpret_cast(kMockLogicalKey)); + + return result; +} + +TEST(FlKeyboardPluginTest, GetPressedState) { + ::testing::NiceMock messenger; + + g_autoptr(FlKeyboardPlugin) plugin = fl_keyboard_plugin_new( + messenger, FL_KEYBOARD_PLUGIN_VIEW_DELEGATE( + fl_mock_keyboard_plugin_view_delegate_new())); + EXPECT_NE(plugin, nullptr); + + g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); + g_autoptr(GBytes) message = fl_method_codec_encode_method_call( + FL_METHOD_CODEC(codec), kGetKeyboardStateMethod, nullptr, nullptr); + + g_autoptr(FlValue) response = fl_value_new_map(); + fl_value_set_take(response, fl_value_new_int(kMockPhysicalKey), + fl_value_new_int(kMockLogicalKey)); + EXPECT_CALL(messenger, + fl_binary_messenger_send_response( + ::testing::Eq(messenger), ::testing::_, + MethodSuccessResponse(response), ::testing::_)) + .WillOnce(::testing::Return(true)); + + messenger.ReceiveMessage(kChannelName, message); +} diff --git a/shell/platform/linux/fl_keyboard_plugin_view_delegate.cc b/shell/platform/linux/fl_keyboard_plugin_view_delegate.cc new file mode 100644 index 0000000000000..d25a98ffecfd6 --- /dev/null +++ b/shell/platform/linux/fl_keyboard_plugin_view_delegate.cc @@ -0,0 +1,20 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/platform/linux/fl_keyboard_plugin_view_delegate.h" + +G_DEFINE_INTERFACE(FlKeyboardPluginViewDelegate, + fl_keyboard_plugin_view_delegate, + G_TYPE_OBJECT) + +static void fl_keyboard_plugin_view_delegate_default_init( + FlKeyboardPluginViewDelegateInterface* iface) {} + +GHashTable* fl_keyboard_plugin_view_delegate_get_keyboard_state( + FlKeyboardPluginViewDelegate* self) { + g_return_val_if_fail(FL_IS_KEYBOARD_PLUGIN_VIEW_DELEGATE(self), nullptr); + + return FL_KEYBOARD_PLUGIN_VIEW_DELEGATE_GET_IFACE(self)->get_keyboard_state( + self); +} diff --git a/shell/platform/linux/fl_keyboard_plugin_view_delegate.h b/shell/platform/linux/fl_keyboard_plugin_view_delegate.h new file mode 100644 index 0000000000000..03d627d64ea7d --- /dev/null +++ b/shell/platform/linux/fl_keyboard_plugin_view_delegate.h @@ -0,0 +1,40 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_SHELL_PLATFORM_LINUX_FL_KEYBOARD_PLUGIN_VIEW_DELEGATE_H_ +#define FLUTTER_SHELL_PLATFORM_LINUX_FL_KEYBOARD_PLUGIN_VIEW_DELEGATE_H_ + +#include +#include +#include + +G_BEGIN_DECLS + +G_DECLARE_INTERFACE(FlKeyboardPluginViewDelegate, + fl_keyboard_plugin_view_delegate, + FL, + KEYBOARD_PLUGIN_VIEW_DELEGATE, + GObject); + +/** + * FlKeyboardPluginViewDelegate: + * + * An interface for a class that provides `FlKeyboardPlugin` with + * view-related features. + * + * This interface is typically implemented by `FlView`. + */ + +struct _FlKeyboardPluginViewDelegateInterface { + GTypeInterface g_iface; + + GHashTable* (*get_keyboard_state)(FlKeyboardPluginViewDelegate* delegate); +}; + +GHashTable* fl_keyboard_plugin_view_delegate_get_keyboard_state( + FlKeyboardPluginViewDelegate* self); + +G_END_DECLS + +#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_KEYBOARD_PLUGIN_VIEW_DELEGATE_H_ diff --git a/shell/platform/linux/fl_view.cc b/shell/platform/linux/fl_view.cc index 58f11ebf68b10..6669b7ac22366 100644 --- a/shell/platform/linux/fl_view.cc +++ b/shell/platform/linux/fl_view.cc @@ -12,6 +12,8 @@ #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_manager.h" +#include "flutter/shell/platform/linux/fl_keyboard_plugin.h" +#include "flutter/shell/platform/linux/fl_keyboard_plugin_view_delegate.h" #include "flutter/shell/platform/linux/fl_keyboard_view_delegate.h" #include "flutter/shell/platform/linux/fl_mouse_cursor_plugin.h" #include "flutter/shell/platform/linux/fl_platform_plugin.h" @@ -48,6 +50,7 @@ struct _FlView { FlScrollingManager* scrolling_manager; FlTextInputPlugin* text_input_plugin; FlMouseCursorPlugin* mouse_cursor_plugin; + FlKeyboardPlugin* keyboard_plugin; FlPlatformPlugin* platform_plugin; GtkWidget* event_box; @@ -76,6 +79,9 @@ static void fl_view_scrolling_delegate_iface_init( static void fl_view_text_input_delegate_iface_init( FlTextInputViewDelegateInterface* iface); +static void fl_view_keyboard_plugin_delegate_iface_init( + FlKeyboardPluginViewDelegateInterface* iface); + G_DEFINE_TYPE_WITH_CODE( FlView, fl_view, @@ -87,7 +93,10 @@ G_DEFINE_TYPE_WITH_CODE( G_IMPLEMENT_INTERFACE(fl_scrolling_view_delegate_get_type(), fl_view_scrolling_delegate_iface_init) G_IMPLEMENT_INTERFACE(fl_text_input_view_delegate_get_type(), - fl_view_text_input_delegate_iface_init)) + fl_view_text_input_delegate_iface_init) + G_IMPLEMENT_INTERFACE( + fl_keyboard_plugin_view_delegate_get_type(), + fl_view_keyboard_plugin_delegate_iface_init)) // Signal handler for GtkWidget::delete-event static gboolean window_delete_event_cb(GtkWidget* widget, @@ -112,6 +121,8 @@ static void init_keyboard(FlView* self) { messenger, im_context, FL_TEXT_INPUT_VIEW_DELEGATE(self)); self->keyboard_manager = fl_keyboard_manager_new(FL_KEYBOARD_VIEW_DELEGATE(self)); + self->keyboard_plugin = + fl_keyboard_plugin_new(messenger, FL_KEYBOARD_PLUGIN_VIEW_DELEGATE(self)); } static void init_scrolling(FlView* self) { @@ -299,6 +310,15 @@ static void fl_view_keyboard_delegate_iface_init( }; } +static void fl_view_keyboard_plugin_delegate_iface_init( + FlKeyboardPluginViewDelegateInterface* iface) { + iface->get_keyboard_state = + [](FlKeyboardPluginViewDelegate* view_delegate) -> GHashTable* { + FlView* self = FL_VIEW(view_delegate); + return fl_view_get_keyboard_state(self); + }; +} + static void fl_view_scrolling_delegate_iface_init( FlScrollingViewDelegateInterface* iface) { iface->send_mouse_pointer_event = @@ -634,6 +654,7 @@ static void fl_view_dispose(GObject* object) { self->keymap_keys_changed_cb_id = 0; } g_clear_object(&self->mouse_cursor_plugin); + g_clear_object(&self->keyboard_plugin); g_clear_object(&self->platform_plugin); G_OBJECT_CLASS(fl_view_parent_class)->dispose(object); @@ -709,3 +730,9 @@ void fl_view_set_textures(FlView* self, fl_gl_area_queue_render(self->gl_area, textures); } + +GHashTable* fl_view_get_keyboard_state(FlView* self) { + g_return_val_if_fail(FL_IS_VIEW(self), nullptr); + + return fl_keyboard_manager_get_pressed_state(self->keyboard_manager); +} diff --git a/shell/platform/linux/fl_view_private.h b/shell/platform/linux/fl_view_private.h index f9650227a88e5..b5a87dcfc2ab3 100644 --- a/shell/platform/linux/fl_view_private.h +++ b/shell/platform/linux/fl_view_private.h @@ -22,4 +22,12 @@ void fl_view_set_textures(FlView* view, GdkGLContext* context, GPtrArray* textures); +/** + * fl_view_get_keyboard_state: + * @view: an #FlView. + * + * Return the keyboard pressed state. + */ +GHashTable* fl_view_get_keyboard_state(FlView* view); + #endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_VIEW_PRIVATE_H_ From 81f420d4c77213709102961996d279c09e71aed2 Mon Sep 17 00:00:00 2001 From: Bruno Leroux Date: Tue, 30 May 2023 11:22:14 +0200 Subject: [PATCH 2/2] Merge KeyboardPlugin in KeyboardManager --- ci/licenses_golden/licenses_flutter | 10 -- shell/platform/linux/BUILD.gn | 4 - .../linux/fl_key_embedder_responder.h | 3 +- shell/platform/linux/fl_keyboard_manager.cc | 58 ++++++++ shell/platform/linux/fl_keyboard_manager.h | 6 +- .../linux/fl_keyboard_manager_test.cc | 64 ++++++++- shell/platform/linux/fl_keyboard_plugin.cc | 111 ---------------- shell/platform/linux/fl_keyboard_plugin.h | 47 ------- .../platform/linux/fl_keyboard_plugin_test.cc | 125 ------------------ .../linux/fl_keyboard_plugin_view_delegate.cc | 20 --- .../linux/fl_keyboard_plugin_view_delegate.h | 40 ------ .../linux/fl_keyboard_view_delegate.cc | 7 + .../linux/fl_keyboard_view_delegate.h | 12 ++ shell/platform/linux/fl_view.cc | 21 +-- shell/platform/linux/fl_view_private.h | 3 +- 15 files changed, 151 insertions(+), 380 deletions(-) delete mode 100644 shell/platform/linux/fl_keyboard_plugin.cc delete mode 100644 shell/platform/linux/fl_keyboard_plugin.h delete mode 100644 shell/platform/linux/fl_keyboard_plugin_test.cc delete mode 100644 shell/platform/linux/fl_keyboard_plugin_view_delegate.cc delete mode 100644 shell/platform/linux/fl_keyboard_plugin_view_delegate.h diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 539b14962ae00..893d479e0dbe4 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -3028,11 +3028,6 @@ ORIGIN: ../../../flutter/shell/platform/linux/fl_key_responder.h + ../../../flut ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_manager.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_manager.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_manager_test.cc + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_plugin.cc + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_plugin.h + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_plugin_test.cc + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_plugin_view_delegate.cc + ../../../flutter/LICENSE -ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_plugin_view_delegate.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_view_delegate.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_view_delegate.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_message_codec.cc + ../../../flutter/LICENSE @@ -5709,11 +5704,6 @@ FILE: ../../../flutter/shell/platform/linux/fl_key_responder.h FILE: ../../../flutter/shell/platform/linux/fl_keyboard_manager.cc FILE: ../../../flutter/shell/platform/linux/fl_keyboard_manager.h FILE: ../../../flutter/shell/platform/linux/fl_keyboard_manager_test.cc -FILE: ../../../flutter/shell/platform/linux/fl_keyboard_plugin.cc -FILE: ../../../flutter/shell/platform/linux/fl_keyboard_plugin.h -FILE: ../../../flutter/shell/platform/linux/fl_keyboard_plugin_test.cc -FILE: ../../../flutter/shell/platform/linux/fl_keyboard_plugin_view_delegate.cc -FILE: ../../../flutter/shell/platform/linux/fl_keyboard_plugin_view_delegate.h FILE: ../../../flutter/shell/platform/linux/fl_keyboard_view_delegate.cc FILE: ../../../flutter/shell/platform/linux/fl_keyboard_view_delegate.h FILE: ../../../flutter/shell/platform/linux/fl_message_codec.cc diff --git a/shell/platform/linux/BUILD.gn b/shell/platform/linux/BUILD.gn index 89d76df7a0fb5..5cb9f2839aaa8 100644 --- a/shell/platform/linux/BUILD.gn +++ b/shell/platform/linux/BUILD.gn @@ -80,7 +80,6 @@ source_set("flutter_linux_sources") { "fl_dart_project_private.h", "fl_engine_private.h", "fl_keyboard_manager.h", - "fl_keyboard_plugin_view_delegate.h", "fl_keyboard_view_delegate.h", "fl_key_event.h", "fl_key_responder.h", @@ -117,8 +116,6 @@ source_set("flutter_linux_sources") { "fl_key_event.cc", "fl_key_responder.cc", "fl_keyboard_manager.cc", - "fl_keyboard_plugin.cc", - "fl_keyboard_plugin_view_delegate.cc", "fl_keyboard_view_delegate.cc", "fl_message_codec.cc", "fl_method_call.cc", @@ -210,7 +207,6 @@ executable("flutter_linux_unittests") { "fl_key_channel_responder_test.cc", "fl_key_embedder_responder_test.cc", "fl_keyboard_manager_test.cc", - "fl_keyboard_plugin_test.cc", "fl_message_codec_test.cc", "fl_method_channel_test.cc", "fl_method_codec_test.cc", diff --git a/shell/platform/linux/fl_key_embedder_responder.h b/shell/platform/linux/fl_key_embedder_responder.h index 025eabde7975e..8937f97e2ec13 100644 --- a/shell/platform/linux/fl_key_embedder_responder.h +++ b/shell/platform/linux/fl_key_embedder_responder.h @@ -68,7 +68,8 @@ void fl_key_embedder_responder_sync_modifiers_if_needed( * fl_key_embedder_responder_get_pressed_state: * @responder: the #FlKeyEmbedderResponder self. * - * Returns the keyboard pressed state. + * Returns the keyboard pressed state. The hash table contains one entry per + * pressed keys, mapping from the logical key to the physical key. */ GHashTable* fl_key_embedder_responder_get_pressed_state( FlKeyEmbedderResponder* responder); diff --git a/shell/platform/linux/fl_keyboard_manager.cc b/shell/platform/linux/fl_keyboard_manager.cc index 4073e54a4dca0..46f70fa2401d2 100644 --- a/shell/platform/linux/fl_keyboard_manager.cc +++ b/shell/platform/linux/fl_keyboard_manager.cc @@ -12,11 +12,16 @@ #include "flutter/shell/platform/linux/fl_key_channel_responder.h" #include "flutter/shell/platform/linux/fl_key_embedder_responder.h" #include "flutter/shell/platform/linux/key_mapping.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_method_channel.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_standard_method_codec.h" // Turn on this flag to print complete layout data when switching IMEs. The data // is used in unit tests. #define DEBUG_PRINT_LAYOUT +static constexpr char kChannelName[] = "flutter/keyboard"; +static constexpr char kGetKeyboardStateMethod[] = "getKeyboardState"; + /* Declarations of private classes */ G_DECLARE_FINAL_TYPE(FlKeyboardPendingEvent, @@ -287,6 +292,9 @@ struct _FlKeyboardManager { // It is set up when the manager is initialized and is not changed ever after. std::unique_ptr> logical_to_mandatory_goals; + + // The channel used by the framework to query the keyboard pressed state. + FlMethodChannel* channel; }; G_DEFINE_TYPE(FlKeyboardManager, fl_keyboard_manager, G_TYPE_OBJECT); @@ -532,7 +540,50 @@ static void guarantee_layout(FlKeyboardManager* self, FlKeyEvent* event) { } } +// Returns the keyboard pressed state. +FlMethodResponse* get_keyboard_state(FlKeyboardManager* self) { + g_autoptr(FlValue) result = fl_value_new_map(); + + GHashTable* pressing_records = + fl_keyboard_view_delegate_get_keyboard_state(self->view_delegate); + + g_hash_table_foreach( + pressing_records, + [](gpointer key, gpointer value, gpointer user_data) { + int64_t physical_key = reinterpret_cast(key); + int64_t logical_key = reinterpret_cast(value); + FlValue* fl_value_map = reinterpret_cast(user_data); + + fl_value_set_take(fl_value_map, fl_value_new_int(physical_key), + fl_value_new_int(logical_key)); + }, + result); + return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); +} + +// Called when a method call on flutter/keyboard is received from Flutter. +static void method_call_handler(FlMethodChannel* channel, + FlMethodCall* method_call, + gpointer user_data) { + FlKeyboardManager* self = FL_KEYBOARD_MANAGER(user_data); + + const gchar* method = fl_method_call_get_name(method_call); + + g_autoptr(FlMethodResponse) response = nullptr; + if (strcmp(method, kGetKeyboardStateMethod) == 0) { + response = get_keyboard_state(self); + } else { + response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new()); + } + + g_autoptr(GError) error = nullptr; + if (!fl_method_call_respond(method_call, response, &error)) { + g_warning("Failed to send method call response: %s", error->message); + } +} + FlKeyboardManager* fl_keyboard_manager_new( + FlBinaryMessenger* messenger, FlKeyboardViewDelegate* view_delegate) { g_return_val_if_fail(FL_IS_KEYBOARD_VIEW_DELEGATE(view_delegate), nullptr); @@ -560,6 +611,13 @@ FlKeyboardManager* fl_keyboard_manager_new( fl_keyboard_view_delegate_subscribe_to_layout_change( self->view_delegate, [self]() { self->derived_layout->clear(); }); + + // Setup the flutter/keyboard channel. + g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); + self->channel = + fl_method_channel_new(messenger, kChannelName, FL_METHOD_CODEC(codec)); + fl_method_channel_set_method_call_handler(self->channel, method_call_handler, + self, nullptr); return self; } diff --git a/shell/platform/linux/fl_keyboard_manager.h b/shell/platform/linux/fl_keyboard_manager.h index 0361ed87c57fb..84f4b574bd28e 100644 --- a/shell/platform/linux/fl_keyboard_manager.h +++ b/shell/platform/linux/fl_keyboard_manager.h @@ -44,6 +44,7 @@ G_DECLARE_FINAL_TYPE(FlKeyboardManager, * Returns: a new #FlKeyboardManager. */ FlKeyboardManager* fl_keyboard_manager_new( + FlBinaryMessenger* messenger, FlKeyboardViewDelegate* view_delegate); /** @@ -87,9 +88,10 @@ void fl_keyboard_manager_sync_modifier_if_needed(FlKeyboardManager* manager, * fl_keyboard_manager_get_pressed_state: * @manager: the #FlKeyboardManager self. * - * Returns the keyboard pressed state. + * Returns the keyboard pressed state. The hash table contains one entry per + * pressed keys, mapping from the logical key to the physical key.* */ -GHashTable* fl_keyboard_manager_get_pressed_state(FlKeyboardManager* responder); +GHashTable* fl_keyboard_manager_get_pressed_state(FlKeyboardManager* manager); G_END_DECLS diff --git a/shell/platform/linux/fl_keyboard_manager_test.cc b/shell/platform/linux/fl_keyboard_manager_test.cc index 0017e6d89aa79..de45994e94850 100644 --- a/shell/platform/linux/fl_keyboard_manager_test.cc +++ b/shell/platform/linux/fl_keyboard_manager_test.cc @@ -8,9 +8,18 @@ #include #include "flutter/shell/platform/embedder/test_utils/key_codes.g.h" +#include "flutter/shell/platform/linux/fl_binary_messenger_private.h" +#include "flutter/shell/platform/linux/fl_method_codec_private.h" #include "flutter/shell/platform/linux/key_mapping.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_json_message_codec.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_method_codec.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_standard_method_codec.h" +#include "flutter/shell/platform/linux/testing/fl_test.h" +#include "flutter/shell/platform/linux/testing/mock_binary_messenger.h" #include "flutter/shell/platform/linux/testing/mock_text_input_plugin.h" +#include "flutter/testing/testing.h" + +#include "gmock/gmock.h" #include "gtest/gtest.h" // Define compound `expect` in macros. If they were defined in functions, the @@ -101,6 +110,10 @@ constexpr guint16 kKeyCodeSemicolon = 0x2fu; constexpr guint16 kKeyCodeKeyLeftBracket = 0x22u; static constexpr char kKeyEventChannelName[] = "flutter/keyevent"; +static constexpr char kKeyboardChannelName[] = "flutter/keyboard"; +static constexpr char kGetKeyboardStateMethod[] = "getKeyboardState"; +static constexpr uint64_t kMockPhysicalKey = 42; +static constexpr uint64_t kMockLogicalKey = 42; // All key clues for a keyboard layout. // @@ -130,6 +143,19 @@ G_DECLARE_FINAL_TYPE(FlMockKeyBinaryMessenger, G_END_DECLS +MATCHER_P(MethodSuccessResponse, result, "") { + g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); + g_autoptr(FlMethodResponse) response = + fl_method_codec_decode_response(FL_METHOD_CODEC(codec), arg, nullptr); + fl_method_response_get_result(response, nullptr); + if (fl_value_equal(fl_method_response_get_result(response, nullptr), + result)) { + return true; + } + *result_listener << ::testing::PrintToString(response); + return false; +} + /***** FlMockKeyBinaryMessenger *****/ /* Mock a binary messenger that only processes messages from the embedding on * the key event channel, and does so according to the callback set by @@ -323,6 +349,15 @@ static guint fl_mock_view_keyboard_lookup_key(FlKeyboardViewDelegate* delegate, return (*group_layout)[key->keycode * 2 + shift]; } +static GHashTable* fl_mock_view_keyboard_get_keyboard_state( + FlKeyboardViewDelegate* view_delegate) { + GHashTable* result = g_hash_table_new(g_direct_hash, g_direct_equal); + g_hash_table_insert(result, reinterpret_cast(kMockPhysicalKey), + reinterpret_cast(kMockLogicalKey)); + + return result; +} + static void fl_mock_view_keyboard_delegate_iface_init( FlKeyboardViewDelegateInterface* iface) { iface->send_key_event = fl_mock_view_keyboard_send_key_event; @@ -332,6 +367,7 @@ static void fl_mock_view_keyboard_delegate_iface_init( iface->subscribe_to_layout_change = fl_mock_view_keyboard_subscribe_to_layout_change; iface->lookup_key = fl_mock_view_keyboard_lookup_key; + iface->get_keyboard_state = fl_mock_view_keyboard_get_keyboard_state; } static FlMockViewDelegate* fl_mock_view_delegate_new() { @@ -407,13 +443,16 @@ static FlKeyEvent* fl_key_event_new_by_mock(bool is_press, class KeyboardTester { public: KeyboardTester() { + ::testing::NiceMock messenger; + view_ = fl_mock_view_delegate_new(); respondToEmbedderCallsWith(false); respondToChannelCallsWith(false); respondToTextInputWith(false); setLayout(kLayoutUs); - manager_ = fl_keyboard_manager_new(FL_KEYBOARD_VIEW_DELEGATE(view_)); + manager_ = + fl_keyboard_manager_new(messenger, FL_KEYBOARD_VIEW_DELEGATE(view_)); } ~KeyboardTester() { @@ -945,6 +984,29 @@ TEST(FlKeyboardManagerTest, GetPressedState) { EXPECT_EQ(gpointer_to_uint64(physical_key), kLogicalKeyA); } +TEST(FlKeyboardPluginTest, KeyboardChannelGetPressedState) { + ::testing::NiceMock messenger; + + g_autoptr(FlKeyboardManager) manager = fl_keyboard_manager_new( + messenger, FL_KEYBOARD_VIEW_DELEGATE(fl_mock_view_delegate_new())); + EXPECT_NE(manager, nullptr); + + g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); + g_autoptr(GBytes) message = fl_method_codec_encode_method_call( + FL_METHOD_CODEC(codec), kGetKeyboardStateMethod, nullptr, nullptr); + + g_autoptr(FlValue) response = fl_value_new_map(); + fl_value_set_take(response, fl_value_new_int(kMockPhysicalKey), + fl_value_new_int(kMockLogicalKey)); + EXPECT_CALL(messenger, + fl_binary_messenger_send_response( + ::testing::Eq(messenger), ::testing::_, + MethodSuccessResponse(response), ::testing::_)) + .WillOnce(::testing::Return(true)); + + messenger.ReceiveMessage(kKeyboardChannelName, message); +} + // The following layout data is generated using DEBUG_PRINT_LAYOUT. const MockGroupLayoutData kLayoutUs0{{ diff --git a/shell/platform/linux/fl_keyboard_plugin.cc b/shell/platform/linux/fl_keyboard_plugin.cc deleted file mode 100644 index bf60f6870730c..0000000000000 --- a/shell/platform/linux/fl_keyboard_plugin.cc +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "flutter/shell/platform/linux/fl_keyboard_plugin.h" - -#include -#include - -#include "flutter/shell/platform/linux/public/flutter_linux/fl_method_channel.h" -#include "flutter/shell/platform/linux/public/flutter_linux/fl_standard_method_codec.h" - -static constexpr char kChannelName[] = "flutter/keyboard"; -static constexpr char kGetKeyboardStateMethod[] = "getKeyboardState"; - -struct _FlKeyboardPlugin { - GObject parent_instance; - - FlMethodChannel* channel; - - FlKeyboardPluginViewDelegate* view_delegate; -}; - -G_DEFINE_TYPE(FlKeyboardPlugin, fl_keyboard_plugin, G_TYPE_OBJECT) - -// Returns the keyboard pressed state. -FlMethodResponse* get_keyboard_state(FlKeyboardPlugin* self) { - g_autoptr(FlValue) result = fl_value_new_map(); - - GHashTable* pressing_records = - fl_keyboard_plugin_view_delegate_get_keyboard_state(self->view_delegate); - - g_hash_table_foreach( - pressing_records, - [](gpointer key, gpointer value, gpointer user_data) { - int64_t physical_key = reinterpret_cast(key); - int64_t logical_key = reinterpret_cast(value); - FlValue* fl_value_map = reinterpret_cast(user_data); - - fl_value_set_take(fl_value_map, fl_value_new_int(physical_key), - fl_value_new_int(logical_key)); - }, - result); - return FL_METHOD_RESPONSE(fl_method_success_response_new(result)); -} - -// Called when a method call is received from Flutter. -static void method_call_cb(FlMethodChannel* channel, - FlMethodCall* method_call, - gpointer user_data) { - FlKeyboardPlugin* self = FL_KEYBOARD_PLUGIN(user_data); - - const gchar* method = fl_method_call_get_name(method_call); - - g_autoptr(FlMethodResponse) response = nullptr; - if (strcmp(method, kGetKeyboardStateMethod) == 0) { - response = get_keyboard_state(self); - } else { - response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new()); - } - - g_autoptr(GError) error = nullptr; - if (!fl_method_call_respond(method_call, response, &error)) { - g_warning("Failed to send method call response: %s", error->message); - } -} - -static void fl_keyboard_plugin_dispose(GObject* object); - -static void fl_keyboard_plugin_class_init(FlKeyboardPluginClass* klass) { - G_OBJECT_CLASS(klass)->dispose = fl_keyboard_plugin_dispose; -} - -static void fl_keyboard_plugin_init(FlKeyboardPlugin* self) {} - -FlKeyboardPlugin* fl_keyboard_plugin_new( - FlBinaryMessenger* messenger, - FlKeyboardPluginViewDelegate* view_delegate) { - g_return_val_if_fail(FL_IS_BINARY_MESSENGER(messenger), nullptr); - g_return_val_if_fail(FL_IS_KEYBOARD_PLUGIN_VIEW_DELEGATE(view_delegate), - nullptr); - - FlKeyboardPlugin* self = - FL_KEYBOARD_PLUGIN(g_object_new(fl_keyboard_plugin_get_type(), nullptr)); - - g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); - self->channel = - fl_method_channel_new(messenger, kChannelName, FL_METHOD_CODEC(codec)); - fl_method_channel_set_method_call_handler(self->channel, method_call_cb, self, - nullptr); - self->view_delegate = view_delegate; - g_object_add_weak_pointer( - G_OBJECT(view_delegate), - reinterpret_cast(&(self->view_delegate))); - - return self; -} - -static void fl_keyboard_plugin_dispose(GObject* object) { - FlKeyboardPlugin* self = FL_KEYBOARD_PLUGIN(object); - - g_clear_object(&self->channel); - if (self->view_delegate != nullptr) { - g_object_remove_weak_pointer( - G_OBJECT(self->view_delegate), - reinterpret_cast(&(self->view_delegate))); - self->view_delegate = nullptr; - } - - G_OBJECT_CLASS(fl_keyboard_plugin_parent_class)->dispose(object); -} diff --git a/shell/platform/linux/fl_keyboard_plugin.h b/shell/platform/linux/fl_keyboard_plugin.h deleted file mode 100644 index 1d0d6c5da8e66..0000000000000 --- a/shell/platform/linux/fl_keyboard_plugin.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef FLUTTER_SHELL_PLATFORM_LINUX_FL_KEYBOARD_PLUGIN_H_ -#define FLUTTER_SHELL_PLATFORM_LINUX_FL_KEYBOARD_PLUGIN_H_ - -#include - -#include "flutter/shell/platform/linux/fl_keyboard_plugin_view_delegate.h" -#include "flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h" -#include "flutter/shell/platform/linux/public/flutter_linux/fl_view.h" - -G_BEGIN_DECLS - -#define FL_TYPE_KEYBOARD_PLUGIN fl_keyboard_plugin_get_type() -G_DECLARE_FINAL_TYPE(FlKeyboardPlugin, - fl_keyboard_plugin, - FL, - KEYBOARD_PLUGIN, - GObject); - -/** - * FlKeyboardPlugin: - * - * #FlKeyboardPlugin is a keyboard channel that implements the shell side - * of SystemChannels.keyboard from the Flutter services library. - */ - -/** - * fl_keyboard_plugin_new: - * @messenger: an #FlBinaryMessenger. - * @view_delegate: An interface that the plugin requires to communicate with - * the platform. Usually implemented by FlView. - * - * Creates a new plugin that implements SystemChannels.keyboard from the - * Flutter services library. - * - * Returns: a new #FlKeyboardPlugin. - */ -FlKeyboardPlugin* fl_keyboard_plugin_new( - FlBinaryMessenger* messenger, - FlKeyboardPluginViewDelegate* view_delegate); - -G_END_DECLS - -#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_KEYBOARD_PLUGIN_H_ diff --git a/shell/platform/linux/fl_keyboard_plugin_test.cc b/shell/platform/linux/fl_keyboard_plugin_test.cc deleted file mode 100644 index 0274618a0d312..0000000000000 --- a/shell/platform/linux/fl_keyboard_plugin_test.cc +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "flutter/shell/platform/linux/fl_keyboard_plugin.h" -#include "flutter/shell/platform/linux/fl_binary_messenger_private.h" -#include "flutter/shell/platform/linux/fl_method_codec_private.h" -#include "flutter/shell/platform/linux/public/flutter_linux/fl_method_codec.h" -#include "flutter/shell/platform/linux/public/flutter_linux/fl_standard_method_codec.h" -#include "flutter/shell/platform/linux/testing/fl_test.h" -#include "flutter/shell/platform/linux/testing/mock_binary_messenger.h" -#include "flutter/testing/testing.h" - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -static constexpr char kChannelName[] = "flutter/keyboard"; -static constexpr char kGetKeyboardStateMethod[] = "getKeyboardState"; -static constexpr uint64_t kMockPhysicalKey = 42; -static constexpr uint64_t kMockLogicalKey = 42; - -G_BEGIN_DECLS - -G_DECLARE_FINAL_TYPE(FlMockKeyboardPluginViewDelegate, - fl_mock_keyboard_plugin_view_delegate, - FL, - MOCK_KEYBOARD_PLUGIN_VIEW_DELEGATE, - GObject); - -G_END_DECLS - -MATCHER_P(MethodSuccessResponse, result, "") { - g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); - g_autoptr(FlMethodResponse) response = - fl_method_codec_decode_response(FL_METHOD_CODEC(codec), arg, nullptr); - fl_method_response_get_result(response, nullptr); - if (fl_value_equal(fl_method_response_get_result(response, nullptr), - result)) { - return true; - } - *result_listener << ::testing::PrintToString(response); - return false; -} - -struct _FlMockKeyboardPluginViewDelegate { - GObject parent_instance; -}; - -static void fl_mock_view_keyboard_plugin_delegate_iface_init( - FlKeyboardPluginViewDelegateInterface* iface); - -G_DEFINE_TYPE_WITH_CODE( - FlMockKeyboardPluginViewDelegate, - fl_mock_keyboard_plugin_view_delegate, - G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE(fl_keyboard_plugin_view_delegate_get_type(), - fl_mock_view_keyboard_plugin_delegate_iface_init)) - -static void fl_mock_keyboard_plugin_view_delegate_init( - FlMockKeyboardPluginViewDelegate* self) {} - -static void fl_mock_keyboard_plugin_view_delegate_dispose(GObject* object) { - G_OBJECT_CLASS(fl_mock_keyboard_plugin_view_delegate_parent_class) - ->dispose(object); -} - -static void fl_mock_keyboard_plugin_view_delegate_class_init( - FlMockKeyboardPluginViewDelegateClass* klass) { - G_OBJECT_CLASS(klass)->dispose = - fl_mock_keyboard_plugin_view_delegate_dispose; -} - -static GHashTable* fl_mock_keyboard_plugin_view_delegate_get_keyboard_state( - FlKeyboardPluginViewDelegate* view_delegate); - -static void fl_mock_view_keyboard_plugin_delegate_iface_init( - FlKeyboardPluginViewDelegateInterface* iface) { - iface->get_keyboard_state = - fl_mock_keyboard_plugin_view_delegate_get_keyboard_state; -} - -static FlMockKeyboardPluginViewDelegate* -fl_mock_keyboard_plugin_view_delegate_new() { - FlMockKeyboardPluginViewDelegate* self = - FL_MOCK_KEYBOARD_PLUGIN_VIEW_DELEGATE(g_object_new( - fl_mock_keyboard_plugin_view_delegate_get_type(), nullptr)); - - // Added to stop compiler complaining about an unused function. - FL_IS_MOCK_KEYBOARD_PLUGIN_VIEW_DELEGATE(self); - - return self; -} - -static GHashTable* fl_mock_keyboard_plugin_view_delegate_get_keyboard_state( - FlKeyboardPluginViewDelegate* view_delegate) { - GHashTable* result = g_hash_table_new(g_direct_hash, g_direct_equal); - g_hash_table_insert(result, reinterpret_cast(kMockPhysicalKey), - reinterpret_cast(kMockLogicalKey)); - - return result; -} - -TEST(FlKeyboardPluginTest, GetPressedState) { - ::testing::NiceMock messenger; - - g_autoptr(FlKeyboardPlugin) plugin = fl_keyboard_plugin_new( - messenger, FL_KEYBOARD_PLUGIN_VIEW_DELEGATE( - fl_mock_keyboard_plugin_view_delegate_new())); - EXPECT_NE(plugin, nullptr); - - g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); - g_autoptr(GBytes) message = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), kGetKeyboardStateMethod, nullptr, nullptr); - - g_autoptr(FlValue) response = fl_value_new_map(); - fl_value_set_take(response, fl_value_new_int(kMockPhysicalKey), - fl_value_new_int(kMockLogicalKey)); - EXPECT_CALL(messenger, - fl_binary_messenger_send_response( - ::testing::Eq(messenger), ::testing::_, - MethodSuccessResponse(response), ::testing::_)) - .WillOnce(::testing::Return(true)); - - messenger.ReceiveMessage(kChannelName, message); -} diff --git a/shell/platform/linux/fl_keyboard_plugin_view_delegate.cc b/shell/platform/linux/fl_keyboard_plugin_view_delegate.cc deleted file mode 100644 index d25a98ffecfd6..0000000000000 --- a/shell/platform/linux/fl_keyboard_plugin_view_delegate.cc +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "flutter/shell/platform/linux/fl_keyboard_plugin_view_delegate.h" - -G_DEFINE_INTERFACE(FlKeyboardPluginViewDelegate, - fl_keyboard_plugin_view_delegate, - G_TYPE_OBJECT) - -static void fl_keyboard_plugin_view_delegate_default_init( - FlKeyboardPluginViewDelegateInterface* iface) {} - -GHashTable* fl_keyboard_plugin_view_delegate_get_keyboard_state( - FlKeyboardPluginViewDelegate* self) { - g_return_val_if_fail(FL_IS_KEYBOARD_PLUGIN_VIEW_DELEGATE(self), nullptr); - - return FL_KEYBOARD_PLUGIN_VIEW_DELEGATE_GET_IFACE(self)->get_keyboard_state( - self); -} diff --git a/shell/platform/linux/fl_keyboard_plugin_view_delegate.h b/shell/platform/linux/fl_keyboard_plugin_view_delegate.h deleted file mode 100644 index 03d627d64ea7d..0000000000000 --- a/shell/platform/linux/fl_keyboard_plugin_view_delegate.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef FLUTTER_SHELL_PLATFORM_LINUX_FL_KEYBOARD_PLUGIN_VIEW_DELEGATE_H_ -#define FLUTTER_SHELL_PLATFORM_LINUX_FL_KEYBOARD_PLUGIN_VIEW_DELEGATE_H_ - -#include -#include -#include - -G_BEGIN_DECLS - -G_DECLARE_INTERFACE(FlKeyboardPluginViewDelegate, - fl_keyboard_plugin_view_delegate, - FL, - KEYBOARD_PLUGIN_VIEW_DELEGATE, - GObject); - -/** - * FlKeyboardPluginViewDelegate: - * - * An interface for a class that provides `FlKeyboardPlugin` with - * view-related features. - * - * This interface is typically implemented by `FlView`. - */ - -struct _FlKeyboardPluginViewDelegateInterface { - GTypeInterface g_iface; - - GHashTable* (*get_keyboard_state)(FlKeyboardPluginViewDelegate* delegate); -}; - -GHashTable* fl_keyboard_plugin_view_delegate_get_keyboard_state( - FlKeyboardPluginViewDelegate* self); - -G_END_DECLS - -#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_KEYBOARD_PLUGIN_VIEW_DELEGATE_H_ diff --git a/shell/platform/linux/fl_keyboard_view_delegate.cc b/shell/platform/linux/fl_keyboard_view_delegate.cc index b2a724acfa415..3c5fac95a8c4d 100644 --- a/shell/platform/linux/fl_keyboard_view_delegate.cc +++ b/shell/platform/linux/fl_keyboard_view_delegate.cc @@ -64,3 +64,10 @@ guint fl_keyboard_view_delegate_lookup_key(FlKeyboardViewDelegate* self, return FL_KEYBOARD_VIEW_DELEGATE_GET_IFACE(self)->lookup_key(self, key); } + +GHashTable* fl_keyboard_view_delegate_get_keyboard_state( + FlKeyboardViewDelegate* self) { + g_return_val_if_fail(FL_IS_KEYBOARD_VIEW_DELEGATE(self), nullptr); + + return FL_KEYBOARD_VIEW_DELEGATE_GET_IFACE(self)->get_keyboard_state(self); +} diff --git a/shell/platform/linux/fl_keyboard_view_delegate.h b/shell/platform/linux/fl_keyboard_view_delegate.h index 041cb0029e143..6d66b12ca3537 100644 --- a/shell/platform/linux/fl_keyboard_view_delegate.h +++ b/shell/platform/linux/fl_keyboard_view_delegate.h @@ -54,6 +54,8 @@ struct _FlKeyboardViewDelegateInterface { guint (*lookup_key)(FlKeyboardViewDelegate* view_delegate, const GdkKeymapKey* key); + + GHashTable* (*get_keyboard_state)(FlKeyboardViewDelegate* delegate); }; /** @@ -116,6 +118,16 @@ void fl_keyboard_view_delegate_subscribe_to_layout_change( guint fl_keyboard_view_delegate_lookup_key(FlKeyboardViewDelegate* delegate, const GdkKeymapKey* key); +/** + * fl_keyboard_view_delegate_get_keyboard_state: + * + * Returns the keyboard pressed state. The hash table contains one entry per + * pressed keys, mapping from the logical key to the physical key.* + * + */ +GHashTable* fl_keyboard_view_delegate_get_keyboard_state( + FlKeyboardViewDelegate* delegate); + G_END_DECLS #endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_KEYBOARD_VIEW_DELEGATE_H_ diff --git a/shell/platform/linux/fl_view.cc b/shell/platform/linux/fl_view.cc index 6669b7ac22366..c1c5b547c6f6e 100644 --- a/shell/platform/linux/fl_view.cc +++ b/shell/platform/linux/fl_view.cc @@ -12,8 +12,6 @@ #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_manager.h" -#include "flutter/shell/platform/linux/fl_keyboard_plugin.h" -#include "flutter/shell/platform/linux/fl_keyboard_plugin_view_delegate.h" #include "flutter/shell/platform/linux/fl_keyboard_view_delegate.h" #include "flutter/shell/platform/linux/fl_mouse_cursor_plugin.h" #include "flutter/shell/platform/linux/fl_platform_plugin.h" @@ -50,7 +48,6 @@ struct _FlView { FlScrollingManager* scrolling_manager; FlTextInputPlugin* text_input_plugin; FlMouseCursorPlugin* mouse_cursor_plugin; - FlKeyboardPlugin* keyboard_plugin; FlPlatformPlugin* platform_plugin; GtkWidget* event_box; @@ -79,9 +76,6 @@ static void fl_view_scrolling_delegate_iface_init( static void fl_view_text_input_delegate_iface_init( FlTextInputViewDelegateInterface* iface); -static void fl_view_keyboard_plugin_delegate_iface_init( - FlKeyboardPluginViewDelegateInterface* iface); - G_DEFINE_TYPE_WITH_CODE( FlView, fl_view, @@ -93,10 +87,7 @@ G_DEFINE_TYPE_WITH_CODE( G_IMPLEMENT_INTERFACE(fl_scrolling_view_delegate_get_type(), fl_view_scrolling_delegate_iface_init) G_IMPLEMENT_INTERFACE(fl_text_input_view_delegate_get_type(), - fl_view_text_input_delegate_iface_init) - G_IMPLEMENT_INTERFACE( - fl_keyboard_plugin_view_delegate_get_type(), - fl_view_keyboard_plugin_delegate_iface_init)) + fl_view_text_input_delegate_iface_init)) // Signal handler for GtkWidget::delete-event static gboolean window_delete_event_cb(GtkWidget* widget, @@ -120,9 +111,7 @@ static void init_keyboard(FlView* self) { self->text_input_plugin = fl_text_input_plugin_new( messenger, im_context, FL_TEXT_INPUT_VIEW_DELEGATE(self)); self->keyboard_manager = - fl_keyboard_manager_new(FL_KEYBOARD_VIEW_DELEGATE(self)); - self->keyboard_plugin = - fl_keyboard_plugin_new(messenger, FL_KEYBOARD_PLUGIN_VIEW_DELEGATE(self)); + fl_keyboard_manager_new(messenger, FL_KEYBOARD_VIEW_DELEGATE(self)); } static void init_scrolling(FlView* self) { @@ -308,12 +297,9 @@ static void fl_view_keyboard_delegate_iface_init( g_return_val_if_fail(self->keymap != nullptr, 0); return gdk_keymap_lookup_key(self->keymap, key); }; -} -static void fl_view_keyboard_plugin_delegate_iface_init( - FlKeyboardPluginViewDelegateInterface* iface) { iface->get_keyboard_state = - [](FlKeyboardPluginViewDelegate* view_delegate) -> GHashTable* { + [](FlKeyboardViewDelegate* view_delegate) -> GHashTable* { FlView* self = FL_VIEW(view_delegate); return fl_view_get_keyboard_state(self); }; @@ -654,7 +640,6 @@ static void fl_view_dispose(GObject* object) { self->keymap_keys_changed_cb_id = 0; } g_clear_object(&self->mouse_cursor_plugin); - g_clear_object(&self->keyboard_plugin); g_clear_object(&self->platform_plugin); G_OBJECT_CLASS(fl_view_parent_class)->dispose(object); diff --git a/shell/platform/linux/fl_view_private.h b/shell/platform/linux/fl_view_private.h index b5a87dcfc2ab3..dffc5114e5387 100644 --- a/shell/platform/linux/fl_view_private.h +++ b/shell/platform/linux/fl_view_private.h @@ -26,7 +26,8 @@ void fl_view_set_textures(FlView* view, * fl_view_get_keyboard_state: * @view: an #FlView. * - * Return the keyboard pressed state. + * Returns the keyboard pressed state. The hash table contains one entry per + * pressed keys, mapping from the logical key to the physical key.* */ GHashTable* fl_view_get_keyboard_state(FlView* view);