From 2a7e219509a0b5d3f1cd52ad65b62d93378e5058 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Wed, 31 Mar 2021 22:58:07 -0700 Subject: [PATCH 001/126] infra --- shell/platform/linux/BUILD.gn | 7 +- .../linux/fl_key_channel_responder.cc | 379 ++++++++++++++++++ .../platform/linux/fl_key_channel_responder.h | 56 +++ shell/platform/linux/fl_key_responder.cc | 17 + shell/platform/linux/fl_key_responder.h | 51 +++ shell/platform/linux/fl_keyboard_manager.cc | 208 ++++++++++ shell/platform/linux/fl_keyboard_manager.h | 74 ++++ shell/platform/linux/fl_view.cc | 19 +- 8 files changed, 802 insertions(+), 9 deletions(-) create mode 100644 shell/platform/linux/fl_key_channel_responder.cc create mode 100644 shell/platform/linux/fl_key_channel_responder.h create mode 100644 shell/platform/linux/fl_key_responder.cc create mode 100644 shell/platform/linux/fl_key_responder.h create mode 100644 shell/platform/linux/fl_keyboard_manager.cc create mode 100644 shell/platform/linux/fl_keyboard_manager.h diff --git a/shell/platform/linux/BUILD.gn b/shell/platform/linux/BUILD.gn index 038909683bc18..ac10603b996a3 100644 --- a/shell/platform/linux/BUILD.gn +++ b/shell/platform/linux/BUILD.gn @@ -74,7 +74,9 @@ source_set("flutter_linux_sources") { "fl_binary_messenger_private.h", "fl_dart_project_private.h", "fl_engine_private.h", - "fl_key_event_plugin_private.h", + "fl_keyboard_manager.h", + "fl_key_responder.h", + "fl_key_channel_responder.h", "fl_method_call_private.h", "fl_method_channel_private.h", "fl_method_codec_private.h", @@ -97,7 +99,8 @@ source_set("flutter_linux_sources") { "fl_gl_area.cc", "fl_json_message_codec.cc", "fl_json_method_codec.cc", - "fl_key_event_plugin.cc", + "fl_keyboard_manager.cc", + "fl_key_channel_responder.cc", "fl_message_codec.cc", "fl_method_call.cc", "fl_method_channel.cc", diff --git a/shell/platform/linux/fl_key_channel_responder.cc b/shell/platform/linux/fl_key_channel_responder.cc new file mode 100644 index 0000000000000..8ec847c95713a --- /dev/null +++ b/shell/platform/linux/fl_key_channel_responder.cc @@ -0,0 +1,379 @@ +// 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_key_event_plugin.h" +#include "flutter/shell/platform/linux/fl_key_event_plugin_private.h" + +#include +#include + +#include "flutter/shell/platform/linux/fl_text_input_plugin.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_basic_message_channel.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_json_message_codec.h" + +static constexpr char kChannelName[] = "flutter/keyevent"; +static constexpr char kTypeKey[] = "type"; +static constexpr char kTypeValueUp[] = "keyup"; +static constexpr char kTypeValueDown[] = "keydown"; +static constexpr char kKeymapKey[] = "keymap"; +static constexpr char kKeyCodeKey[] = "keyCode"; +static constexpr char kScanCodeKey[] = "scanCode"; +static constexpr char kModifiersKey[] = "modifiers"; +static constexpr char kToolkitKey[] = "toolkit"; +static constexpr char kUnicodeScalarValuesKey[] = "unicodeScalarValues"; + +static constexpr char kGtkToolkit[] = "gtk"; +static constexpr char kLinuxKeymap[] = "linux"; + +static constexpr uint64_t kMaxPendingEvents = 1000; + +static void fl_key_channel_responder_iface_init(FlKeyResponder* iface); + +// Definition of the FlKeyEventPlugin GObject class. + +struct _FlKeyEventPlugin { + GObject parent_instance; + + FlKeybaordManager* manager; + FlBasicMessageChannel* channel; + GPtrArray* pending_events; + uint64_t last_id; +}; + +G_DEFINE_TYPE_WITH_CODE( + FlKeyChannelResponder, + fl_key_channel_responder, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE(fl_key_responder_get_type(), + fl_key_channel_responder_iface_init)) + +static void fl_engine_plugin_registry_iface_init( + FlKeyResponder* iface) { + iface->handle_event = fl_key_channel_responder_handle_event; +} + +// Declare and define a private pair object to bind the id and the event +// together. + +G_DECLARE_FINAL_TYPE(FlKeyEventPair, + fl_key_event_pair, + FL, + KEY_EVENT_PAIR, + GObject); + +G_DEFINE_TYPE(FlKeyEventPair, fl_key_event_pair, G_TYPE_OBJECT) + +// Dispose method for FlKeyEventPair. +static void fl_key_event_pair_dispose(GObject* object) { + // Redundant, but added so that we don't get a warning about unused function + // for FL_IS_KEY_EVENT_PAIR. + g_return_if_fail(FL_IS_KEY_EVENT_PAIR(object)); + + FlKeyEventPair* self = FL_KEY_EVENT_PAIR(object); + g_clear_pointer(&self->event, gdk_event_free); + G_OBJECT_CLASS(fl_key_event_pair_parent_class)->dispose(object); +} + +// Class Initialization method for FlKeyEventPair class. +static void fl_key_event_pair_class_init(FlKeyEventPairClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_key_event_pair_dispose; +} + +// Initialization for FlKeyEventPair instances. +static void fl_key_event_pair_init(FlKeyEventPair* self) {} + +// Creates a new FlKeyEventPair instance, given a unique ID, and an event struct +// to keep. +FlKeyEventPair* fl_key_event_pair_new(uint64_t id, GdkEventKey* event) { + FlKeyEventPair* self = + FL_KEY_EVENT_PAIR(g_object_new(fl_key_event_pair_get_type(), nullptr)); + + // Copy the event to preserve refcounts for referenced values (mainly the + // window). + GdkEventKey* event_copy = reinterpret_cast( + gdk_event_copy(reinterpret_cast(event))); + self->id = id; + self->event = event_copy; + return self; +} + +// Declare and define a private class to hold response data from the framework. +G_DECLARE_FINAL_TYPE(FlKeyEventResponseData, + fl_key_event_response_data, + FL, + KEY_EVENT_RESPONSE_DATA, + GObject); + +struct _FlKeyEventResponseData { + GObject parent_instance; + + FlKeyEventPlugin* plugin; + uint64_t id; + FlKeyResponderAsyncCallback callback; + gpointer user_data; +}; + +// Definition for FlKeyEventResponseData private class. +G_DEFINE_TYPE(FlKeyEventResponseData, fl_key_event_response_data, G_TYPE_OBJECT) + +// Dispose method for FlKeyEventResponseData private class. +static void fl_key_event_response_data_dispose(GObject* object) { + g_return_if_fail(FL_IS_KEY_EVENT_RESPONSE_DATA(object)); + FlKeyEventResponseData* self = FL_KEY_EVENT_RESPONSE_DATA(object); + if (self->plugin != nullptr) { + g_object_remove_weak_pointer(G_OBJECT(self->plugin), + reinterpret_cast(&(self->plugin))); + self->plugin = nullptr; + } +} + +// Class initialization method for FlKeyEventResponseData private class. +static void fl_key_event_response_data_class_init( + FlKeyEventResponseDataClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_key_event_response_data_dispose; +} + +// Instance initialization method for FlKeyEventResponseData private class. +static void fl_key_event_response_data_init(FlKeyEventResponseData* self) {} + +// Creates a new FlKeyEventResponseData private class with a plugin that created +// the request, a unique ID for tracking, and optional user data. +// Will keep a weak pointer to the plugin. +FlKeyEventResponseData* fl_key_event_response_data_new(FlKeyEventPlugin* plugin, + uint64_t id, + FlKeyResponderAsyncCallback callback, + gpointer user_data) { + FlKeyEventResponseData* self = FL_KEY_EVENT_RESPONSE_DATA( + g_object_new(fl_key_event_response_data_get_type(), nullptr)); + + self->plugin = plugin; + // Add a weak pointer so we can know if the key event plugin disappeared + // while the framework was responding. + g_object_add_weak_pointer(G_OBJECT(plugin), + reinterpret_cast(&(self->plugin))); + self->id = id; + self->callback = callback; + self->user_data = user_data; + return self; +} + +// Finds an event in the event queue that was sent to the framework by its ID. +GdkEventKey* fl_key_event_plugin_find_pending_event(FlKeyEventPlugin* self, + uint64_t id) { + for (guint i = 0; i < self->pending_events->len; ++i) { + if (FL_KEY_EVENT_PAIR(g_ptr_array_index(self->pending_events, i))->id == + id) { + return FL_KEY_EVENT_PAIR(g_ptr_array_index(self->pending_events, i)) + ->event; + } + } + return nullptr; +} + +// Removes an event from the pending event queue. +static void remove_pending_event(FlKeyEventPlugin* self, uint64_t id) { + for (guint i = 0; i < self->pending_events->len; ++i) { + if (FL_KEY_EVENT_PAIR(g_ptr_array_index(self->pending_events, i))->id == + id) { + g_ptr_array_remove_index(self->pending_events, i); + return; + } + } + g_warning("Tried to remove pending event with id %" PRIu64 + ", but the event was not found.", + id); +} + +// Adds an GdkEventKey to the pending event queue, with a unique ID, and the +// plugin that added it. +static void add_pending_event(FlKeyEventPlugin* self, + uint64_t id, + GdkEventKey* event) { + if (self->pending_events->len > kMaxPendingEvents) { + g_warning( + "There are %d keyboard events that have not yet received a " + "response from the framework. Are responses being sent?", + self->pending_events->len); + } + g_ptr_array_add(self->pending_events, fl_key_event_pair_new(id, event)); +} + +// Handles a response from the framework to a key event sent to the framework +// earlier. +static void handle_response(GObject* object, + GAsyncResult* result, + gpointer user_data) { + g_autoptr(FlKeyEventResponseData) data = + FL_KEY_EVENT_RESPONSE_DATA(user_data); + + // Will also return if the weak pointer has been destroyed. + if (data->plugin == nullptr) { + return; + } + + FlKeyEventPlugin* self = data->plugin; + + g_autoptr(GError) error = nullptr; + FlBasicMessageChannel* messageChannel = FL_BASIC_MESSAGE_CHANNEL(object); + FlValue* message = + fl_basic_message_channel_send_finish(messageChannel, result, &error); + if (error != nullptr) { + g_warning("Unable to retrieve framework response: %s", error->message); + return; + } + g_autoptr(FlValue) handled_value = fl_value_lookup_string(message, "handled"); + bool handled = fl_value_get_bool(handled_value); + + remove_pending_event(self, data->id); + data->callback(self->manager, data->id, handled); +} + +// Disposes of an FlKeyEventPlugin instance. +static void fl_key_event_plugin_dispose(GObject* object) { + FlKeyEventPlugin* self = FL_KEY_CHANNEL_RESPONDER(object); + + g_clear_object(&self->channel); + if (self->text_input_plugin != nullptr) { + g_object_remove_weak_pointer( + G_OBJECT(self->text_input_plugin), + reinterpret_cast(&(self->text_input_plugin))); + self->text_input_plugin = nullptr; + } + g_ptr_array_free(self->pending_events, TRUE); + + G_OBJECT_CLASS(fl_key_event_plugin_parent_class)->dispose(object); +} + +// Initializes the FlKeyEventPlugin class methods. +static void fl_key_event_plugin_class_init(FlKeyEventPluginClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_key_event_plugin_dispose; +} + +// Initializes an FlKeyEventPlugin instance. +static void fl_key_event_plugin_init(FlKeyEventPlugin* self) {} + +// Creates a new FlKeyEventPlugin instance, with a messenger used to send +// messages to the framework, an FlTextInputPlugin used to handle key events +// that the framework doesn't handle. Mainly for testing purposes, it also takes +// an optional callback to call when a response is received, and an optional +// channel name to use when sending messages. +FlKeyEventPlugin* fl_key_event_plugin_new( + FlKeybaordManager* manager, + FlBinaryMessenger* messenger) { + g_return_val_if_fail(FL_IS_BINARY_MESSENGER(messenger), nullptr); + + FlKeyChannelResponder* self = FL_KEY_CHANNEL_RESPONDER(g_object_new(FL_KEY_CHANNEL_RESPONDER, nullptr)); + self->last_id = 1; + self->manager = manager; + + g_autoptr(FlJsonMessageCodec) codec = fl_json_message_codec_new(); + self->channel = fl_basic_message_channel_new( + messenger, channel_name == nullptr ? kChannelName : channel_name, + FL_MESSAGE_CODEC(codec)); + + self->pending_events = g_ptr_array_new_with_free_func(g_object_unref); + return self; +} + +// Sends a key event to the framework. +bool fl_key_channel_responder_handle_event( + FlKeyResponder* responder, + GdkEventKey* event, + FlKeyResponderAsyncCallback callback, + gpointer user_data) { + FlKeyChannelResponder* self = FL_KEY_EVENT_PLUGIN(responder); + g_return_val_if_fail(event != nullptr, FALSE); + g_return_val_if_fail(callback != nullptr, FALSE); + + uint64_t id = (++self->last_id); + + const gchar* type; + switch (event->type) { + case GDK_KEY_PRESS: + type = kTypeValueDown; + break; + case GDK_KEY_RELEASE: + type = kTypeValueUp; + break; + default: + return FALSE; + } + + int64_t scan_code = event->hardware_keycode; + int64_t unicodeScalarValues = gdk_keyval_to_unicode(event->keyval); + + // For most modifier keys, GTK keeps track of the "pressed" state of the + // modifier keys. Flutter uses this information to keep modifier keys from + // being "stuck" when a key-up event is lost because it happens after the app + // loses focus. + // + // For Lock keys (ShiftLock, CapsLock, NumLock), however, GTK keeps track of + // the state of the locks themselves, not the "pressed" state of the key. + // + // Since Flutter expects the "pressed" state of the modifier keys, the lock + // state for these keys is discarded here, and it is substituted for the + // pressed state of the key. + // + // This code has the flaw that if a key event is missed due to the app losing + // focus, then this state will still think the key is pressed when it isn't, + // but that is no worse than for "regular" keys until we implement the + // sync/cancel events on app focus changes. + // + // This is necessary to do here instead of in the framework because Flutter + // does modifier key syncing in the framework, and will turn on/off these keys + // as being "pressed" whenever the lock is on, which breaks a lot of + // interactions (for example, if shift-lock is on, tab traversal is broken). + // + // TODO(gspencergoog): get rid of this tracked state when we are tracking the + // state of all keys and sending sync/cancel events when focus is gained/lost. + + // Remove lock states from state mask. + guint state = event->state & ~(GDK_LOCK_MASK | GDK_MOD2_MASK); + + static bool shift_lock_pressed = FALSE; + static bool caps_lock_pressed = FALSE; + static bool num_lock_pressed = FALSE; + switch (event->keyval) { + case GDK_KEY_Num_Lock: + num_lock_pressed = event->type == GDK_KEY_PRESS; + break; + case GDK_KEY_Caps_Lock: + caps_lock_pressed = event->type == GDK_KEY_PRESS; + break; + case GDK_KEY_Shift_Lock: + shift_lock_pressed = event->type == GDK_KEY_PRESS; + break; + } + + // Add back in the state matching the actual pressed state of the lock keys, + // not the lock states. + state |= (shift_lock_pressed || caps_lock_pressed) ? GDK_LOCK_MASK : 0x0; + state |= num_lock_pressed ? GDK_MOD2_MASK : 0x0; + + g_autoptr(FlValue) message = fl_value_new_map(); + fl_value_set_string_take(message, kTypeKey, fl_value_new_string(type)); + fl_value_set_string_take(message, kKeymapKey, + fl_value_new_string(kLinuxKeymap)); + fl_value_set_string_take(message, kScanCodeKey, fl_value_new_int(scan_code)); + fl_value_set_string_take(message, kToolkitKey, + fl_value_new_string(kGtkToolkit)); + fl_value_set_string_take(message, kKeyCodeKey, + fl_value_new_int(event->keyval)); + fl_value_set_string_take(message, kModifiersKey, fl_value_new_int(state)); + if (unicodeScalarValues != 0) { + fl_value_set_string_take(message, kUnicodeScalarValuesKey, + fl_value_new_int(unicodeScalarValues)); + } + + // Track the event as pending a response from the framework. + add_pending_event(self, id, event); + FlKeyEventResponseData* data = + fl_key_event_response_data_new(self, id, callback, user_data); + // Send the message off to the framework for handling (or not). + fl_basic_message_channel_send(self->channel, message, nullptr, + handle_response, data); + // Return true before we know what the framework will do, because if it + // doesn't handle the key, we'll re-dispatch it later. + return TRUE; +} diff --git a/shell/platform/linux/fl_key_channel_responder.h b/shell/platform/linux/fl_key_channel_responder.h new file mode 100644 index 0000000000000..446ce57a74bf0 --- /dev/null +++ b/shell/platform/linux/fl_key_channel_responder.h @@ -0,0 +1,56 @@ +// 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_KEY_CHANNEL_RESPONDER_H_ +#define FLUTTER_SHELL_PLATFORM_LINUX_FL_KEY_CHANNEL_RESPONDER_H_ + +#include "flutter/shell/platform/linux/fl_keyboard_manager.h" +#include "flutter/shell/platform/linux/fl_key_responder.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_value.h" + +#include + +G_BEGIN_DECLS + +G_DECLARE_FINAL_TYPE(FlKeyChannelResponder, + fl_key_channel_responder, + FL, + KEY_CHANNEL_RESPONDER, + GObject); + +/** + * FlKeyChannelResponder: + * + * #FlKeyChannelResponder is a plugin that implements the shell side + * of SystemChannels.keyEvent from the Flutter services library. + */ + +/** + * fl_key_channel_responder_new: + * @messenger: an #FlBinaryMessenger. + * @response_callback: the callback to call when a response is received. If not + * given (nullptr), then the default response callback is + * used. Typically used for tests to receive event + * information. If specified, unhandled events will not be + * re-dispatched. + * @text_input_plugin: The #FlTextInputPlugin to send key events to if the + * framework doesn't handle them. + * @channel_name: the name of the channel to send key events to the framework + * on. If not given (nullptr), then the standard key event + * channel name is used. Typically used for tests to send on a + * test channel. + * + * Creates a new plugin that implements SystemChannels.keyEvent from the + * Flutter services library. + * + * Returns: a new #FlKeyChannelResponder. + */ +FlKeyChannelResponder* fl_key_channel_responder_new( + FlKeybaordManager* manager, + FlBinaryMessenger* messenger); + +G_END_DECLS + +#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_KEY_CHANNEL_RESPONDER_H_ diff --git a/shell/platform/linux/fl_key_responder.cc b/shell/platform/linux/fl_key_responder.cc new file mode 100644 index 0000000000000..e34f8f300df5e --- /dev/null +++ b/shell/platform/linux/fl_key_responder.cc @@ -0,0 +1,17 @@ +// 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_key_responder.h" + +G_DEFINE_INTERFACE(FlKeyResponder, fl_key_responder, G_TYPE_OBJECT) + +void fl_key_responder_default_init(FlKeyResponder* self) {} + +bool fl_key_responder_handle_event(FlKeyResponder* self, GdkEvent* event, FlKeyResponderAsyncCallback callback) { + g_return_val_if_fail(FL_IS_KEY_RESPONDER(self), nullptr); + g_return_val_if_fail(event != nullptr, nullptr); + g_return_val_if_fail(callback != nullptr, nullptr); + + return FL_KEY_RESPONDER_GET_IFACE(self)->handle_event(self, event, callback); +} diff --git a/shell/platform/linux/fl_key_responder.h b/shell/platform/linux/fl_key_responder.h new file mode 100644 index 0000000000000..896d17e6f1a49 --- /dev/null +++ b/shell/platform/linux/fl_key_responder.h @@ -0,0 +1,51 @@ +// 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_KEY_RESPONDER_H_ +#define FLUTTER_SHELL_PLATFORM_LINUX_FL_KEY_RESPONDER_H_ + +#include "flutter/shell/platform/linux/fl_text_input_plugin.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_value.h" + +#include +#include + +typedef void (*FlKeyResponderAsyncCallback)(FlKeyboardManager* manager, uint64_t sequence_id, bool handled); + +G_BEGIN_DECLS + +G_DECLARE_INTERFACE(FlKeyResponder, + fl_key_responder, + FL, + KEY_RESPONDER, + GObject); + +struct _FlKeyResponderInterface { + GTypeInterface g_iface; + + /** + * FlPluginRegistry::get_registrar_for_plugin: + * @registry: an #FlPluginRegistry. + * @name: plugin name. + * + * Gets the plugin registrar for the the plugin with @name. + * + * Returns: (transfer full): an #FlPluginRegistrar. + */ + bool (*handle_event)(FlKeyResponder* responder, GdkEvent* event, FlKeyResponderAsyncCallback callback, gpointer user_data); +}; + +/** + * FlKeyResponder: + * + * #FlKeyResponder is a plugin that implements the shell side + * of SystemChannels.keyEvent from the Flutter services library. + */ + +bool fl_key_responder_handle_event(FlKeyResponder* responder, GdkEvent* event, FlKeyResponderAsyncCallback callback, gpointer user_data); + +G_END_DECLS + +#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_KEY_RESPONDER_H_ diff --git a/shell/platform/linux/fl_keyboard_manager.cc b/shell/platform/linux/fl_keyboard_manager.cc new file mode 100644 index 0000000000000..d75ccb642fe9e --- /dev/null +++ b/shell/platform/linux/fl_keyboard_manager.cc @@ -0,0 +1,208 @@ +// 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_manager.h" + +#include + +struct _FlKeyboardPendingEvent { + GdkEventKey* event; + + // Self-incrementing ID attached to an event sent to the framework. + uint64_t sequence_id; + // The number of responders that haven't replied. + size_t unreplied; + // Whether any replied responders reported true (handled). + bool any_handled; + + // A value calculated out of critical event information that can be used + // to identify redispatched events. + uint64_t hash; +}; + + +// Calculates a unique ID for a given GdkEventKey object to use for +// identification of responses from the framework. +static uint64_t fl_keyboard_manager_get_event_hash(GdkEventKey* event) { + // Combine the event timestamp, the type of event, and the hardware keycode + // (scan code) of the event to come up with a unique id for this event that + // can be derived solely from the event data itself, so that we can identify + // whether or not we have seen this event already. + return (event->time & 0xffffffff) | + (static_cast(event->type) & 0xffff) << 32 | + (static_cast(event->hardware_keycode) & 0xffff) << 48; +} + +struct _FlKeybaordManager { + GObject parent_instance; + + FlKeyboardManagerRedispatcher redispatch_callback; + + // A text plugin. Automatially released on dispose. + FlTextInputPlugin* text_input_plugin; + // An array of #FlKeyResponder. Elements are added with + // #fl_keyboard_manager_add_responder immediately after initialization and are + // automatically released on dispose. + GPtrArray* responder_list; + + // An array of #_FlKeyboardPendingEvent. FlKeybaordManager must manually + // release the elements unless it is transferring them to + // pending_redispatches. + GPtrArray* pending_responds; + // An array of #_FlKeyboardPendingEvent. FlKeybaordManager must manually + // release the elements. + GPtrArray* pending_redispatches; + + uint64_t last_sequence_id; +} + +G_DECLARE_FINAL_TYPE(FlKeyboardManager, + fl_keyboard_manager, + FL, + KEYBOARD_MANAGER, + GObject); + +// Disposes of an FlKeyEventPlugin instance. +static void fl_keyboard_manager_dispose(GObject* object) { + FlKeyEventPlugin* self = FL_KEYBOARD_MANAGER(object); + + g_clear_object(&self->text_input_plugin); + g_ptr_array_free(self->responder_list, TRUE); + g_ptr_array_set_free_func(self->pending_responds, g_free); + g_ptr_array_free(self->pending_responds, TRUE); + g_ptr_array_set_free_func(self->pending_redispatches, g_free); + g_ptr_array_free(self->pending_redispatches, TRUE); + + G_OBJECT_CLASS(fl_keyboard_manager_parent_class)->dispose(object); +} + +// Initializes the FlKeyEventPlugin class methods. +static void fl_keyboard_manager_class_init(FlKeyEventPluginClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_keyboard_manager_dispose; +} + +// Compare a #_FlKeyboardPendingEvent with the given sequence_id. The #needle +// should be a pointer to uint64_t sequence_id. +static bool compare_pending_by_sequence_id(gconstpointer pending, gconstpointer needle_sequence_id) { + uint64_t sequence_id = *reinterpret_cast(needle_sequence_id); + return static_cast(pending)->sequence_id == sequence_id; +} + +// Compare a #_FlKeyboardPendingEvent with the given hash. The #needle should be +// a pointer to uint64_t hash. +static bool compare_pending_by_hash(gconstpointer pending, gconstpointer needle_hash) { + uint64_t hash = *reinterpret_cast(needle_hash); + return static_cast(pending)->hash == hash; +} + +static bool fl_keyboard_manager_remove_redispatched(FlKeyboardManager* self, uint64_t hash) { + guint result_index; + gboolean found = g_ptr_array_find_with_equal_func( + self->pending_redispatches, + static_cast(&hash), + compare_pending_by_hash, + &result_index); + if (found) { + gpointer removed = g_ptr_array_remove_index_fast(self->pending_redispatches, result_index); + g_return_val_if_fail(removed != nullptr, TRUE); + g_free(removed); + return TRUE; + } else { + return FALSE; + } +} + +static void responder_handle_event_callback(FlKeyboardManager* self, uint64_t sequence_id, bool handled) { + g_return_val_if_fail(FL_IS_KEYBOARD_MANAGER(self), nullptr); + + guint result_index; + gboolean found = g_ptr_array_find_with_equal_func( + self->pending_responds, + static_cast(&sequence_id), + compare_pending_by_hash, + &result_index); + g_return_if_fail(found); + _FlKeyboardPendingEvent* pending = static_cast<_FlKeyboardPendingEvent*>(g_ptr_array_index(self->pending_responds, result_index)); + g_return_if_fail(pending != nullptr); + g_return_if_fail(pending->unreplied > 0); + pending->unreplied -= 1; + pending->any_handled = pending->any_handled || handled; + // All responders have replied. + if (pending->unreplied == 0) { + g_ptr_array_remove_index_fast(self->pending_responds, result_index); + bool should_redispatch = false; + if (!pending->any_handled) { + // If no responders have handled, send it to text plugin. + if (!fl_text_input_plugin_filter_keypress(self->text_input_plugin, pending->event)) { + // If text plugin doesn't handle either, redispatch. + should_redispatch = true; + } + } + if (should_redispatch) { + g_ptr_array_add(self->pending_redispatches, pending); + self->redispatch_callback(pending->event); + } else { + g_free(pending); + } + } +} + +static void dispatch_pending_to_responder(gpointer responder_data, gpointer event_data) { + FlKeyResponder* responder = static_cast(pending_data); + GdkEventKey* event = static_cast(event_data); + fl_key_responder_handle_event(responder, event, responder_handle_event_callback); +} + +FlKeyboardManager* fl_keyboard_manager_new( + FlTextInputPlugin* text_input_plugin, + FlKeyboardManagerRedispatcher redispatch_callback) { + g_return_val_if_fail(FL_IS_TEXT_INPUT_PLUGIN(text_input_plugin), nullptr); + g_return_val_if_fail(redispatch != nullptr, nullptr); + + FlKeyEventPlugin* self = FL_KEYBOARD_MANAGER( + g_object_new(fl_keyboard_manager_get_type(), nullptr)); + + self->text_input_plugin = text_input_plugin; + self->redispatch_callback = redispatch_callback; + self->responder_list = g_ptr_array_new_with_free_func(g_clear_object); + + self->pending_responds = g_ptr_array_new(); + self->pending_redispatches = g_ptr_array_new(); + + self->last_sequence_id = 1; + + return self; +} + +void fl_keyboard_manager_add_responder( + FlKeyboardManager* self, + FlKeyResponder* responder) { + g_return_if_fail(FL_IS_KEYBOARD_MANAGER(self)); + g_return_if_fail(responder != nullptr); + + g_ptr_array_add(self->responder_list, responder); +} + +bool fl_keyboard_manager_handle_event(FlKeyboardManager* self, GdkEventKey* event) { + g_return_val_if_fail(FL_IS_KEYBOARD_MANAGER(self), FALSE); + g_return_val_if_fail(event != nullptr, FALSE); + + uint64_t incoming_hash = fl_keyboard_manager_get_event_hash(event); + if (fl_keyboard_manager_remove_redispatched(incoming_hash)) { + return FALSE; + } + + _FlKeyboardPendingEvent* pending = g_new(_FlKeyboardPendingEvent, 1); + pending->event = reinterpret_cast( + gdk_event_copy(reinterpret_cast(event))); + pending->sequence_id = (++self->last_sequence_id); + pending->unreplied = self->responder_list->len; + pending->any_handled = FALSE; + pending->hash = incoming_hash; + + g_ptr_array_add(self->pending_responds, pending); + g_ptr_array_foreach(self->responder_list, dispatch_pending_to_responder, self); + + return TRUE; +} diff --git a/shell/platform/linux/fl_keyboard_manager.h b/shell/platform/linux/fl_keyboard_manager.h new file mode 100644 index 0000000000000..e5dcdfdd0ff91 --- /dev/null +++ b/shell/platform/linux/fl_keyboard_manager.h @@ -0,0 +1,74 @@ +// 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_MANAGER_H_ +#define FLUTTER_SHELL_PLATFORM_LINUX_FL_KEYBOARD_MANAGER_H_ + +#include "flutter/shell/platform/linux/fl_text_input_plugin.h" + +#include + +#include "flutter/shell/platform/linux/fl_key_responder.h" + +/** + * FlKeyEventPluginCallback: + * @source_object: (nullable): the object the key event was started with. + * @message: the message returned from the framework. + * @handled: a boolean indicating whether the key event was handled in the + * framework. + * @user_data: user data passed to the callback. + * + * Type definition for a function that will be called when a key event is + * received from the engine. + **/ +typedef void (*FlKeyboardManagerRedispatcher)(GdkEvent* event); + +G_BEGIN_DECLS + +G_DECLARE_FINAL_TYPE(FlKeyboardManager, + fl_keyboard_manager, + FL, + KEYBOARD_MANAGER, + GObject); + +/** + * FlKeyboardManager: + * + * #FlKeyboardManager is a plugin that implements the shell side + * of SystemChannels.keyEvent from the Flutter services library. + */ + +/** + * fl_keyboard_manager_new: + * @messenger: an #FlBinaryMessenger. + * @response_callback: the callback to call when a response is received. If not + * given (nullptr), then the default response callback is + * used. Typically used for tests to receive event + * information. If specified, unhandled events will not be + * re-dispatched. + * @text_input_plugin: The #FlTextInputPlugin to send key events to if the + * framework doesn't handle them. + * @channel_name: the name of the channel to send key events to the framework + * on. If not given (nullptr), then the standard key event + * channel name is used. Typically used for tests to send on a + * test channel. + * + * Creates a new plugin that implements SystemChannels.keyEvent from the + * Flutter services library. + * + * Returns: a new #FlKeyEventPlugin. + */ +FlKeyboardManager* fl_keyboard_manager_new( + FlTextInputPlugin* text_input_plugin, + FlKeyboardManagerRedispatcher redispatch_callback); + +void fl_keyboard_manager_add_responder( + FlKeyboardManager* manager, + FlKeyResponder* responder); + +bool fl_keyboard_manager_handle_event(GdkEvent* event); + +G_END_DECLS + +#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_KEYBOARD_MANAGER_H_ diff --git a/shell/platform/linux/fl_view.cc b/shell/platform/linux/fl_view.cc index 4287f60b6c4be..ec289f44f3b09 100644 --- a/shell/platform/linux/fl_view.cc +++ b/shell/platform/linux/fl_view.cc @@ -10,12 +10,12 @@ #include "flutter/shell/platform/linux/fl_accessibility_plugin.h" #include "flutter/shell/platform/linux/fl_engine_private.h" -#include "flutter/shell/platform/linux/fl_key_event_plugin.h" +#include "flutter/shell/platform/linux/fl_keyboard_manager.h" +#include "flutter/shell/platform/linux/fl_key_channel_responder.h" #include "flutter/shell/platform/linux/fl_mouse_cursor_plugin.h" #include "flutter/shell/platform/linux/fl_platform_plugin.h" #include "flutter/shell/platform/linux/fl_plugin_registrar_private.h" #include "flutter/shell/platform/linux/fl_renderer_gl.h" -#include "flutter/shell/platform/linux/fl_text_input_plugin.h" #include "flutter/shell/platform/linux/fl_view_accessible.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_engine.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_plugin_registry.h" @@ -39,10 +39,9 @@ struct _FlView { // Flutter system channel handlers. FlAccessibilityPlugin* accessibility_plugin; - FlKeyEventPlugin* key_event_plugin; + FlKeybaordManager* keyboard_manager; FlMouseCursorPlugin* mouse_cursor_plugin; FlPlatformPlugin* platform_plugin; - FlTextInputPlugin* text_input_plugin; GList* gl_area_list; GList* used_area_list; @@ -181,9 +180,15 @@ static void fl_view_constructed(GObject* object) { // Create system channel handlers. FlBinaryMessenger* messenger = fl_engine_get_binary_messenger(self->engine); self->accessibility_plugin = fl_accessibility_plugin_new(self); - self->text_input_plugin = fl_text_input_plugin_new(messenger, self); - self->key_event_plugin = - fl_key_event_plugin_new(messenger, self->text_input_plugin); + self->text_input_plugin = ; + self->keyboard_manager = fl_keyboard_manager_new( + fl_text_input_plugin_new(messenger, self), + gdk_event_put); + fl_keyboard_manager_add_responder( + self->keyboard_manager, + fl_key_channel_responder_new( + self->keyboard_manager, + messenger)); self->mouse_cursor_plugin = fl_mouse_cursor_plugin_new(messenger, self); self->platform_plugin = fl_platform_plugin_new(messenger); From 5979f9415494ced65036df4984fa165b893c7773 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Wed, 31 Mar 2021 22:58:25 -0700 Subject: [PATCH 002/126] Remove unused constants --- shell/platform/windows/keyboard_key_handler.cc | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/shell/platform/windows/keyboard_key_handler.cc b/shell/platform/windows/keyboard_key_handler.cc index 0a7e48772bd63..d5042412fd0f0 100644 --- a/shell/platform/windows/keyboard_key_handler.cc +++ b/shell/platform/windows/keyboard_key_handler.cc @@ -14,20 +14,6 @@ namespace flutter { namespace { -static constexpr char kChannelName[] = "flutter/keyevent"; - -static constexpr char kKeyCodeKey[] = "keyCode"; -static constexpr char kScanCodeKey[] = "scanCode"; -static constexpr char kCharacterCodePointKey[] = "characterCodePoint"; -static constexpr char kModifiersKey[] = "modifiers"; -static constexpr char kKeyMapKey[] = "keymap"; -static constexpr char kTypeKey[] = "type"; -static constexpr char kHandledKey[] = "handled"; - -static constexpr char kWindowsKeyMap[] = "windows"; -static constexpr char kKeyUp[] = "keyup"; -static constexpr char kKeyDown[] = "keydown"; - // The maximum number of pending events to keep before // emitting a warning on the console about unhandled events. static constexpr int kMaxPendingEvents = 1000; @@ -148,7 +134,6 @@ bool KeyboardKeyHandler::RemoveRedispatchedEvent(const PendingEvent& incoming) { } } return false; - ; } void KeyboardKeyHandler::ResolvePendingEvent(uint64_t sequence_id, From e7131bedfc06f0f5f6a619047e1dd2bc2de9c838 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Thu, 1 Apr 2021 01:09:02 -0700 Subject: [PATCH 003/126] Compiled --- shell/platform/linux/BUILD.gn | 2 +- .../linux/fl_key_channel_responder.cc | 109 ++++++++++-------- .../platform/linux/fl_key_channel_responder.h | 3 +- shell/platform/linux/fl_key_responder.cc | 12 +- shell/platform/linux/fl_key_responder.h | 14 ++- shell/platform/linux/fl_keyboard_manager.cc | 51 ++++---- shell/platform/linux/fl_keyboard_manager.h | 8 +- shell/platform/linux/fl_view.cc | 14 +-- 8 files changed, 110 insertions(+), 103 deletions(-) diff --git a/shell/platform/linux/BUILD.gn b/shell/platform/linux/BUILD.gn index ac10603b996a3..d3d9fe15b5345 100644 --- a/shell/platform/linux/BUILD.gn +++ b/shell/platform/linux/BUILD.gn @@ -100,6 +100,7 @@ source_set("flutter_linux_sources") { "fl_json_message_codec.cc", "fl_json_method_codec.cc", "fl_keyboard_manager.cc", + "fl_key_responder.cc", "fl_key_channel_responder.cc", "fl_message_codec.cc", "fl_method_call.cc", @@ -167,7 +168,6 @@ executable("flutter_linux_unittests") { "fl_event_channel_test.cc", "fl_json_message_codec_test.cc", "fl_json_method_codec_test.cc", - "fl_key_event_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_channel_responder.cc b/shell/platform/linux/fl_key_channel_responder.cc index 8ec847c95713a..6110a9bd6bc40 100644 --- a/shell/platform/linux/fl_key_channel_responder.cc +++ b/shell/platform/linux/fl_key_channel_responder.cc @@ -2,13 +2,12 @@ // 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_key_event_plugin.h" -#include "flutter/shell/platform/linux/fl_key_event_plugin_private.h" +#include "flutter/shell/platform/linux/fl_key_channel_responder.h" #include #include -#include "flutter/shell/platform/linux/fl_text_input_plugin.h" +#include "flutter/shell/platform/linux/fl_keyboard_manager.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_basic_message_channel.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_json_message_codec.h" @@ -28,28 +27,35 @@ static constexpr char kLinuxKeymap[] = "linux"; static constexpr uint64_t kMaxPendingEvents = 1000; -static void fl_key_channel_responder_iface_init(FlKeyResponder* iface); +// Definition of the FlKeyChannelResponder GObject class. -// Definition of the FlKeyEventPlugin GObject class. - -struct _FlKeyEventPlugin { +struct _FlKeyChannelResponder { GObject parent_instance; - FlKeybaordManager* manager; + FlKeyboardManager* manager; FlBasicMessageChannel* channel; GPtrArray* pending_events; uint64_t last_id; }; +static void fl_key_channel_responder_iface_init( + FlKeyResponderInterface* iface); + G_DEFINE_TYPE_WITH_CODE( FlKeyChannelResponder, fl_key_channel_responder, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE(fl_key_responder_get_type(), + G_IMPLEMENT_INTERFACE(FL_TYPE_KEY_RESPONDER, fl_key_channel_responder_iface_init)) -static void fl_engine_plugin_registry_iface_init( - FlKeyResponder* iface) { +static bool fl_key_channel_responder_handle_event( + FlKeyResponder* responder, + GdkEventKey* event, + FlKeyResponderAsyncCallback callback, + gpointer user_data); + +static void fl_key_channel_responder_iface_init( + FlKeyResponderInterface* iface) { iface->handle_event = fl_key_channel_responder_handle_event; } @@ -62,6 +68,13 @@ G_DECLARE_FINAL_TYPE(FlKeyEventPair, KEY_EVENT_PAIR, GObject); +struct _FlKeyEventPair { + GObject parent_instance; + + uint64_t id; + GdkEventKey* event; +}; + G_DEFINE_TYPE(FlKeyEventPair, fl_key_event_pair, G_TYPE_OBJECT) // Dispose method for FlKeyEventPair. @@ -108,7 +121,7 @@ G_DECLARE_FINAL_TYPE(FlKeyEventResponseData, struct _FlKeyEventResponseData { GObject parent_instance; - FlKeyEventPlugin* plugin; + FlKeyChannelResponder* responder; uint64_t id; FlKeyResponderAsyncCallback callback; gpointer user_data; @@ -121,10 +134,10 @@ G_DEFINE_TYPE(FlKeyEventResponseData, fl_key_event_response_data, G_TYPE_OBJECT) static void fl_key_event_response_data_dispose(GObject* object) { g_return_if_fail(FL_IS_KEY_EVENT_RESPONSE_DATA(object)); FlKeyEventResponseData* self = FL_KEY_EVENT_RESPONSE_DATA(object); - if (self->plugin != nullptr) { - g_object_remove_weak_pointer(G_OBJECT(self->plugin), - reinterpret_cast(&(self->plugin))); - self->plugin = nullptr; + if (self->responder != nullptr) { + g_object_remove_weak_pointer(G_OBJECT(self->responder), + reinterpret_cast(&(self->responder))); + self->responder = nullptr; } } @@ -137,21 +150,21 @@ static void fl_key_event_response_data_class_init( // Instance initialization method for FlKeyEventResponseData private class. static void fl_key_event_response_data_init(FlKeyEventResponseData* self) {} -// Creates a new FlKeyEventResponseData private class with a plugin that created +// Creates a new FlKeyEventResponseData private class with a responder that created // the request, a unique ID for tracking, and optional user data. -// Will keep a weak pointer to the plugin. -FlKeyEventResponseData* fl_key_event_response_data_new(FlKeyEventPlugin* plugin, +// Will keep a weak pointer to the responder. +FlKeyEventResponseData* fl_key_event_response_data_new(FlKeyChannelResponder* responder, uint64_t id, FlKeyResponderAsyncCallback callback, gpointer user_data) { FlKeyEventResponseData* self = FL_KEY_EVENT_RESPONSE_DATA( g_object_new(fl_key_event_response_data_get_type(), nullptr)); - self->plugin = plugin; - // Add a weak pointer so we can know if the key event plugin disappeared + self->responder = responder; + // Add a weak pointer so we can know if the key event responder disappeared // while the framework was responding. - g_object_add_weak_pointer(G_OBJECT(plugin), - reinterpret_cast(&(self->plugin))); + g_object_add_weak_pointer(G_OBJECT(responder), + reinterpret_cast(&(self->responder))); self->id = id; self->callback = callback; self->user_data = user_data; @@ -159,7 +172,7 @@ FlKeyEventResponseData* fl_key_event_response_data_new(FlKeyEventPlugin* plugin, } // Finds an event in the event queue that was sent to the framework by its ID. -GdkEventKey* fl_key_event_plugin_find_pending_event(FlKeyEventPlugin* self, +GdkEventKey* fl_key_channel_responder_find_pending_event(FlKeyChannelResponder* self, uint64_t id) { for (guint i = 0; i < self->pending_events->len; ++i) { if (FL_KEY_EVENT_PAIR(g_ptr_array_index(self->pending_events, i))->id == @@ -172,7 +185,7 @@ GdkEventKey* fl_key_event_plugin_find_pending_event(FlKeyEventPlugin* self, } // Removes an event from the pending event queue. -static void remove_pending_event(FlKeyEventPlugin* self, uint64_t id) { +static void remove_pending_event(FlKeyChannelResponder* self, uint64_t id) { for (guint i = 0; i < self->pending_events->len; ++i) { if (FL_KEY_EVENT_PAIR(g_ptr_array_index(self->pending_events, i))->id == id) { @@ -186,8 +199,8 @@ static void remove_pending_event(FlKeyEventPlugin* self, uint64_t id) { } // Adds an GdkEventKey to the pending event queue, with a unique ID, and the -// plugin that added it. -static void add_pending_event(FlKeyEventPlugin* self, +// responder that added it. +static void add_pending_event(FlKeyChannelResponder* self, uint64_t id, GdkEventKey* event) { if (self->pending_events->len > kMaxPendingEvents) { @@ -208,11 +221,11 @@ static void handle_response(GObject* object, FL_KEY_EVENT_RESPONSE_DATA(user_data); // Will also return if the weak pointer has been destroyed. - if (data->plugin == nullptr) { + if (data->responder == nullptr) { return; } - FlKeyEventPlugin* self = data->plugin; + FlKeyChannelResponder* self = data->responder; g_autoptr(GError) error = nullptr; FlBasicMessageChannel* messageChannel = FL_BASIC_MESSAGE_CHANNEL(object); @@ -229,47 +242,41 @@ static void handle_response(GObject* object, data->callback(self->manager, data->id, handled); } -// Disposes of an FlKeyEventPlugin instance. -static void fl_key_event_plugin_dispose(GObject* object) { - FlKeyEventPlugin* self = FL_KEY_CHANNEL_RESPONDER(object); +// Disposes of an FlKeyChannelResponder instance. +static void fl_key_channel_responder_dispose(GObject* object) { + FlKeyChannelResponder* self = FL_KEY_CHANNEL_RESPONDER(object); g_clear_object(&self->channel); - if (self->text_input_plugin != nullptr) { - g_object_remove_weak_pointer( - G_OBJECT(self->text_input_plugin), - reinterpret_cast(&(self->text_input_plugin))); - self->text_input_plugin = nullptr; - } g_ptr_array_free(self->pending_events, TRUE); - G_OBJECT_CLASS(fl_key_event_plugin_parent_class)->dispose(object); + G_OBJECT_CLASS(fl_key_channel_responder_parent_class)->dispose(object); } -// Initializes the FlKeyEventPlugin class methods. -static void fl_key_event_plugin_class_init(FlKeyEventPluginClass* klass) { - G_OBJECT_CLASS(klass)->dispose = fl_key_event_plugin_dispose; +// Initializes the FlKeyChannelResponder class methods. +static void fl_key_channel_responder_class_init(FlKeyChannelResponderClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_key_channel_responder_dispose; } -// Initializes an FlKeyEventPlugin instance. -static void fl_key_event_plugin_init(FlKeyEventPlugin* self) {} +// Initializes an FlKeyChannelResponder instance. +static void fl_key_channel_responder_init(FlKeyChannelResponder* self) {} -// Creates a new FlKeyEventPlugin instance, with a messenger used to send +// Creates a new FlKeyChannelResponder instance, with a messenger used to send // messages to the framework, an FlTextInputPlugin used to handle key events // that the framework doesn't handle. Mainly for testing purposes, it also takes // an optional callback to call when a response is received, and an optional // channel name to use when sending messages. -FlKeyEventPlugin* fl_key_event_plugin_new( - FlKeybaordManager* manager, +FlKeyChannelResponder* fl_key_channel_responder_new( + FlKeyboardManager* manager, FlBinaryMessenger* messenger) { g_return_val_if_fail(FL_IS_BINARY_MESSENGER(messenger), nullptr); - FlKeyChannelResponder* self = FL_KEY_CHANNEL_RESPONDER(g_object_new(FL_KEY_CHANNEL_RESPONDER, nullptr)); + FlKeyChannelResponder* self = FL_KEY_CHANNEL_RESPONDER(g_object_new(FL_KEY_CHANNEL_RESPONDER(), nullptr)); self->last_id = 1; self->manager = manager; g_autoptr(FlJsonMessageCodec) codec = fl_json_message_codec_new(); self->channel = fl_basic_message_channel_new( - messenger, channel_name == nullptr ? kChannelName : channel_name, + messenger, kChannelName, FL_MESSAGE_CODEC(codec)); self->pending_events = g_ptr_array_new_with_free_func(g_object_unref); @@ -277,12 +284,12 @@ FlKeyEventPlugin* fl_key_event_plugin_new( } // Sends a key event to the framework. -bool fl_key_channel_responder_handle_event( +static bool fl_key_channel_responder_handle_event( FlKeyResponder* responder, GdkEventKey* event, FlKeyResponderAsyncCallback callback, gpointer user_data) { - FlKeyChannelResponder* self = FL_KEY_EVENT_PLUGIN(responder); + FlKeyChannelResponder* self = FL_KEY_CHANNEL_RESPONDER(responder); g_return_val_if_fail(event != nullptr, FALSE); g_return_val_if_fail(callback != nullptr, FALSE); diff --git a/shell/platform/linux/fl_key_channel_responder.h b/shell/platform/linux/fl_key_channel_responder.h index 446ce57a74bf0..cfb34c6f18be1 100644 --- a/shell/platform/linux/fl_key_channel_responder.h +++ b/shell/platform/linux/fl_key_channel_responder.h @@ -14,6 +14,7 @@ G_BEGIN_DECLS +#define FL_KEY_CHANNEL_RESPONDER fl_key_channel_responder_get_type G_DECLARE_FINAL_TYPE(FlKeyChannelResponder, fl_key_channel_responder, FL, @@ -48,7 +49,7 @@ G_DECLARE_FINAL_TYPE(FlKeyChannelResponder, * Returns: a new #FlKeyChannelResponder. */ FlKeyChannelResponder* fl_key_channel_responder_new( - FlKeybaordManager* manager, + FlKeyboardManager* manager, FlBinaryMessenger* messenger); G_END_DECLS diff --git a/shell/platform/linux/fl_key_responder.cc b/shell/platform/linux/fl_key_responder.cc index e34f8f300df5e..f1a6b58d2ffbc 100644 --- a/shell/platform/linux/fl_key_responder.cc +++ b/shell/platform/linux/fl_key_responder.cc @@ -6,12 +6,12 @@ G_DEFINE_INTERFACE(FlKeyResponder, fl_key_responder, G_TYPE_OBJECT) -void fl_key_responder_default_init(FlKeyResponder* self) {} +static void fl_key_responder_default_init(FlKeyResponderInterface* iface) {} -bool fl_key_responder_handle_event(FlKeyResponder* self, GdkEvent* event, FlKeyResponderAsyncCallback callback) { - g_return_val_if_fail(FL_IS_KEY_RESPONDER(self), nullptr); - g_return_val_if_fail(event != nullptr, nullptr); - g_return_val_if_fail(callback != nullptr, nullptr); +bool fl_key_responder_handle_event(FlKeyResponder* self, GdkEventKey* event, FlKeyResponderAsyncCallback callback, gpointer user_data) { + g_return_val_if_fail(FL_IS_KEY_RESPONDER(self), FALSE); + g_return_val_if_fail(event != nullptr, FALSE); + g_return_val_if_fail(callback != nullptr, FALSE); - return FL_KEY_RESPONDER_GET_IFACE(self)->handle_event(self, event, callback); + return FL_KEY_RESPONDER_GET_IFACE(self)->handle_event(self, event, callback, user_data); } diff --git a/shell/platform/linux/fl_key_responder.h b/shell/platform/linux/fl_key_responder.h index 896d17e6f1a49..47a0aa3f9020f 100644 --- a/shell/platform/linux/fl_key_responder.h +++ b/shell/platform/linux/fl_key_responder.h @@ -5,16 +5,18 @@ #ifndef FLUTTER_SHELL_PLATFORM_LINUX_FL_KEY_RESPONDER_H_ #define FLUTTER_SHELL_PLATFORM_LINUX_FL_KEY_RESPONDER_H_ -#include "flutter/shell/platform/linux/fl_text_input_plugin.h" +#include +#include + #include "flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_value.h" -#include -#include +G_BEGIN_DECLS +typedef struct _FlKeyboardManager FlKeyboardManager; typedef void (*FlKeyResponderAsyncCallback)(FlKeyboardManager* manager, uint64_t sequence_id, bool handled); -G_BEGIN_DECLS +#define FL_TYPE_KEY_RESPONDER fl_key_responder_get_type () G_DECLARE_INTERFACE(FlKeyResponder, fl_key_responder, @@ -34,7 +36,7 @@ struct _FlKeyResponderInterface { * * Returns: (transfer full): an #FlPluginRegistrar. */ - bool (*handle_event)(FlKeyResponder* responder, GdkEvent* event, FlKeyResponderAsyncCallback callback, gpointer user_data); + bool (*handle_event)(FlKeyResponder* responder, GdkEventKey* event, FlKeyResponderAsyncCallback callback, gpointer user_data); }; /** @@ -44,7 +46,7 @@ struct _FlKeyResponderInterface { * of SystemChannels.keyEvent from the Flutter services library. */ -bool fl_key_responder_handle_event(FlKeyResponder* responder, GdkEvent* event, FlKeyResponderAsyncCallback callback, gpointer user_data); +bool fl_key_responder_handle_event(FlKeyResponder* responder, GdkEventKey* event, FlKeyResponderAsyncCallback callback, gpointer user_data); G_END_DECLS diff --git a/shell/platform/linux/fl_keyboard_manager.cc b/shell/platform/linux/fl_keyboard_manager.cc index d75ccb642fe9e..b2b3efdc702fd 100644 --- a/shell/platform/linux/fl_keyboard_manager.cc +++ b/shell/platform/linux/fl_keyboard_manager.cc @@ -34,7 +34,7 @@ static uint64_t fl_keyboard_manager_get_event_hash(GdkEventKey* event) { (static_cast(event->hardware_keycode) & 0xffff) << 48; } -struct _FlKeybaordManager { +struct _FlKeyboardManager { GObject parent_instance; FlKeyboardManagerRedispatcher redispatch_callback; @@ -46,26 +46,24 @@ struct _FlKeybaordManager { // automatically released on dispose. GPtrArray* responder_list; - // An array of #_FlKeyboardPendingEvent. FlKeybaordManager must manually + // An array of #_FlKeyboardPendingEvent. FlKeyboardManager must manually // release the elements unless it is transferring them to // pending_redispatches. GPtrArray* pending_responds; - // An array of #_FlKeyboardPendingEvent. FlKeybaordManager must manually + // An array of #_FlKeyboardPendingEvent. FlKeyboardManager must manually // release the elements. GPtrArray* pending_redispatches; uint64_t last_sequence_id; -} +}; -G_DECLARE_FINAL_TYPE(FlKeyboardManager, - fl_keyboard_manager, - FL, - KEYBOARD_MANAGER, - GObject); +G_DEFINE_TYPE(FlKeyboardManager, + fl_keyboard_manager, + G_TYPE_OBJECT); -// Disposes of an FlKeyEventPlugin instance. +// Disposes of an FlKeyboardManager instance. static void fl_keyboard_manager_dispose(GObject* object) { - FlKeyEventPlugin* self = FL_KEYBOARD_MANAGER(object); + FlKeyboardManager* self = FL_KEYBOARD_MANAGER(object); g_clear_object(&self->text_input_plugin); g_ptr_array_free(self->responder_list, TRUE); @@ -77,21 +75,24 @@ static void fl_keyboard_manager_dispose(GObject* object) { G_OBJECT_CLASS(fl_keyboard_manager_parent_class)->dispose(object); } -// Initializes the FlKeyEventPlugin class methods. -static void fl_keyboard_manager_class_init(FlKeyEventPluginClass* klass) { +// Initializes the FlKeyboardManager class methods. +static void fl_keyboard_manager_class_init(FlKeyboardManagerClass* klass) { G_OBJECT_CLASS(klass)->dispose = fl_keyboard_manager_dispose; } +static void fl_keyboard_manager_init(FlKeyboardManager* self) { +} + // Compare a #_FlKeyboardPendingEvent with the given sequence_id. The #needle // should be a pointer to uint64_t sequence_id. -static bool compare_pending_by_sequence_id(gconstpointer pending, gconstpointer needle_sequence_id) { +static gboolean compare_pending_by_sequence_id(gconstpointer pending, gconstpointer needle_sequence_id) { uint64_t sequence_id = *reinterpret_cast(needle_sequence_id); return static_cast(pending)->sequence_id == sequence_id; } // Compare a #_FlKeyboardPendingEvent with the given hash. The #needle should be // a pointer to uint64_t hash. -static bool compare_pending_by_hash(gconstpointer pending, gconstpointer needle_hash) { +static gboolean compare_pending_by_hash(gconstpointer pending, gconstpointer needle_hash) { uint64_t hash = *reinterpret_cast(needle_hash); return static_cast(pending)->hash == hash; } @@ -114,13 +115,13 @@ static bool fl_keyboard_manager_remove_redispatched(FlKeyboardManager* self, uin } static void responder_handle_event_callback(FlKeyboardManager* self, uint64_t sequence_id, bool handled) { - g_return_val_if_fail(FL_IS_KEYBOARD_MANAGER(self), nullptr); + g_return_if_fail(FL_IS_KEYBOARD_MANAGER(self)); guint result_index; gboolean found = g_ptr_array_find_with_equal_func( self->pending_responds, static_cast(&sequence_id), - compare_pending_by_hash, + compare_pending_by_sequence_id, &result_index); g_return_if_fail(found); _FlKeyboardPendingEvent* pending = static_cast<_FlKeyboardPendingEvent*>(g_ptr_array_index(self->pending_responds, result_index)); @@ -141,7 +142,7 @@ static void responder_handle_event_callback(FlKeyboardManager* self, uint64_t se } if (should_redispatch) { g_ptr_array_add(self->pending_redispatches, pending); - self->redispatch_callback(pending->event); + self->redispatch_callback(reinterpret_cast(pending->event)); } else { g_free(pending); } @@ -149,23 +150,23 @@ static void responder_handle_event_callback(FlKeyboardManager* self, uint64_t se } static void dispatch_pending_to_responder(gpointer responder_data, gpointer event_data) { - FlKeyResponder* responder = static_cast(pending_data); + FlKeyResponder* responder = FL_KEY_RESPONDER(responder_data); GdkEventKey* event = static_cast(event_data); - fl_key_responder_handle_event(responder, event, responder_handle_event_callback); + fl_key_responder_handle_event(responder, event, responder_handle_event_callback, nullptr); } FlKeyboardManager* fl_keyboard_manager_new( FlTextInputPlugin* text_input_plugin, FlKeyboardManagerRedispatcher redispatch_callback) { g_return_val_if_fail(FL_IS_TEXT_INPUT_PLUGIN(text_input_plugin), nullptr); - g_return_val_if_fail(redispatch != nullptr, nullptr); + g_return_val_if_fail(redispatch_callback != nullptr, nullptr); - FlKeyEventPlugin* self = FL_KEYBOARD_MANAGER( + FlKeyboardManager* self = FL_KEYBOARD_MANAGER( g_object_new(fl_keyboard_manager_get_type(), nullptr)); self->text_input_plugin = text_input_plugin; self->redispatch_callback = redispatch_callback; - self->responder_list = g_ptr_array_new_with_free_func(g_clear_object); + self->responder_list = g_ptr_array_new_with_free_func(g_object_unref); self->pending_responds = g_ptr_array_new(); self->pending_redispatches = g_ptr_array_new(); @@ -184,12 +185,12 @@ void fl_keyboard_manager_add_responder( g_ptr_array_add(self->responder_list, responder); } -bool fl_keyboard_manager_handle_event(FlKeyboardManager* self, GdkEventKey* event) { +gboolean fl_keyboard_manager_handle_event(FlKeyboardManager* self, GdkEventKey* event) { g_return_val_if_fail(FL_IS_KEYBOARD_MANAGER(self), FALSE); g_return_val_if_fail(event != nullptr, FALSE); uint64_t incoming_hash = fl_keyboard_manager_get_event_hash(event); - if (fl_keyboard_manager_remove_redispatched(incoming_hash)) { + if (fl_keyboard_manager_remove_redispatched(self, incoming_hash)) { return FALSE; } diff --git a/shell/platform/linux/fl_keyboard_manager.h b/shell/platform/linux/fl_keyboard_manager.h index e5dcdfdd0ff91..0c787f23c588f 100644 --- a/shell/platform/linux/fl_keyboard_manager.h +++ b/shell/platform/linux/fl_keyboard_manager.h @@ -5,10 +5,9 @@ #ifndef FLUTTER_SHELL_PLATFORM_LINUX_FL_KEYBOARD_MANAGER_H_ #define FLUTTER_SHELL_PLATFORM_LINUX_FL_KEYBOARD_MANAGER_H_ -#include "flutter/shell/platform/linux/fl_text_input_plugin.h" - #include +#include "flutter/shell/platform/linux/fl_text_input_plugin.h" #include "flutter/shell/platform/linux/fl_key_responder.h" /** @@ -22,10 +21,11 @@ * Type definition for a function that will be called when a key event is * received from the engine. **/ -typedef void (*FlKeyboardManagerRedispatcher)(GdkEvent* event); +typedef void (*FlKeyboardManagerRedispatcher)(const GdkEvent* event); G_BEGIN_DECLS +#define FL_KEYBOARD_MANAGER fl_keyboard_manager_get_type G_DECLARE_FINAL_TYPE(FlKeyboardManager, fl_keyboard_manager, FL, @@ -67,7 +67,7 @@ void fl_keyboard_manager_add_responder( FlKeyboardManager* manager, FlKeyResponder* responder); -bool fl_keyboard_manager_handle_event(GdkEvent* event); +gboolean fl_keyboard_manager_handle_event(FlKeyboardManager* manager, GdkEventKey* event); G_END_DECLS diff --git a/shell/platform/linux/fl_view.cc b/shell/platform/linux/fl_view.cc index ec289f44f3b09..1a6938c2f52c3 100644 --- a/shell/platform/linux/fl_view.cc +++ b/shell/platform/linux/fl_view.cc @@ -39,7 +39,7 @@ struct _FlView { // Flutter system channel handlers. FlAccessibilityPlugin* accessibility_plugin; - FlKeybaordManager* keyboard_manager; + FlKeyboardManager* keyboard_manager; FlMouseCursorPlugin* mouse_cursor_plugin; FlPlatformPlugin* platform_plugin; @@ -180,15 +180,12 @@ static void fl_view_constructed(GObject* object) { // Create system channel handlers. FlBinaryMessenger* messenger = fl_engine_get_binary_messenger(self->engine); self->accessibility_plugin = fl_accessibility_plugin_new(self); - self->text_input_plugin = ; self->keyboard_manager = fl_keyboard_manager_new( fl_text_input_plugin_new(messenger, self), gdk_event_put); fl_keyboard_manager_add_responder( self->keyboard_manager, - fl_key_channel_responder_new( - self->keyboard_manager, - messenger)); + FL_KEY_RESPONDER(fl_key_channel_responder_new(self->keyboard_manager, messenger))); self->mouse_cursor_plugin = fl_mouse_cursor_plugin_new(messenger, self); self->platform_plugin = fl_platform_plugin_new(messenger); @@ -267,10 +264,9 @@ static void fl_view_dispose(GObject* object) { g_clear_object(&self->renderer); g_clear_object(&self->engine); g_clear_object(&self->accessibility_plugin); - g_clear_object(&self->key_event_plugin); + g_clear_object(&self->keyboard_manager); g_clear_object(&self->mouse_cursor_plugin); g_clear_object(&self->platform_plugin); - g_clear_object(&self->text_input_plugin); g_list_free_full(self->gl_area_list, g_object_unref); self->gl_area_list = nullptr; @@ -506,7 +502,7 @@ static gboolean event_box_motion_notify_event(GtkWidget* widget, static gboolean fl_view_key_press_event(GtkWidget* widget, GdkEventKey* event) { FlView* self = FL_VIEW(widget); - return fl_key_event_plugin_send_key_event(self->key_event_plugin, event); + return fl_keyboard_manager_handle_event(self->keyboard_manager, event); } // Implements GtkWidget::key_release_event. @@ -514,7 +510,7 @@ static gboolean fl_view_key_release_event(GtkWidget* widget, GdkEventKey* event) { FlView* self = FL_VIEW(widget); - return fl_key_event_plugin_send_key_event(self->key_event_plugin, event); + return fl_keyboard_manager_handle_event(self->keyboard_manager, event); } static void fl_view_put(FlView* self, From 45ff4dc35b441465724ba8703339e6455ac96ac7 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Thu, 1 Apr 2021 23:17:31 -0700 Subject: [PATCH 004/126] WIP tests --- .../platform/linux/fl_key_channel_responder.h | 2 +- shell/platform/linux/fl_keyboard_manager.cc | 34 +- .../linux/fl_keyboard_manager_test.cc | 314 ++++++++++++++++++ 3 files changed, 345 insertions(+), 5 deletions(-) create mode 100644 shell/platform/linux/fl_keyboard_manager_test.cc diff --git a/shell/platform/linux/fl_key_channel_responder.h b/shell/platform/linux/fl_key_channel_responder.h index cfb34c6f18be1..d5a20aeb20a43 100644 --- a/shell/platform/linux/fl_key_channel_responder.h +++ b/shell/platform/linux/fl_key_channel_responder.h @@ -14,7 +14,7 @@ G_BEGIN_DECLS -#define FL_KEY_CHANNEL_RESPONDER fl_key_channel_responder_get_type +#define FL_KEY_CHANNEL_RESPONDER fl_key_channel_responder_get_type () G_DECLARE_FINAL_TYPE(FlKeyChannelResponder, fl_key_channel_responder, FL, diff --git a/shell/platform/linux/fl_keyboard_manager.cc b/shell/platform/linux/fl_keyboard_manager.cc index b2b3efdc702fd..fae44e8135009 100644 --- a/shell/platform/linux/fl_keyboard_manager.cc +++ b/shell/platform/linux/fl_keyboard_manager.cc @@ -6,6 +6,12 @@ #include +G_DECLARE_FINAL_TYPE(FlKeyboardPendingEvent, + fl_keyboard_pending_event, + FL, + KEYBOARD_PENDING_EVENT, + GObject); + struct _FlKeyboardPendingEvent { GdkEventKey* event; @@ -21,6 +27,26 @@ struct _FlKeyboardPendingEvent { uint64_t hash; }; +G_DEFINE_TYPE(FlKeyboardPendingEvent, fl_keyboard_pending_event, G_TYPE_OBJECT) + +// Dispose method for FlKeyboardPendingEvent. +static void fl_keyboard_pending_event_dispose(GObject* object) { + // Redundant, but added so that we don't get a warning about unused function + // for FL_IS_KEYBOARD_PENDING_EVENT. + g_return_if_fail(FL_IS_KEYBOARD_PENDING_EVENT(object)); + + FlKeyboardPendingEvent* self = FL_KEYBOARD_PENDING_EVENT(object); + g_clear_pointer(&self->event, gdk_event_free); + G_OBJECT_CLASS(fl_keyboard_pending_event_parent_class)->dispose(object); +} + +// Class Initialization method for FlKeyboardPendingEvent class. +static void fl_keyboard_pending_event_class_init(FlKeyboardPendingEventClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_keyboard_pending_event_dispose; +} + +// Initialization for FlKeyboardPendingEvent instances. +static void fl_keyboard_pending_event_init(FlKeyboardPendingEvent* self) {} // Calculates a unique ID for a given GdkEventKey object to use for // identification of responses from the framework. @@ -67,9 +93,9 @@ static void fl_keyboard_manager_dispose(GObject* object) { g_clear_object(&self->text_input_plugin); g_ptr_array_free(self->responder_list, TRUE); - g_ptr_array_set_free_func(self->pending_responds, g_free); + g_ptr_array_set_free_func(self->pending_responds, g_object_unref); g_ptr_array_free(self->pending_responds, TRUE); - g_ptr_array_set_free_func(self->pending_redispatches, g_free); + g_ptr_array_set_free_func(self->pending_redispatches, g_object_unref); g_ptr_array_free(self->pending_redispatches, TRUE); G_OBJECT_CLASS(fl_keyboard_manager_parent_class)->dispose(object); @@ -107,7 +133,7 @@ static bool fl_keyboard_manager_remove_redispatched(FlKeyboardManager* self, uin if (found) { gpointer removed = g_ptr_array_remove_index_fast(self->pending_redispatches, result_index); g_return_val_if_fail(removed != nullptr, TRUE); - g_free(removed); + g_object_unref(removed); return TRUE; } else { return FALSE; @@ -144,7 +170,7 @@ static void responder_handle_event_callback(FlKeyboardManager* self, uint64_t se g_ptr_array_add(self->pending_redispatches, pending); self->redispatch_callback(reinterpret_cast(pending->event)); } else { - g_free(pending); + g_object_unref(pending); } } } diff --git a/shell/platform/linux/fl_keyboard_manager_test.cc b/shell/platform/linux/fl_keyboard_manager_test.cc new file mode 100644 index 0000000000000..d3c0c628dea0c --- /dev/null +++ b/shell/platform/linux/fl_keyboard_manager_test.cc @@ -0,0 +1,314 @@ +// 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_manager.h" + +#include + +#include "gtest/gtest.h" + +G_BEGIN_DECLS + +#define FL_KEY_MOCK_RESPONDER fl_key_mock_responder_get_type () +G_DECLARE_FINAL_TYPE(FlKeyMockResponder, + fl_key_mock_responder, + FL, + KEY_MOCK_RESPONDER, + GObject); + +G_END_DECLS + +struct _FlKeyMockResponder { + GObject parent_instance; + + FlKeyboardManager* manager; + FlBasicMessageChannel* channel; + GPtrArray* pending_events; + uint64_t last_id; +}; + +static void fl_key_mock_responder_iface_init( + FlKeyResponderInterface* iface); + +G_DEFINE_TYPE_WITH_CODE( + FlKeyMockResponder, + fl_key_mock_responder, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE(FL_TYPE_KEY_RESPONDER, + fl_key_mock_responder_iface_init)) + +static bool fl_key_mock_responder_handle_event( + FlKeyResponder* responder, + GdkEventKey* event, + FlKeyResponderAsyncCallback callback, + gpointer user_data); + +static void fl_key_mock_responder_iface_init( + FlKeyResponderInterface* iface) { + iface->handle_event = fl_key_mock_responder_handle_event; +} + +static bool fl_key_mock_responder_handle_event( + FlKeyResponder* responder, + GdkEventKey* event, + FlKeyResponderAsyncCallback callback, + gpointer user_data) { + +} + +G_DECLARE_FINAL_TYPE(FlKeyboardCallRecord, + fl_keyboard_call_record, + FL, + KEYBOARD_CALL_RECORD, + GObject); + +struct _FlKeyboardCallRecord { + GdkEventKey* event; + + uint64_t hash; +}; + +G_DEFINE_TYPE(FlKeyboardCallRecord, fl_keyboard_call_record, G_TYPE_OBJECT) + +// Dispose method for FlKeyboardCallRecord. +static void fl_keyboard_call_record_dispose(GObject* object) { + // Redundant, but added so that we don't get a warning about unused function + // for FL_IS_KEYBOARD_CALL_RECORD. + g_return_if_fail(FL_IS_KEYBOARD_CALL_RECORD(object)); + + FlKeyboardCallRecord* self = fl_keyboard_call_record(object); + g_clear_pointer(&self->event, gdk_event_free); + G_OBJECT_CLASS(fl_keyboard_call_record_parent_class)->dispose(object); +} + +// Class Initialization method for FlKeyboardCallRecord class. +static void fl_keyboard_call_record_class_init(FlKeyboardCallRecordClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_keyboard_call_record_dispose; +} + +// Converts a binary blob to a string. +static gchar* message_to_text(GBytes* message) { + size_t data_length; + const gchar* data = + static_cast(g_bytes_get_data(message, &data_length)); + return g_strndup(data, data_length); +} + +// Converts a string to a binary blob. +static GBytes* text_to_message(const gchar* text) { + return g_bytes_new(text, strlen(text)); +} + +// Encodes a method call using JsonMethodCodec to a UTF-8 string. +static gchar* encode_method_call(const gchar* name, FlValue* args) { + g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); + g_autoptr(GError) error = nullptr; + g_autoptr(GBytes) message = fl_method_codec_encode_method_call( + FL_METHOD_CODEC(codec), name, args, &error); + EXPECT_NE(message, nullptr); + EXPECT_EQ(error, nullptr); + + return message_to_text(message); +} + +// Encodes a success envelope response using JsonMethodCodec to a UTF-8 string. +static gchar* encode_success_envelope(FlValue* result) { + g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); + g_autoptr(GError) error = nullptr; + g_autoptr(GBytes) message = fl_method_codec_encode_success_envelope( + FL_METHOD_CODEC(codec), result, &error); + EXPECT_NE(message, nullptr); + EXPECT_EQ(error, nullptr); + + return message_to_text(message); +} + +// Encodes a error envelope response using JsonMethodCodec to a UTF8 string. +static gchar* encode_error_envelope(const gchar* error_code, + const gchar* error_message, + FlValue* details) { + g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); + g_autoptr(GError) error = nullptr; + g_autoptr(GBytes) message = fl_method_codec_encode_error_envelope( + FL_METHOD_CODEC(codec), error_code, error_message, details, &error); + EXPECT_NE(message, nullptr); + EXPECT_EQ(error, nullptr); + + return message_to_text(message); +} + +// Decodes a method call using JsonMethodCodec with a UTF8 string. +static void decode_method_call(const char* text, gchar** name, FlValue** args) { + g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); + g_autoptr(GBytes) data = text_to_message(text); + g_autoptr(GError) error = nullptr; + gboolean result = fl_method_codec_decode_method_call( + FL_METHOD_CODEC(codec), data, name, args, &error); + EXPECT_TRUE(result); + EXPECT_EQ(error, nullptr); +} + +// Decodes a method call using JsonMethodCodec. Expect the given error. +static void decode_error_method_call(const char* text, + GQuark domain, + gint code) { + g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); + g_autoptr(GBytes) data = text_to_message(text); + g_autoptr(GError) error = nullptr; + g_autofree gchar* name = nullptr; + g_autoptr(FlValue) args = nullptr; + gboolean result = fl_method_codec_decode_method_call( + FL_METHOD_CODEC(codec), data, &name, &args, &error); + EXPECT_FALSE(result); + EXPECT_EQ(name, nullptr); + EXPECT_EQ(args, nullptr); + EXPECT_TRUE(g_error_matches(error, domain, code)); +} + +// Decodes a response using JsonMethodCodec. Expect the response is a result. +static void decode_response_with_success(const char* text, FlValue* result) { + g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); + g_autoptr(GBytes) message = text_to_message(text); + g_autoptr(GError) error = nullptr; + g_autoptr(FlMethodResponse) response = + fl_method_codec_decode_response(FL_METHOD_CODEC(codec), message, &error); + ASSERT_NE(response, nullptr); + EXPECT_EQ(error, nullptr); + ASSERT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response)); + EXPECT_TRUE(fl_value_equal(fl_method_success_response_get_result( + FL_METHOD_SUCCESS_RESPONSE(response)), + result)); +} + +// Decodes a response using JsonMethodCodec. Expect the response contains the +// given error. +static void decode_response_with_error(const char* text, + const gchar* code, + const gchar* error_message, + FlValue* details) { + g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); + g_autoptr(GBytes) message = text_to_message(text); + g_autoptr(GError) error = nullptr; + g_autoptr(FlMethodResponse) response = + fl_method_codec_decode_response(FL_METHOD_CODEC(codec), message, &error); + ASSERT_NE(response, nullptr); + EXPECT_EQ(error, nullptr); + ASSERT_TRUE(FL_IS_METHOD_ERROR_RESPONSE(response)); + EXPECT_STREQ( + fl_method_error_response_get_code(FL_METHOD_ERROR_RESPONSE(response)), + code); + if (error_message == nullptr) { + EXPECT_EQ(fl_method_error_response_get_message( + FL_METHOD_ERROR_RESPONSE(response)), + nullptr); + } else { + EXPECT_STREQ(fl_method_error_response_get_message( + FL_METHOD_ERROR_RESPONSE(response)), + error_message); + } + if (details == nullptr) { + EXPECT_EQ(fl_method_error_response_get_details( + FL_METHOD_ERROR_RESPONSE(response)), + nullptr); + } else { + EXPECT_TRUE(fl_value_equal(fl_method_error_response_get_details( + FL_METHOD_ERROR_RESPONSE(response)), + details)); + } +} + +// Decode a response using JsonMethodCodec. Expect the given error. +static void decode_error_response(const char* text, GQuark domain, gint code) { + g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); + g_autoptr(GBytes) message = text_to_message(text); + g_autoptr(GError) error = nullptr; + g_autoptr(FlMethodResponse) response = + fl_method_codec_decode_response(FL_METHOD_CODEC(codec), message, &error); + EXPECT_EQ(response, nullptr); + EXPECT_TRUE(g_error_matches(error, domain, code)); +} + +TEST(FlJsonMethodCodecTest, EncodeMethodCallNullptrArgs) { + g_autofree gchar* text = encode_method_call("hello", nullptr); + EXPECT_STREQ(text, "{\"method\":\"hello\",\"args\":null}"); +} + +TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { + g_autolist(call_history) + + std::list ; + + // Capture the scancode of the last redispatched event + int redispatch_scancode = 0; + bool delegate_handled = false; + TestKeyboardKeyHandler handler([&redispatch_scancode](UINT cInputs, + LPINPUT pInputs, + int cbSize) -> UINT { + EXPECT_TRUE(cbSize > 0); + redispatch_scancode = pInputs->ki.wScan; + return 1; + }); + // Add one delegate + auto delegate = std::make_unique(1, &hook_history); + handler.AddDelegate(std::move(delegate)); + + /// Test 1: One event that is handled by the framework + + // Dispatch a key event + delegate_handled = handler.KeyboardHook(nullptr, 64, kHandledScanCode, + WM_KEYDOWN, L'a', false, true); + EXPECT_EQ(delegate_handled, true); + EXPECT_EQ(redispatch_scancode, 0); + EXPECT_EQ(hook_history.size(), 1); + EXPECT_EQ(hook_history.back().delegate_id, 1); + EXPECT_EQ(hook_history.back().scancode, kHandledScanCode); + EXPECT_EQ(hook_history.back().was_down, true); + + EXPECT_EQ(handler.HasRedispatched(), false); + hook_history.back().callback(true); + EXPECT_EQ(redispatch_scancode, 0); + + EXPECT_EQ(handler.HasRedispatched(), false); + hook_history.clear(); + + /// Test 2: Two events that are unhandled by the framework + + delegate_handled = handler.KeyboardHook(nullptr, 64, kHandledScanCode, + WM_KEYDOWN, L'a', false, false); + EXPECT_EQ(delegate_handled, true); + EXPECT_EQ(redispatch_scancode, 0); + EXPECT_EQ(hook_history.size(), 1); + EXPECT_EQ(hook_history.back().delegate_id, 1); + EXPECT_EQ(hook_history.back().scancode, kHandledScanCode); + EXPECT_EQ(hook_history.back().was_down, false); + + // Dispatch another key event + delegate_handled = handler.KeyboardHook(nullptr, 65, kHandledScanCode2, + WM_KEYUP, L'b', false, true); + EXPECT_EQ(delegate_handled, true); + EXPECT_EQ(redispatch_scancode, 0); + EXPECT_EQ(hook_history.size(), 2); + EXPECT_EQ(hook_history.back().delegate_id, 1); + EXPECT_EQ(hook_history.back().scancode, kHandledScanCode2); + EXPECT_EQ(hook_history.back().was_down, true); + + // Resolve the second event first to test out-of-order response + hook_history.back().callback(false); + EXPECT_EQ(redispatch_scancode, kHandledScanCode2); + + // Resolve the first event then + hook_history.front().callback(false); + EXPECT_EQ(redispatch_scancode, kHandledScanCode); + + EXPECT_EQ(handler.KeyboardHook(nullptr, 64, kHandledScanCode, WM_KEYDOWN, + L'a', false, false), + false); + EXPECT_EQ(handler.KeyboardHook(nullptr, 65, kHandledScanCode2, WM_KEYUP, L'b', + false, false), + false); + + EXPECT_EQ(handler.HasRedispatched(), false); + hook_history.clear(); + redispatch_scancode = 0; +} From ba19f0e54ecfb06b9affcf98addbac1fa7707b7f Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 5 Apr 2021 15:18:50 -0700 Subject: [PATCH 005/126] Test? (untested) --- .../linux/fl_key_channel_responder.cc | 2 +- shell/platform/linux/fl_key_responder.h | 2 +- shell/platform/linux/fl_keyboard_manager.cc | 110 +++++- .../linux/fl_keyboard_manager_test.cc | 364 +++++++----------- 4 files changed, 231 insertions(+), 247 deletions(-) diff --git a/shell/platform/linux/fl_key_channel_responder.cc b/shell/platform/linux/fl_key_channel_responder.cc index 6110a9bd6bc40..a651e5072a168 100644 --- a/shell/platform/linux/fl_key_channel_responder.cc +++ b/shell/platform/linux/fl_key_channel_responder.cc @@ -239,7 +239,7 @@ static void handle_response(GObject* object, bool handled = fl_value_get_bool(handled_value); remove_pending_event(self, data->id); - data->callback(self->manager, data->id, handled); + data->callback(handled, data->user_data); } // Disposes of an FlKeyChannelResponder instance. diff --git a/shell/platform/linux/fl_key_responder.h b/shell/platform/linux/fl_key_responder.h index 47a0aa3f9020f..d0869ad28b06e 100644 --- a/shell/platform/linux/fl_key_responder.h +++ b/shell/platform/linux/fl_key_responder.h @@ -14,7 +14,7 @@ G_BEGIN_DECLS typedef struct _FlKeyboardManager FlKeyboardManager; -typedef void (*FlKeyResponderAsyncCallback)(FlKeyboardManager* manager, uint64_t sequence_id, bool handled); +typedef void (*FlKeyResponderAsyncCallback)(bool handled, gpointer user_data); #define FL_TYPE_KEY_RESPONDER fl_key_responder_get_type () diff --git a/shell/platform/linux/fl_keyboard_manager.cc b/shell/platform/linux/fl_keyboard_manager.cc index fae44e8135009..59f9be04970f3 100644 --- a/shell/platform/linux/fl_keyboard_manager.cc +++ b/shell/platform/linux/fl_keyboard_manager.cc @@ -6,6 +6,65 @@ #include +G_BEGIN_DECLS + +// Declare and define a private class to hold response data from the framework. +#define FL_KEYBOARD_MANAGER_USER_DATA fl_keyboard_manager_user_data_get_type () +G_DECLARE_FINAL_TYPE(FlKeyboardManagerUserData, + fl_keyboard_manager_user_data, + FL, + KEYBOARD_MANAGER_USER_DATA, + GObject); + +struct _FlKeyboardManagerUserData { + GObject parent_instance; + + FlKeyboardManager* manager; + uint64_t sequence_id; +}; + +G_END_DECLS + +// Definition for FlKeyboardManagerUserData private class. +G_DEFINE_TYPE(FlKeyboardManagerUserData, fl_keyboard_manager_user_data, G_TYPE_OBJECT) + +// Dispose method for FlKeyboardManagerUserData private class. +static void fl_keyboard_manager_user_data_dispose(GObject* object) { + g_return_if_fail(FL_IS_KEYBOARD_MANAGER_USER_DATA(object)); + FlKeyboardManagerUserData* self = FL_KEYBOARD_MANAGER_USER_DATA(object); + if (self->manager != nullptr) { + g_object_remove_weak_pointer(G_OBJECT(self->manager), + reinterpret_cast(&(self->manager))); + self->manager = nullptr; + } +} + +// Class initialization method for FlKeyboardManagerUserData private class. +static void fl_keyboard_manager_user_data_class_init( + FlKeyboardManagerUserDataClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_keyboard_manager_user_data_dispose; +} + +// Instance initialization method for FlKeyboardManagerUserData private class. +static void fl_keyboard_manager_user_data_init(FlKeyboardManagerUserData* self) {} + +// Creates a new FlKeyboardManagerUserData private class with a responder that created +// the request, a unique ID for tracking, and optional user data. +// Will keep a weak pointer to the responder. +FlKeyboardManagerUserData* fl_keyboard_manager_user_data_new(FlKeyboardManager* manager, + uint64_t sequence_id) { + FlKeyboardManagerUserData* self = FL_KEYBOARD_MANAGER_USER_DATA( + g_object_new(fl_keyboard_manager_user_data_get_type(), nullptr)); + + self->manager = manager; + // Add a weak pointer so we can know if the key event responder disappeared + // while the framework was responding. + g_object_add_weak_pointer(G_OBJECT(manager), + reinterpret_cast(&(self->manager))); + self->sequence_id = sequence_id; + return self; +} + G_DECLARE_FINAL_TYPE(FlKeyboardPendingEvent, fl_keyboard_pending_event, FL, @@ -60,6 +119,23 @@ static uint64_t fl_keyboard_manager_get_event_hash(GdkEventKey* event) { (static_cast(event->hardware_keycode) & 0xffff) << 48; } +FlKeyboardPendingEvent* fl_keyboard_pending_event_new( + GdkEventKey* event, uint64_t sequence_id, size_t to_reply) { + FlKeyboardPendingEvent* self = + FL_KEYBOARD_PENDING_EVENT(g_object_new(fl_keyboard_pending_event_get_type(), nullptr)); + + // Copy the event to preserve refcounts for referenced values (mainly the + // window). + GdkEventKey* event_copy = reinterpret_cast( + gdk_event_copy(reinterpret_cast(event))); + self->event = event; + self->sequence_id = sequence_id; + self->unreplied = to_reply; + self->any_handled = any_handled; + self->hash = fl_keyboard_manager_get_event_hash(event); + return self; +} + struct _FlKeyboardManager { GObject parent_instance; @@ -72,11 +148,11 @@ struct _FlKeyboardManager { // automatically released on dispose. GPtrArray* responder_list; - // An array of #_FlKeyboardPendingEvent. FlKeyboardManager must manually + // An array of #FlKeyboardPendingEvent. FlKeyboardManager must manually // release the elements unless it is transferring them to // pending_redispatches. GPtrArray* pending_responds; - // An array of #_FlKeyboardPendingEvent. FlKeyboardManager must manually + // An array of #FlKeyboardPendingEvent. FlKeyboardManager must manually // release the elements. GPtrArray* pending_redispatches; @@ -91,7 +167,8 @@ G_DEFINE_TYPE(FlKeyboardManager, static void fl_keyboard_manager_dispose(GObject* object) { FlKeyboardManager* self = FL_KEYBOARD_MANAGER(object); - g_clear_object(&self->text_input_plugin); + if (self->text_input_plugin != nullptr) + g_clear_object(&self->text_input_plugin); g_ptr_array_free(self->responder_list, TRUE); g_ptr_array_set_free_func(self->pending_responds, g_object_unref); g_ptr_array_free(self->pending_responds, TRUE); @@ -109,18 +186,18 @@ static void fl_keyboard_manager_class_init(FlKeyboardManagerClass* klass) { static void fl_keyboard_manager_init(FlKeyboardManager* self) { } -// Compare a #_FlKeyboardPendingEvent with the given sequence_id. The #needle +// Compare a #FlKeyboardPendingEvent with the given sequence_id. The #needle // should be a pointer to uint64_t sequence_id. static gboolean compare_pending_by_sequence_id(gconstpointer pending, gconstpointer needle_sequence_id) { uint64_t sequence_id = *reinterpret_cast(needle_sequence_id); - return static_cast(pending)->sequence_id == sequence_id; + return static_cast(pending)->sequence_id == sequence_id; } -// Compare a #_FlKeyboardPendingEvent with the given hash. The #needle should be +// Compare a #FlKeyboardPendingEvent with the given hash. The #needle should be // a pointer to uint64_t hash. static gboolean compare_pending_by_hash(gconstpointer pending, gconstpointer needle_hash) { uint64_t hash = *reinterpret_cast(needle_hash); - return static_cast(pending)->hash == hash; + return static_cast(pending)->hash == hash; } static bool fl_keyboard_manager_remove_redispatched(FlKeyboardManager* self, uint64_t hash) { @@ -140,7 +217,7 @@ static bool fl_keyboard_manager_remove_redispatched(FlKeyboardManager* self, uin } } -static void responder_handle_event_callback(FlKeyboardManager* self, uint64_t sequence_id, bool handled) { +static void responder_handle_event_callback(bool handled, gpointer user_data) { g_return_if_fail(FL_IS_KEYBOARD_MANAGER(self)); guint result_index; @@ -150,7 +227,7 @@ static void responder_handle_event_callback(FlKeyboardManager* self, uint64_t se compare_pending_by_sequence_id, &result_index); g_return_if_fail(found); - _FlKeyboardPendingEvent* pending = static_cast<_FlKeyboardPendingEvent*>(g_ptr_array_index(self->pending_responds, result_index)); + FlKeyboardPendingEvent* pending = static_cast(g_ptr_array_index(self->pending_responds, result_index)); g_return_if_fail(pending != nullptr); g_return_if_fail(pending->unreplied > 0); pending->unreplied -= 1; @@ -161,7 +238,7 @@ static void responder_handle_event_callback(FlKeyboardManager* self, uint64_t se bool should_redispatch = false; if (!pending->any_handled) { // If no responders have handled, send it to text plugin. - if (!fl_text_input_plugin_filter_keypress(self->text_input_plugin, pending->event)) { + if (self->text_input_plugin != nullptr && !fl_text_input_plugin_filter_keypress(self->text_input_plugin, pending->event)) { // If text plugin doesn't handle either, redispatch. should_redispatch = true; } @@ -184,7 +261,7 @@ static void dispatch_pending_to_responder(gpointer responder_data, gpointer even FlKeyboardManager* fl_keyboard_manager_new( FlTextInputPlugin* text_input_plugin, FlKeyboardManagerRedispatcher redispatch_callback) { - g_return_val_if_fail(FL_IS_TEXT_INPUT_PLUGIN(text_input_plugin), nullptr); + g_return_val_if_fail(text_input_plugin == nullptr || FL_IS_TEXT_INPUT_PLUGIN(text_input_plugin), nullptr); g_return_val_if_fail(redispatch_callback != nullptr, nullptr); FlKeyboardManager* self = FL_KEYBOARD_MANAGER( @@ -220,13 +297,10 @@ gboolean fl_keyboard_manager_handle_event(FlKeyboardManager* self, GdkEventKey* return FALSE; } - _FlKeyboardPendingEvent* pending = g_new(_FlKeyboardPendingEvent, 1); - pending->event = reinterpret_cast( - gdk_event_copy(reinterpret_cast(event))); - pending->sequence_id = (++self->last_sequence_id); - pending->unreplied = self->responder_list->len; - pending->any_handled = FALSE; - pending->hash = incoming_hash; + FlKeyboardPendingEvent* pending = fl_keyboard_pending_event_new( + reinterpret_cast(event), + ++self->last_sequence_id, + self->responder_list->len); g_ptr_array_add(self->pending_responds, pending); g_ptr_array_foreach(self->responder_list, dispatch_pending_to_responder, self); diff --git a/shell/platform/linux/fl_keyboard_manager_test.cc b/shell/platform/linux/fl_keyboard_manager_test.cc index d3c0c628dea0c..e7e81b1f7f7e6 100644 --- a/shell/platform/linux/fl_keyboard_manager_test.cc +++ b/shell/platform/linux/fl_keyboard_manager_test.cc @@ -10,6 +10,75 @@ G_BEGIN_DECLS +#define FL_KEYBOARD_CALL_RECORD fl_keyboard_call_record_get_type () +G_DECLARE_FINAL_TYPE(FlKeyboardCallRecord, + fl_keyboard_call_record, + FL, + KEYBOARD_CALL_RECORD, + GObject); + +typedef struct _FlKeyMockResponder FlKeyMockResponder; +struct _FlKeyboardCallRecord { + FlKeyMockResponder* responder; + GdkEventKey* event; + FlKeyResponderAsyncCallback callback; + gpointer user_data; +}; + +G_END_DECLS + +G_DEFINE_TYPE(FlKeyboardCallRecord, fl_keyboard_call_record, G_TYPE_OBJECT) + +// Dispose method for FlKeyboardCallRecord. +static void fl_keyboard_call_record_dispose(GObject* object) { + // Redundant, but added so that we don't get a warning about unused function + // for FL_IS_KEYBOARD_CALL_RECORD. + g_return_if_fail(FL_IS_KEYBOARD_CALL_RECORD(object)); + + FlKeyboardCallRecord* self = fl_keyboard_call_record(object); + g_clear_pointer(&self->event, gdk_event_free); + G_OBJECT_CLASS(fl_keyboard_call_record_parent_class)->dispose(object); +} + +// Class Initialization method for FlKeyboardCallRecord class. +static void fl_keyboard_call_record_class_init(FlKeyboardCallRecordClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_keyboard_call_record_dispose; +} + +static FlKeyboardCallRecord* fl_keyboard_call_record_new( + FlKeyMockResponder* responder, + GdkEventKey* event, + FlKeyResponderAsyncCallback callback, + gpointer user_data) { + g_return_val_if_fail(FL_IS_KEY_MOCK_RESPONDER(responder), nullptr); + g_return_val_if_fail(event != nullptr, nullptr); + g_return_val_if_fail(callback != nullptr, nullptr); + g_return_val_if_fail(user_data != nullptr, nullptr); + + FlKeyboardCallRecord* self = FL_KEYBOARD_CALL_RECORD( + g_object_new(fl_keyboard_call_record_get_type(), nullptr)); + + self->responder = responder; + self->event = event; + self->callback = callback; + self->user_data = user_data; + + return self; +} + +static void dont_respond(FlKeyResponderAsyncCallback callback, gpointer user_data) {} +static void respond_true(FlKeyResponderAsyncCallback callback, gpointer user_data) { + callback(true); +} +static void respond_false(FlKeyResponderAsyncCallback callback, gpointer user_data) { + callback(false); +} +namespace { +typedef void (*CallbackHandler)(FlKeyResponderAsyncCallback callback, gpointer user_data); +} + +G_BEGIN_DECLS + #define FL_KEY_MOCK_RESPONDER fl_key_mock_responder_get_type () G_DECLARE_FINAL_TYPE(FlKeyMockResponder, fl_key_mock_responder, @@ -22,10 +91,10 @@ G_END_DECLS struct _FlKeyMockResponder { GObject parent_instance; - FlKeyboardManager* manager; - FlBasicMessageChannel* channel; - GPtrArray* pending_events; - uint64_t last_id; + // A list of _FlKeyboardCallRecord. + GList* call_records; + CallbackHandler callback_handler; + int delegate_id; }; static void fl_key_mock_responder_iface_init( @@ -54,168 +123,28 @@ static bool fl_key_mock_responder_handle_event( GdkEventKey* event, FlKeyResponderAsyncCallback callback, gpointer user_data) { - + FlKeyMockResponder* self = FL_KEY_MOCK_RESPONDER(responder); + g_list_append(self->call_records, + fl_keyboard_call_record_new(self, event, callback, user_data)); + self->callback_handler(callback, user_data); } -G_DECLARE_FINAL_TYPE(FlKeyboardCallRecord, - fl_keyboard_call_record, - FL, - KEYBOARD_CALL_RECORD, - GObject); - -struct _FlKeyboardCallRecord { - GdkEventKey* event; +static FlKeyMockResponder* fl_key_mock_responder_new( + GList* call_records, + int delegate_id, + CallbackHandler callback_handler = dont_respond) { + g_return_val_if_fail(FL_IS_KEY_RESPONDER(responder), nullptr); + g_return_val_if_fail(event != nullptr, nullptr); + g_return_val_if_fail(callback != nullptr, nullptr); + g_return_val_if_fail(user_data != nullptr, nullptr); - uint64_t hash; -}; + FlKeyMockResponder* self = FL_KEY_MOCK_RESPONDER(g_object_new(FL_KEY_MOCK_RESPONDER, nullptr)); -G_DEFINE_TYPE(FlKeyboardCallRecord, fl_keyboard_call_record, G_TYPE_OBJECT) + self->call_records = call_records; + self->callback_handler = callback_handler; + self->delegate_id = delegate_id; -// Dispose method for FlKeyboardCallRecord. -static void fl_keyboard_call_record_dispose(GObject* object) { - // Redundant, but added so that we don't get a warning about unused function - // for FL_IS_KEYBOARD_CALL_RECORD. - g_return_if_fail(FL_IS_KEYBOARD_CALL_RECORD(object)); - - FlKeyboardCallRecord* self = fl_keyboard_call_record(object); - g_clear_pointer(&self->event, gdk_event_free); - G_OBJECT_CLASS(fl_keyboard_call_record_parent_class)->dispose(object); -} - -// Class Initialization method for FlKeyboardCallRecord class. -static void fl_keyboard_call_record_class_init(FlKeyboardCallRecordClass* klass) { - G_OBJECT_CLASS(klass)->dispose = fl_keyboard_call_record_dispose; -} - -// Converts a binary blob to a string. -static gchar* message_to_text(GBytes* message) { - size_t data_length; - const gchar* data = - static_cast(g_bytes_get_data(message, &data_length)); - return g_strndup(data, data_length); -} - -// Converts a string to a binary blob. -static GBytes* text_to_message(const gchar* text) { - return g_bytes_new(text, strlen(text)); -} - -// Encodes a method call using JsonMethodCodec to a UTF-8 string. -static gchar* encode_method_call(const gchar* name, FlValue* args) { - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GError) error = nullptr; - g_autoptr(GBytes) message = fl_method_codec_encode_method_call( - FL_METHOD_CODEC(codec), name, args, &error); - EXPECT_NE(message, nullptr); - EXPECT_EQ(error, nullptr); - - return message_to_text(message); -} - -// Encodes a success envelope response using JsonMethodCodec to a UTF-8 string. -static gchar* encode_success_envelope(FlValue* result) { - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GError) error = nullptr; - g_autoptr(GBytes) message = fl_method_codec_encode_success_envelope( - FL_METHOD_CODEC(codec), result, &error); - EXPECT_NE(message, nullptr); - EXPECT_EQ(error, nullptr); - - return message_to_text(message); -} - -// Encodes a error envelope response using JsonMethodCodec to a UTF8 string. -static gchar* encode_error_envelope(const gchar* error_code, - const gchar* error_message, - FlValue* details) { - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GError) error = nullptr; - g_autoptr(GBytes) message = fl_method_codec_encode_error_envelope( - FL_METHOD_CODEC(codec), error_code, error_message, details, &error); - EXPECT_NE(message, nullptr); - EXPECT_EQ(error, nullptr); - - return message_to_text(message); -} - -// Decodes a method call using JsonMethodCodec with a UTF8 string. -static void decode_method_call(const char* text, gchar** name, FlValue** args) { - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GBytes) data = text_to_message(text); - g_autoptr(GError) error = nullptr; - gboolean result = fl_method_codec_decode_method_call( - FL_METHOD_CODEC(codec), data, name, args, &error); - EXPECT_TRUE(result); - EXPECT_EQ(error, nullptr); -} - -// Decodes a method call using JsonMethodCodec. Expect the given error. -static void decode_error_method_call(const char* text, - GQuark domain, - gint code) { - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GBytes) data = text_to_message(text); - g_autoptr(GError) error = nullptr; - g_autofree gchar* name = nullptr; - g_autoptr(FlValue) args = nullptr; - gboolean result = fl_method_codec_decode_method_call( - FL_METHOD_CODEC(codec), data, &name, &args, &error); - EXPECT_FALSE(result); - EXPECT_EQ(name, nullptr); - EXPECT_EQ(args, nullptr); - EXPECT_TRUE(g_error_matches(error, domain, code)); -} - -// Decodes a response using JsonMethodCodec. Expect the response is a result. -static void decode_response_with_success(const char* text, FlValue* result) { - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GBytes) message = text_to_message(text); - g_autoptr(GError) error = nullptr; - g_autoptr(FlMethodResponse) response = - fl_method_codec_decode_response(FL_METHOD_CODEC(codec), message, &error); - ASSERT_NE(response, nullptr); - EXPECT_EQ(error, nullptr); - ASSERT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response)); - EXPECT_TRUE(fl_value_equal(fl_method_success_response_get_result( - FL_METHOD_SUCCESS_RESPONSE(response)), - result)); -} - -// Decodes a response using JsonMethodCodec. Expect the response contains the -// given error. -static void decode_response_with_error(const char* text, - const gchar* code, - const gchar* error_message, - FlValue* details) { - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GBytes) message = text_to_message(text); - g_autoptr(GError) error = nullptr; - g_autoptr(FlMethodResponse) response = - fl_method_codec_decode_response(FL_METHOD_CODEC(codec), message, &error); - ASSERT_NE(response, nullptr); - EXPECT_EQ(error, nullptr); - ASSERT_TRUE(FL_IS_METHOD_ERROR_RESPONSE(response)); - EXPECT_STREQ( - fl_method_error_response_get_code(FL_METHOD_ERROR_RESPONSE(response)), - code); - if (error_message == nullptr) { - EXPECT_EQ(fl_method_error_response_get_message( - FL_METHOD_ERROR_RESPONSE(response)), - nullptr); - } else { - EXPECT_STREQ(fl_method_error_response_get_message( - FL_METHOD_ERROR_RESPONSE(response)), - error_message); - } - if (details == nullptr) { - EXPECT_EQ(fl_method_error_response_get_details( - FL_METHOD_ERROR_RESPONSE(response)), - nullptr); - } else { - EXPECT_TRUE(fl_value_equal(fl_method_error_response_get_details( - FL_METHOD_ERROR_RESPONSE(response)), - details)); - } + return self; } // Decode a response using JsonMethodCodec. Expect the given error. @@ -229,41 +158,60 @@ static void decode_error_response(const char* text, GQuark domain, gint code) { EXPECT_TRUE(g_error_matches(error, domain, code)); } -TEST(FlJsonMethodCodecTest, EncodeMethodCallNullptrArgs) { - g_autofree gchar* text = encode_method_call("hello", nullptr); - EXPECT_STREQ(text, "{\"method\":\"hello\",\"args\":null}"); +static GdkEvent* key_event_new( + boolean is_down, + guint keyval, + guint16 hardware_keycode, + guint state, + gchar* string, + guint* string_length, + gboolean is_modifier) { + GdkEventType type = is_down ? GDK_KEY_PRESS : GDK_KEY_RELEASE; + GdkEvent* event = reinterpret_cast(gdk_event_new(type)); + event->window = nullptr; + event->send_event = TRUE; + event->time = 0; + event->state = state; + event->keyval = keyval; + event->length = string_length; + event->string = string; + event->hardware_keycode = hardware_keycode; + event->group = 0; + event->is_modifier = is_modifier ? 1 : 0; + return event; +} + +namespace { +// A global variable to store redispatched scancode. It is a global variable so +// that it can be used in a function without user_data. +int g_redispatch_keyval = 0; +} + +static void store_redispatch_scancode(const GdkEvent* event) { + g_redispatch_keyval = event->keyval; } TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { - g_autolist(call_history) - - std::list ; - - // Capture the scancode of the last redispatched event - int redispatch_scancode = 0; - bool delegate_handled = false; - TestKeyboardKeyHandler handler([&redispatch_scancode](UINT cInputs, - LPINPUT pInputs, - int cbSize) -> UINT { - EXPECT_TRUE(cbSize > 0); - redispatch_scancode = pInputs->ki.wScan; - return 1; - }); - // Add one delegate - auto delegate = std::make_unique(1, &hook_history); - handler.AddDelegate(std::move(delegate)); + g_autolist(call_records) = NULL; + + gboolean manager_handled = false; + g_autoptr(FlKeyboardManager) manager = fl_keyboard_manager_new( + nullptr, _g_redispatch_keyval); + fl_keyboard_manager_add_responder(manager, + fl_key_mock_responder_new(call_records, 0)); /// Test 1: One event that is handled by the framework // Dispatch a key event - delegate_handled = handler.KeyboardHook(nullptr, 64, kHandledScanCode, - WM_KEYDOWN, L'a', false, true); - EXPECT_EQ(delegate_handled, true); - EXPECT_EQ(redispatch_scancode, 0); - EXPECT_EQ(hook_history.size(), 1); - EXPECT_EQ(hook_history.back().delegate_id, 1); - EXPECT_EQ(hook_history.back().scancode, kHandledScanCode); - EXPECT_EQ(hook_history.back().was_down, true); + manager_handled = fl_keyboard_manager_handle_event( + manager, + key_event_new(true, 0x50, 0x70, 0, "a", 1, false)); + EXPECT_EQ(manager_handled, true); + EXPECT_EQ(g_redispatch_keyval, 0); + EXPECT_EQ(g_list_length(call_records), 1); + EXPECT_EQ(g_list_last(call_records).delegate_id, 1); + EXPECT_EQ(g_list_last(call_records).keyval, 0x50); + EXPECT_EQ(g_list_last(call_records).hardware_keycode, 0x70); EXPECT_EQ(handler.HasRedispatched(), false); hook_history.back().callback(true); @@ -272,43 +220,5 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { EXPECT_EQ(handler.HasRedispatched(), false); hook_history.clear(); - /// Test 2: Two events that are unhandled by the framework - - delegate_handled = handler.KeyboardHook(nullptr, 64, kHandledScanCode, - WM_KEYDOWN, L'a', false, false); - EXPECT_EQ(delegate_handled, true); - EXPECT_EQ(redispatch_scancode, 0); - EXPECT_EQ(hook_history.size(), 1); - EXPECT_EQ(hook_history.back().delegate_id, 1); - EXPECT_EQ(hook_history.back().scancode, kHandledScanCode); - EXPECT_EQ(hook_history.back().was_down, false); - - // Dispatch another key event - delegate_handled = handler.KeyboardHook(nullptr, 65, kHandledScanCode2, - WM_KEYUP, L'b', false, true); - EXPECT_EQ(delegate_handled, true); - EXPECT_EQ(redispatch_scancode, 0); - EXPECT_EQ(hook_history.size(), 2); - EXPECT_EQ(hook_history.back().delegate_id, 1); - EXPECT_EQ(hook_history.back().scancode, kHandledScanCode2); - EXPECT_EQ(hook_history.back().was_down, true); - - // Resolve the second event first to test out-of-order response - hook_history.back().callback(false); - EXPECT_EQ(redispatch_scancode, kHandledScanCode2); - - // Resolve the first event then - hook_history.front().callback(false); - EXPECT_EQ(redispatch_scancode, kHandledScanCode); - - EXPECT_EQ(handler.KeyboardHook(nullptr, 64, kHandledScanCode, WM_KEYDOWN, - L'a', false, false), - false); - EXPECT_EQ(handler.KeyboardHook(nullptr, 65, kHandledScanCode2, WM_KEYUP, L'b', - false, false), - false); - - EXPECT_EQ(handler.HasRedispatched(), false); - hook_history.clear(); redispatch_scancode = 0; } From 40b8afc52d25379ae65194443b3cbfdac80eb456 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 5 Apr 2021 16:27:06 -0700 Subject: [PATCH 006/126] Compiled --- shell/platform/linux/BUILD.gn | 1 + .../linux/fl_key_channel_responder.cc | 15 +- .../platform/linux/fl_key_channel_responder.h | 2 +- shell/platform/linux/fl_key_responder.cc | 10 +- shell/platform/linux/fl_key_responder.h | 4 +- shell/platform/linux/fl_keyboard_manager.cc | 16 ++- .../linux/fl_keyboard_manager_test.cc | 132 ++++++++---------- 7 files changed, 85 insertions(+), 95 deletions(-) diff --git a/shell/platform/linux/BUILD.gn b/shell/platform/linux/BUILD.gn index d3d9fe15b5345..a1a0adb664f5c 100644 --- a/shell/platform/linux/BUILD.gn +++ b/shell/platform/linux/BUILD.gn @@ -168,6 +168,7 @@ executable("flutter_linux_unittests") { "fl_event_channel_test.cc", "fl_json_message_codec_test.cc", "fl_json_method_codec_test.cc", + "fl_keyboard_manager_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_channel_responder.cc b/shell/platform/linux/fl_key_channel_responder.cc index a651e5072a168..75f5c35055997 100644 --- a/shell/platform/linux/fl_key_channel_responder.cc +++ b/shell/platform/linux/fl_key_channel_responder.cc @@ -48,7 +48,7 @@ G_DEFINE_TYPE_WITH_CODE( G_IMPLEMENT_INTERFACE(FL_TYPE_KEY_RESPONDER, fl_key_channel_responder_iface_init)) -static bool fl_key_channel_responder_handle_event( +static void fl_key_channel_responder_handle_event( FlKeyResponder* responder, GdkEventKey* event, FlKeyResponderAsyncCallback callback, @@ -270,7 +270,7 @@ FlKeyChannelResponder* fl_key_channel_responder_new( FlBinaryMessenger* messenger) { g_return_val_if_fail(FL_IS_BINARY_MESSENGER(messenger), nullptr); - FlKeyChannelResponder* self = FL_KEY_CHANNEL_RESPONDER(g_object_new(FL_KEY_CHANNEL_RESPONDER(), nullptr)); + FlKeyChannelResponder* self = FL_KEY_CHANNEL_RESPONDER(g_object_new(fl_key_channel_responder_get_type(), nullptr)); self->last_id = 1; self->manager = manager; @@ -284,14 +284,14 @@ FlKeyChannelResponder* fl_key_channel_responder_new( } // Sends a key event to the framework. -static bool fl_key_channel_responder_handle_event( +static void fl_key_channel_responder_handle_event( FlKeyResponder* responder, GdkEventKey* event, FlKeyResponderAsyncCallback callback, gpointer user_data) { FlKeyChannelResponder* self = FL_KEY_CHANNEL_RESPONDER(responder); - g_return_val_if_fail(event != nullptr, FALSE); - g_return_val_if_fail(callback != nullptr, FALSE); + g_return_if_fail(event != nullptr); + g_return_if_fail(callback != nullptr); uint64_t id = (++self->last_id); @@ -304,7 +304,7 @@ static bool fl_key_channel_responder_handle_event( type = kTypeValueUp; break; default: - return FALSE; + return; } int64_t scan_code = event->hardware_keycode; @@ -380,7 +380,4 @@ static bool fl_key_channel_responder_handle_event( // Send the message off to the framework for handling (or not). fl_basic_message_channel_send(self->channel, message, nullptr, handle_response, data); - // Return true before we know what the framework will do, because if it - // doesn't handle the key, we'll re-dispatch it later. - return TRUE; } diff --git a/shell/platform/linux/fl_key_channel_responder.h b/shell/platform/linux/fl_key_channel_responder.h index d5a20aeb20a43..900f6c3b50039 100644 --- a/shell/platform/linux/fl_key_channel_responder.h +++ b/shell/platform/linux/fl_key_channel_responder.h @@ -14,7 +14,7 @@ G_BEGIN_DECLS -#define FL_KEY_CHANNEL_RESPONDER fl_key_channel_responder_get_type () +#define FL_TYPE_KEY_CHANNEL_RESPONDER fl_key_channel_responder_get_type () G_DECLARE_FINAL_TYPE(FlKeyChannelResponder, fl_key_channel_responder, FL, diff --git a/shell/platform/linux/fl_key_responder.cc b/shell/platform/linux/fl_key_responder.cc index f1a6b58d2ffbc..338fd27792120 100644 --- a/shell/platform/linux/fl_key_responder.cc +++ b/shell/platform/linux/fl_key_responder.cc @@ -8,10 +8,10 @@ G_DEFINE_INTERFACE(FlKeyResponder, fl_key_responder, G_TYPE_OBJECT) static void fl_key_responder_default_init(FlKeyResponderInterface* iface) {} -bool fl_key_responder_handle_event(FlKeyResponder* self, GdkEventKey* event, FlKeyResponderAsyncCallback callback, gpointer user_data) { - g_return_val_if_fail(FL_IS_KEY_RESPONDER(self), FALSE); - g_return_val_if_fail(event != nullptr, FALSE); - g_return_val_if_fail(callback != nullptr, FALSE); +void fl_key_responder_handle_event(FlKeyResponder* self, GdkEventKey* event, FlKeyResponderAsyncCallback callback, gpointer user_data) { + g_return_if_fail(FL_IS_KEY_RESPONDER(self)); + g_return_if_fail(event != nullptr); + g_return_if_fail(callback != nullptr); - return FL_KEY_RESPONDER_GET_IFACE(self)->handle_event(self, event, callback, user_data); + FL_KEY_RESPONDER_GET_IFACE(self)->handle_event(self, event, callback, user_data); } diff --git a/shell/platform/linux/fl_key_responder.h b/shell/platform/linux/fl_key_responder.h index d0869ad28b06e..efcb5581dba42 100644 --- a/shell/platform/linux/fl_key_responder.h +++ b/shell/platform/linux/fl_key_responder.h @@ -36,7 +36,7 @@ struct _FlKeyResponderInterface { * * Returns: (transfer full): an #FlPluginRegistrar. */ - bool (*handle_event)(FlKeyResponder* responder, GdkEventKey* event, FlKeyResponderAsyncCallback callback, gpointer user_data); + void (*handle_event)(FlKeyResponder* responder, GdkEventKey* event, FlKeyResponderAsyncCallback callback, gpointer user_data); }; /** @@ -46,7 +46,7 @@ struct _FlKeyResponderInterface { * of SystemChannels.keyEvent from the Flutter services library. */ -bool fl_key_responder_handle_event(FlKeyResponder* responder, GdkEventKey* event, FlKeyResponderAsyncCallback callback, gpointer user_data); +void fl_key_responder_handle_event(FlKeyResponder* responder, GdkEventKey* event, FlKeyResponderAsyncCallback callback, gpointer user_data); G_END_DECLS diff --git a/shell/platform/linux/fl_keyboard_manager.cc b/shell/platform/linux/fl_keyboard_manager.cc index 59f9be04970f3..4262c862dd554 100644 --- a/shell/platform/linux/fl_keyboard_manager.cc +++ b/shell/platform/linux/fl_keyboard_manager.cc @@ -9,7 +9,7 @@ G_BEGIN_DECLS // Declare and define a private class to hold response data from the framework. -#define FL_KEYBOARD_MANAGER_USER_DATA fl_keyboard_manager_user_data_get_type () +#define FL_TYPE_KEYBOARD_MANAGER_USER_DATA fl_keyboard_manager_user_data_get_type () G_DECLARE_FINAL_TYPE(FlKeyboardManagerUserData, fl_keyboard_manager_user_data, FL, @@ -128,10 +128,10 @@ FlKeyboardPendingEvent* fl_keyboard_pending_event_new( // window). GdkEventKey* event_copy = reinterpret_cast( gdk_event_copy(reinterpret_cast(event))); - self->event = event; + self->event = event_copy; self->sequence_id = sequence_id; self->unreplied = to_reply; - self->any_handled = any_handled; + self->any_handled = false; self->hash = fl_keyboard_manager_get_event_hash(event); return self; } @@ -217,13 +217,15 @@ static bool fl_keyboard_manager_remove_redispatched(FlKeyboardManager* self, uin } } -static void responder_handle_event_callback(bool handled, gpointer user_data) { - g_return_if_fail(FL_IS_KEYBOARD_MANAGER(self)); +static void responder_handle_event_callback(bool handled, gpointer user_data_ptr) { + g_return_if_fail(FL_IS_KEYBOARD_MANAGER_USER_DATA(user_data_ptr)); + FlKeyboardManagerUserData* user_data = reinterpret_cast(user_data_ptr); + FlKeyboardManager* self = user_data->manager; guint result_index; gboolean found = g_ptr_array_find_with_equal_func( self->pending_responds, - static_cast(&sequence_id), + &user_data->sequence_id, compare_pending_by_sequence_id, &result_index); g_return_if_fail(found); @@ -298,7 +300,7 @@ gboolean fl_keyboard_manager_handle_event(FlKeyboardManager* self, GdkEventKey* } FlKeyboardPendingEvent* pending = fl_keyboard_pending_event_new( - reinterpret_cast(event), + event, ++self->last_sequence_id, self->responder_list->len); diff --git a/shell/platform/linux/fl_keyboard_manager_test.cc b/shell/platform/linux/fl_keyboard_manager_test.cc index e7e81b1f7f7e6..18fc9c710e44b 100644 --- a/shell/platform/linux/fl_keyboard_manager_test.cc +++ b/shell/platform/linux/fl_keyboard_manager_test.cc @@ -8,9 +8,13 @@ #include "gtest/gtest.h" +namespace { +typedef void (*CallbackHandler)(FlKeyResponderAsyncCallback callback, gpointer user_data); +} + G_BEGIN_DECLS -#define FL_KEYBOARD_CALL_RECORD fl_keyboard_call_record_get_type () +#define FL_TYPE_KEYBOARD_CALL_RECORD fl_keyboard_call_record_get_type () G_DECLARE_FINAL_TYPE(FlKeyboardCallRecord, fl_keyboard_call_record, FL, @@ -25,17 +29,35 @@ struct _FlKeyboardCallRecord { gpointer user_data; }; +#define FL_TYPE_KEY_MOCK_RESPONDER fl_key_mock_responder_get_type () +G_DECLARE_FINAL_TYPE(FlKeyMockResponder, + fl_key_mock_responder, + FL, + KEY_MOCK_RESPONDER, + GObject); + +struct _FlKeyMockResponder { + GObject parent_instance; + + // A weak pointer for a list of FlKeyboardCallRecord. + GList* call_records; + CallbackHandler callback_handler; + int delegate_id; +}; + G_END_DECLS G_DEFINE_TYPE(FlKeyboardCallRecord, fl_keyboard_call_record, G_TYPE_OBJECT) +static void fl_keyboard_call_record_init(FlKeyboardCallRecord* self) {} + // Dispose method for FlKeyboardCallRecord. static void fl_keyboard_call_record_dispose(GObject* object) { // Redundant, but added so that we don't get a warning about unused function // for FL_IS_KEYBOARD_CALL_RECORD. g_return_if_fail(FL_IS_KEYBOARD_CALL_RECORD(object)); - FlKeyboardCallRecord* self = fl_keyboard_call_record(object); + FlKeyboardCallRecord* self = FL_KEYBOARD_CALL_RECORD(object); g_clear_pointer(&self->event, gdk_event_free); G_OBJECT_CLASS(fl_keyboard_call_record_parent_class)->dispose(object); } @@ -67,35 +89,12 @@ static FlKeyboardCallRecord* fl_keyboard_call_record_new( } static void dont_respond(FlKeyResponderAsyncCallback callback, gpointer user_data) {} -static void respond_true(FlKeyResponderAsyncCallback callback, gpointer user_data) { - callback(true); -} -static void respond_false(FlKeyResponderAsyncCallback callback, gpointer user_data) { - callback(false); -} -namespace { -typedef void (*CallbackHandler)(FlKeyResponderAsyncCallback callback, gpointer user_data); -} - -G_BEGIN_DECLS - -#define FL_KEY_MOCK_RESPONDER fl_key_mock_responder_get_type () -G_DECLARE_FINAL_TYPE(FlKeyMockResponder, - fl_key_mock_responder, - FL, - KEY_MOCK_RESPONDER, - GObject); - -G_END_DECLS - -struct _FlKeyMockResponder { - GObject parent_instance; - - // A list of _FlKeyboardCallRecord. - GList* call_records; - CallbackHandler callback_handler; - int delegate_id; -}; +// static void respond_true(FlKeyResponderAsyncCallback callback, gpointer user_data) { +// callback(true, user_data); +// } +// static void respond_false(FlKeyResponderAsyncCallback callback, gpointer user_data) { +// callback(false, user_data); +// } static void fl_key_mock_responder_iface_init( FlKeyResponderInterface* iface); @@ -107,7 +106,7 @@ G_DEFINE_TYPE_WITH_CODE( G_IMPLEMENT_INTERFACE(FL_TYPE_KEY_RESPONDER, fl_key_mock_responder_iface_init)) -static bool fl_key_mock_responder_handle_event( +static void fl_key_mock_responder_handle_event( FlKeyResponder* responder, GdkEventKey* event, FlKeyResponderAsyncCallback callback, @@ -118,27 +117,30 @@ static void fl_key_mock_responder_iface_init( iface->handle_event = fl_key_mock_responder_handle_event; } -static bool fl_key_mock_responder_handle_event( +static void fl_key_mock_responder_handle_event( FlKeyResponder* responder, GdkEventKey* event, FlKeyResponderAsyncCallback callback, gpointer user_data) { FlKeyMockResponder* self = FL_KEY_MOCK_RESPONDER(responder); - g_list_append(self->call_records, + self->call_records = g_list_append(self->call_records, fl_keyboard_call_record_new(self, event, callback, user_data)); self->callback_handler(callback, user_data); } +static void fl_key_mock_responder_class_init(FlKeyMockResponderClass* klass) { +} + +static void fl_key_mock_responder_init(FlKeyMockResponder* self) { +} + static FlKeyMockResponder* fl_key_mock_responder_new( GList* call_records, int delegate_id, CallbackHandler callback_handler = dont_respond) { - g_return_val_if_fail(FL_IS_KEY_RESPONDER(responder), nullptr); - g_return_val_if_fail(event != nullptr, nullptr); - g_return_val_if_fail(callback != nullptr, nullptr); - g_return_val_if_fail(user_data != nullptr, nullptr); + g_return_val_if_fail(callback_handler != nullptr, nullptr); - FlKeyMockResponder* self = FL_KEY_MOCK_RESPONDER(g_object_new(FL_KEY_MOCK_RESPONDER, nullptr)); + FlKeyMockResponder* self = FL_KEY_MOCK_RESPONDER(g_object_new(fl_key_mock_responder_get_type(), nullptr)); self->call_records = call_records; self->callback_handler = callback_handler; @@ -147,27 +149,16 @@ static FlKeyMockResponder* fl_key_mock_responder_new( return self; } -// Decode a response using JsonMethodCodec. Expect the given error. -static void decode_error_response(const char* text, GQuark domain, gint code) { - g_autoptr(FlJsonMethodCodec) codec = fl_json_method_codec_new(); - g_autoptr(GBytes) message = text_to_message(text); - g_autoptr(GError) error = nullptr; - g_autoptr(FlMethodResponse) response = - fl_method_codec_decode_response(FL_METHOD_CODEC(codec), message, &error); - EXPECT_EQ(response, nullptr); - EXPECT_TRUE(g_error_matches(error, domain, code)); -} - -static GdkEvent* key_event_new( - boolean is_down, +static GdkEventKey* key_event_new( + gboolean is_down, guint keyval, guint16 hardware_keycode, guint state, gchar* string, - guint* string_length, + guint string_length, gboolean is_modifier) { GdkEventType type = is_down ? GDK_KEY_PRESS : GDK_KEY_RELEASE; - GdkEvent* event = reinterpret_cast(gdk_event_new(type)); + GdkEventKey* event = reinterpret_cast(gdk_event_new(type)); event->window = nullptr; event->send_event = TRUE; event->time = 0; @@ -187,38 +178,37 @@ namespace { int g_redispatch_keyval = 0; } -static void store_redispatch_scancode(const GdkEvent* event) { - g_redispatch_keyval = event->keyval; +static void store_redispatch_keyval(const GdkEvent* event) { + g_redispatch_keyval = reinterpret_cast(event)->keyval; } TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { - g_autolist(call_records) = NULL; + g_autolist(FlKeyboardCallRecord) call_records = NULL; + FlKeyboardCallRecord* record; gboolean manager_handled = false; g_autoptr(FlKeyboardManager) manager = fl_keyboard_manager_new( - nullptr, _g_redispatch_keyval); + nullptr, store_redispatch_keyval); fl_keyboard_manager_add_responder(manager, - fl_key_mock_responder_new(call_records, 0)); + FL_KEY_RESPONDER(fl_key_mock_responder_new(call_records, 0))); /// Test 1: One event that is handled by the framework // Dispatch a key event + char stringA[] = "a"; manager_handled = fl_keyboard_manager_handle_event( manager, - key_event_new(true, 0x50, 0x70, 0, "a", 1, false)); + key_event_new(true, 0x50, 0x70, 0, stringA, 1, false)); EXPECT_EQ(manager_handled, true); EXPECT_EQ(g_redispatch_keyval, 0); - EXPECT_EQ(g_list_length(call_records), 1); - EXPECT_EQ(g_list_last(call_records).delegate_id, 1); - EXPECT_EQ(g_list_last(call_records).keyval, 0x50); - EXPECT_EQ(g_list_last(call_records).hardware_keycode, 0x70); - - EXPECT_EQ(handler.HasRedispatched(), false); - hook_history.back().callback(true); - EXPECT_EQ(redispatch_scancode, 0); + EXPECT_EQ(g_list_length(call_records), 1u); + record = FL_KEYBOARD_CALL_RECORD(g_list_last(call_records)->data); + EXPECT_EQ(record->responder->delegate_id, 1); + EXPECT_EQ(record->event->keyval, 0x50u); + EXPECT_EQ(record->event->hardware_keycode, 0x70u); - EXPECT_EQ(handler.HasRedispatched(), false); - hook_history.clear(); + record->callback(true, record->user_data); + EXPECT_EQ(g_redispatch_keyval, 0); - redispatch_scancode = 0; + g_redispatch_keyval = 0; } From be64f77c6837c58b23b924998fe97c372bd61bae Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 6 Apr 2021 09:17:48 -0700 Subject: [PATCH 007/126] First Test pass --- shell/platform/linux/fl_keyboard_manager.cc | 64 +++++++++++++---- .../linux/fl_keyboard_manager_test.cc | 72 +++++++++++-------- shell/platform/linux/fl_view.cc | 6 ++ 3 files changed, 98 insertions(+), 44 deletions(-) diff --git a/shell/platform/linux/fl_keyboard_manager.cc b/shell/platform/linux/fl_keyboard_manager.cc index 4262c862dd554..481024acb49a2 100644 --- a/shell/platform/linux/fl_keyboard_manager.cc +++ b/shell/platform/linux/fl_keyboard_manager.cc @@ -6,8 +6,6 @@ #include -G_BEGIN_DECLS - // Declare and define a private class to hold response data from the framework. #define FL_TYPE_KEYBOARD_MANAGER_USER_DATA fl_keyboard_manager_user_data_get_type () G_DECLARE_FINAL_TYPE(FlKeyboardManagerUserData, @@ -23,7 +21,12 @@ struct _FlKeyboardManagerUserData { uint64_t sequence_id; }; -G_END_DECLS +namespace { +typedef struct { + GdkEventKey* event; + FlKeyboardManagerUserData* user_data; +} DispatchPendingToResponderForeachData; +} // Definition for FlKeyboardManagerUserData private class. G_DEFINE_TYPE(FlKeyboardManagerUserData, fl_keyboard_manager_user_data, G_TYPE_OBJECT) @@ -72,6 +75,8 @@ G_DECLARE_FINAL_TYPE(FlKeyboardPendingEvent, GObject); struct _FlKeyboardPendingEvent { + GObject parent_instance; + GdkEventKey* event; // Self-incrementing ID attached to an event sent to the framework. @@ -121,19 +126,30 @@ static uint64_t fl_keyboard_manager_get_event_hash(GdkEventKey* event) { FlKeyboardPendingEvent* fl_keyboard_pending_event_new( GdkEventKey* event, uint64_t sequence_id, size_t to_reply) { + printf("new pending 1\n"); FlKeyboardPendingEvent* self = FL_KEYBOARD_PENDING_EVENT(g_object_new(fl_keyboard_pending_event_get_type(), nullptr)); + printf("new pending 2\n"); + + FL_KEYBOARD_PENDING_EVENT(self); + printf("new 1\n"); // Copy the event to preserve refcounts for referenced values (mainly the // window). GdkEventKey* event_copy = reinterpret_cast( gdk_event_copy(reinterpret_cast(event))); + printf("new 1.5\n"); + FlKeyboardPendingEvent* self2 = FL_KEYBOARD_PENDING_EVENT(self); + printf("new 2\n"); self->event = event_copy; self->sequence_id = sequence_id; self->unreplied = to_reply; self->any_handled = false; self->hash = fl_keyboard_manager_get_event_hash(event); - return self; + printf("new 3\n"); + // FlKeyboardPendingEvent* self2 = FL_KEYBOARD_PENDING_EVENT(self); + printf("new 4\n"); + return self2; } struct _FlKeyboardManager { @@ -219,7 +235,8 @@ static bool fl_keyboard_manager_remove_redispatched(FlKeyboardManager* self, uin static void responder_handle_event_callback(bool handled, gpointer user_data_ptr) { g_return_if_fail(FL_IS_KEYBOARD_MANAGER_USER_DATA(user_data_ptr)); - FlKeyboardManagerUserData* user_data = reinterpret_cast(user_data_ptr); + g_autoptr(FlKeyboardManagerUserData) user_data = FL_KEYBOARD_MANAGER_USER_DATA(user_data_ptr); + printf("callback 2\n"); FlKeyboardManager* self = user_data->manager; guint result_index; @@ -229,16 +246,21 @@ static void responder_handle_event_callback(bool handled, gpointer user_data_ptr compare_pending_by_sequence_id, &result_index); g_return_if_fail(found); - FlKeyboardPendingEvent* pending = static_cast(g_ptr_array_index(self->pending_responds, result_index)); + printf("callback 3\n"); + FlKeyboardPendingEvent* pending1 = reinterpret_cast(g_ptr_array_index(self->pending_responds, result_index)); + FlKeyboardPendingEvent* pending = FL_KEYBOARD_PENDING_EVENT(pending1); + printf("callback 4\n"); g_return_if_fail(pending != nullptr); g_return_if_fail(pending->unreplied > 0); pending->unreplied -= 1; pending->any_handled = pending->any_handled || handled; // All responders have replied. if (pending->unreplied == 0) { + printf("callback 5\n"); g_ptr_array_remove_index_fast(self->pending_responds, result_index); bool should_redispatch = false; if (!pending->any_handled) { + printf("callback 6\n"); // If no responders have handled, send it to text plugin. if (self->text_input_plugin != nullptr && !fl_text_input_plugin_filter_keypress(self->text_input_plugin, pending->event)) { // If text plugin doesn't handle either, redispatch. @@ -246,18 +268,15 @@ static void responder_handle_event_callback(bool handled, gpointer user_data_ptr } } if (should_redispatch) { + printf("callback 7\n"); g_ptr_array_add(self->pending_redispatches, pending); self->redispatch_callback(reinterpret_cast(pending->event)); } else { + printf("callback 8\n"); g_object_unref(pending); } } -} - -static void dispatch_pending_to_responder(gpointer responder_data, gpointer event_data) { - FlKeyResponder* responder = FL_KEY_RESPONDER(responder_data); - GdkEventKey* event = static_cast(event_data); - fl_key_responder_handle_event(responder, event, responder_handle_event_callback, nullptr); + printf("callback ret\n"); } FlKeyboardManager* fl_keyboard_manager_new( @@ -290,22 +309,41 @@ void fl_keyboard_manager_add_responder( g_ptr_array_add(self->responder_list, responder); } +static void dispatch_pending_to_responder(gpointer responder_data, gpointer foreach_data_ptr) { + DispatchPendingToResponderForeachData* foreach_data = + reinterpret_cast(foreach_data_ptr); + FlKeyResponder* responder = FL_KEY_RESPONDER(responder_data); + fl_key_responder_handle_event(responder, foreach_data->event, responder_handle_event_callback, foreach_data->user_data); +} + gboolean fl_keyboard_manager_handle_event(FlKeyboardManager* self, GdkEventKey* event) { g_return_val_if_fail(FL_IS_KEYBOARD_MANAGER(self), FALSE); g_return_val_if_fail(event != nullptr, FALSE); uint64_t incoming_hash = fl_keyboard_manager_get_event_hash(event); + printf("Handle 1\n"); if (fl_keyboard_manager_remove_redispatched(self, incoming_hash)) { + printf("Handle ret\n"); return FALSE; } + printf("Handle 2\n"); FlKeyboardPendingEvent* pending = fl_keyboard_pending_event_new( event, ++self->last_sequence_id, self->responder_list->len); + printf("Handle 2.5\n"); g_ptr_array_add(self->pending_responds, pending); - g_ptr_array_foreach(self->responder_list, dispatch_pending_to_responder, self); + printf("Handle 3\n"); + FlKeyboardManagerUserData* user_data = fl_keyboard_manager_user_data_new( + self, pending->sequence_id); + DispatchPendingToResponderForeachData data{ + .event = event, + .user_data = user_data, + }; + g_ptr_array_foreach(self->responder_list, dispatch_pending_to_responder, &data); + printf("Handle 4\n"); return TRUE; } diff --git a/shell/platform/linux/fl_keyboard_manager_test.cc b/shell/platform/linux/fl_keyboard_manager_test.cc index 18fc9c710e44b..a87dfb36188ea 100644 --- a/shell/platform/linux/fl_keyboard_manager_test.cc +++ b/shell/platform/linux/fl_keyboard_manager_test.cc @@ -23,6 +23,8 @@ G_DECLARE_FINAL_TYPE(FlKeyboardCallRecord, typedef struct _FlKeyMockResponder FlKeyMockResponder; struct _FlKeyboardCallRecord { + GObject parent_instance; + FlKeyMockResponder* responder; GdkEventKey* event; FlKeyResponderAsyncCallback callback; @@ -40,7 +42,7 @@ struct _FlKeyMockResponder { GObject parent_instance; // A weak pointer for a list of FlKeyboardCallRecord. - GList* call_records; + GPtrArray* call_records; CallbackHandler callback_handler; int delegate_id; }; @@ -53,8 +55,6 @@ static void fl_keyboard_call_record_init(FlKeyboardCallRecord* self) {} // Dispose method for FlKeyboardCallRecord. static void fl_keyboard_call_record_dispose(GObject* object) { - // Redundant, but added so that we don't get a warning about unused function - // for FL_IS_KEYBOARD_CALL_RECORD. g_return_if_fail(FL_IS_KEYBOARD_CALL_RECORD(object)); FlKeyboardCallRecord* self = FL_KEYBOARD_CALL_RECORD(object); @@ -77,8 +77,7 @@ static FlKeyboardCallRecord* fl_keyboard_call_record_new( g_return_val_if_fail(callback != nullptr, nullptr); g_return_val_if_fail(user_data != nullptr, nullptr); - FlKeyboardCallRecord* self = FL_KEYBOARD_CALL_RECORD( - g_object_new(fl_keyboard_call_record_get_type(), nullptr)); + FlKeyboardCallRecord* self = FL_KEYBOARD_CALL_RECORD(g_object_new(fl_keyboard_call_record_get_type(), nullptr)); self->responder = responder; self->event = event; @@ -88,10 +87,10 @@ static FlKeyboardCallRecord* fl_keyboard_call_record_new( return self; } -static void dont_respond(FlKeyResponderAsyncCallback callback, gpointer user_data) {} -// static void respond_true(FlKeyResponderAsyncCallback callback, gpointer user_data) { -// callback(true, user_data); -// } +// static void dont_respond(FlKeyResponderAsyncCallback callback, gpointer user_data) {} +static void respond_true(FlKeyResponderAsyncCallback callback, gpointer user_data) { + callback(true, user_data); +} // static void respond_false(FlKeyResponderAsyncCallback callback, gpointer user_data) { // callback(false, user_data); // } @@ -122,9 +121,10 @@ static void fl_key_mock_responder_handle_event( GdkEventKey* event, FlKeyResponderAsyncCallback callback, gpointer user_data) { + printf("MockHandle 1\n"); FlKeyMockResponder* self = FL_KEY_MOCK_RESPONDER(responder); - self->call_records = g_list_append(self->call_records, - fl_keyboard_call_record_new(self, event, callback, user_data)); + g_ptr_array_add(self->call_records, FL_KEYBOARD_CALL_RECORD(fl_keyboard_call_record_new(self, event, callback, user_data))); + printf("MockHandle [0] %lx\n", (uint64_t)FL_KEYBOARD_CALL_RECORD(g_ptr_array_index(self->call_records, 0))); self->callback_handler(callback, user_data); } @@ -135,9 +135,9 @@ static void fl_key_mock_responder_init(FlKeyMockResponder* self) { } static FlKeyMockResponder* fl_key_mock_responder_new( - GList* call_records, + GPtrArray* call_records, int delegate_id, - CallbackHandler callback_handler = dont_respond) { + CallbackHandler callback_handler) { g_return_val_if_fail(callback_handler != nullptr, nullptr); FlKeyMockResponder* self = FL_KEY_MOCK_RESPONDER(g_object_new(fl_key_mock_responder_get_type(), nullptr)); @@ -154,18 +154,16 @@ static GdkEventKey* key_event_new( guint keyval, guint16 hardware_keycode, guint state, - gchar* string, - guint string_length, gboolean is_modifier) { - GdkEventType type = is_down ? GDK_KEY_PRESS : GDK_KEY_RELEASE; - GdkEventKey* event = reinterpret_cast(gdk_event_new(type)); + GdkEventKey* event = g_new(GdkEventKey, 1); + event->type = is_down ? GDK_KEY_PRESS : GDK_KEY_RELEASE; event->window = nullptr; - event->send_event = TRUE; - event->time = 0; + event->send_event = FALSE; + event->time = 12345; event->state = state; event->keyval = keyval; - event->length = string_length; - event->string = string; + event->length = 0; + event->string = nullptr; event->hardware_keycode = hardware_keycode; event->group = 0; event->is_modifier = is_modifier ? 1 : 0; @@ -183,32 +181,44 @@ static void store_redispatch_keyval(const GdkEvent* event) { } TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { - g_autolist(FlKeyboardCallRecord) call_records = NULL; + GPtrArray* call_records = g_ptr_array_new_with_free_func(g_object_unref); FlKeyboardCallRecord* record; gboolean manager_handled = false; + printf("Main 1\n"); g_autoptr(FlKeyboardManager) manager = fl_keyboard_manager_new( nullptr, store_redispatch_keyval); + printf("Main 2\n"); fl_keyboard_manager_add_responder(manager, - FL_KEY_RESPONDER(fl_key_mock_responder_new(call_records, 0))); + FL_KEY_RESPONDER(fl_key_mock_responder_new(call_records, 1, respond_true))); + printf("Main 3\n"); /// Test 1: One event that is handled by the framework // Dispatch a key event - char stringA[] = "a"; + g_autofree GdkEventKey* event = key_event_new(true, GDK_KEY_a, 0x26, 0x10, false); + manager_handled = fl_keyboard_manager_handle_event( manager, - key_event_new(true, 0x50, 0x70, 0, stringA, 1, false)); + event); + printf("Main 4\n"); EXPECT_EQ(manager_handled, true); EXPECT_EQ(g_redispatch_keyval, 0); - EXPECT_EQ(g_list_length(call_records), 1u); - record = FL_KEYBOARD_CALL_RECORD(g_list_last(call_records)->data); + EXPECT_EQ(call_records->len, 1u); + gpointer record_ptr = g_ptr_array_index(call_records, 0); + printf("Main [0] %lx\n", (uint64_t)record_ptr); + record = FL_KEYBOARD_CALL_RECORD(record_ptr); + printf("Main 5\n"); EXPECT_EQ(record->responder->delegate_id, 1); - EXPECT_EQ(record->event->keyval, 0x50u); - EXPECT_EQ(record->event->hardware_keycode, 0x70u); + EXPECT_EQ(record->event->keyval, 0x61u); + EXPECT_EQ(record->event->hardware_keycode, 0x26u); - record->callback(true, record->user_data); - EXPECT_EQ(g_redispatch_keyval, 0); + // record->callback(true, record->user_data); + printf("Main 6\n"); + // EXPECT_EQ(g_redispatch_keyval, 0); g_redispatch_keyval = 0; } + +// #PRESS keyval 0x61 keycode 0x26 state 0x10 ismod 0 snd 0 grp 0 time 1762702987 +// #RELEASE keyval 0x61 keycode 0x26 state 0x10 ismod 0 snd 0 grp 0 time 1762703128 diff --git a/shell/platform/linux/fl_view.cc b/shell/platform/linux/fl_view.cc index 1a6938c2f52c3..dedef95f8171d 100644 --- a/shell/platform/linux/fl_view.cc +++ b/shell/platform/linux/fl_view.cc @@ -502,6 +502,9 @@ static gboolean event_box_motion_notify_event(GtkWidget* widget, static gboolean fl_view_key_press_event(GtkWidget* widget, GdkEventKey* event) { FlView* self = FL_VIEW(widget); + printf("#PRESS keyval 0x%x keycode 0x%x state 0x%x ismod %d snd %d grp %d time %d\n", + event->keyval, event->hardware_keycode, event->state, event->is_modifier, event->send_event, event->group, event->time); + fflush(stdout); return fl_keyboard_manager_handle_event(self->keyboard_manager, event); } @@ -510,6 +513,9 @@ static gboolean fl_view_key_release_event(GtkWidget* widget, GdkEventKey* event) { FlView* self = FL_VIEW(widget); + printf("#RELEASE keyval 0x%x keycode 0x%x state 0x%x ismod %d snd %d grp %d time %d\n", + event->keyval, event->hardware_keycode, event->state, event->is_modifier, event->send_event, event->group, event->time); + fflush(stdout); return fl_keyboard_manager_handle_event(self->keyboard_manager, event); } From 985b03f2a7c52bf70d34a57cab2fa4b137a872ff Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 6 Apr 2021 09:46:35 -0700 Subject: [PATCH 008/126] Check pending. better event --- shell/platform/linux/fl_keyboard_manager.cc | 5 ++ shell/platform/linux/fl_keyboard_manager.h | 2 + .../linux/fl_keyboard_manager_test.cc | 66 ++++++++++--------- 3 files changed, 43 insertions(+), 30 deletions(-) diff --git a/shell/platform/linux/fl_keyboard_manager.cc b/shell/platform/linux/fl_keyboard_manager.cc index 481024acb49a2..0b9a6af7921f3 100644 --- a/shell/platform/linux/fl_keyboard_manager.cc +++ b/shell/platform/linux/fl_keyboard_manager.cc @@ -347,3 +347,8 @@ gboolean fl_keyboard_manager_handle_event(FlKeyboardManager* self, GdkEventKey* return TRUE; } + +gboolean fl_keyboard_manager_has_pending_redispatched(FlKeyboardManager* self) { + g_return_val_if_fail(FL_IS_KEYBOARD_MANAGER(self), FALSE); + return self->pending_redispatches->len > 0; +} diff --git a/shell/platform/linux/fl_keyboard_manager.h b/shell/platform/linux/fl_keyboard_manager.h index 0c787f23c588f..0f8826b05dff3 100644 --- a/shell/platform/linux/fl_keyboard_manager.h +++ b/shell/platform/linux/fl_keyboard_manager.h @@ -69,6 +69,8 @@ void fl_keyboard_manager_add_responder( gboolean fl_keyboard_manager_handle_event(FlKeyboardManager* manager, GdkEventKey* event); +gboolean fl_keyboard_manager_has_pending_redispatched(FlKeyboardManager* manager); + 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 a87dfb36188ea..bbaa99eb5d72e 100644 --- a/shell/platform/linux/fl_keyboard_manager_test.cc +++ b/shell/platform/linux/fl_keyboard_manager_test.cc @@ -87,10 +87,10 @@ static FlKeyboardCallRecord* fl_keyboard_call_record_new( return self; } -// static void dont_respond(FlKeyResponderAsyncCallback callback, gpointer user_data) {} -static void respond_true(FlKeyResponderAsyncCallback callback, gpointer user_data) { - callback(true, user_data); -} +static void dont_respond(FlKeyResponderAsyncCallback callback, gpointer user_data) {} +// static void respond_true(FlKeyResponderAsyncCallback callback, gpointer user_data) { +// callback(true, user_data); +// } // static void respond_false(FlKeyResponderAsyncCallback callback, gpointer user_data) { // callback(false, user_data); // } @@ -149,25 +149,34 @@ static FlKeyMockResponder* fl_key_mock_responder_new( return self; } +static void g_ptr_array_clear(GPtrArray* array) { + g_ptr_array_remove_range(array, 0, array->len); +} + +namespace { +// A global variable to store new event. It is a global variable so that it can +// be returned as a dynamically allocated object for easy use. +GdkEventKey _g_key_event; +} + static GdkEventKey* key_event_new( gboolean is_down, guint keyval, guint16 hardware_keycode, guint state, gboolean is_modifier) { - GdkEventKey* event = g_new(GdkEventKey, 1); - event->type = is_down ? GDK_KEY_PRESS : GDK_KEY_RELEASE; - event->window = nullptr; - event->send_event = FALSE; - event->time = 12345; - event->state = state; - event->keyval = keyval; - event->length = 0; - event->string = nullptr; - event->hardware_keycode = hardware_keycode; - event->group = 0; - event->is_modifier = is_modifier ? 1 : 0; - return event; + _g_key_event.type = is_down ? GDK_KEY_PRESS : GDK_KEY_RELEASE; + _g_key_event.window = nullptr; + _g_key_event.send_event = FALSE; + _g_key_event.time = 12345; + _g_key_event.state = state; + _g_key_event.keyval = keyval; + _g_key_event.length = 0; + _g_key_event.string = nullptr; + _g_key_event.hardware_keycode = hardware_keycode; + _g_key_event.group = 0; + _g_key_event.is_modifier = is_modifier ? 1 : 0; + return &_g_key_event; } namespace { @@ -185,37 +194,34 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { FlKeyboardCallRecord* record; gboolean manager_handled = false; - printf("Main 1\n"); g_autoptr(FlKeyboardManager) manager = fl_keyboard_manager_new( nullptr, store_redispatch_keyval); - printf("Main 2\n"); fl_keyboard_manager_add_responder(manager, - FL_KEY_RESPONDER(fl_key_mock_responder_new(call_records, 1, respond_true))); + FL_KEY_RESPONDER(fl_key_mock_responder_new(call_records, 1, dont_respond))); - printf("Main 3\n"); /// Test 1: One event that is handled by the framework // Dispatch a key event - g_autofree GdkEventKey* event = key_event_new(true, GDK_KEY_a, 0x26, 0x10, false); - manager_handled = fl_keyboard_manager_handle_event( manager, - event); - printf("Main 4\n"); + key_event_new(true, GDK_KEY_a, 0x26, 0x10, false)); EXPECT_EQ(manager_handled, true); EXPECT_EQ(g_redispatch_keyval, 0); EXPECT_EQ(call_records->len, 1u); gpointer record_ptr = g_ptr_array_index(call_records, 0); - printf("Main [0] %lx\n", (uint64_t)record_ptr); record = FL_KEYBOARD_CALL_RECORD(record_ptr); - printf("Main 5\n"); EXPECT_EQ(record->responder->delegate_id, 1); EXPECT_EQ(record->event->keyval, 0x61u); EXPECT_EQ(record->event->hardware_keycode, 0x26u); - // record->callback(true, record->user_data); - printf("Main 6\n"); - // EXPECT_EQ(g_redispatch_keyval, 0); + EXPECT_FALSE(fl_keyboard_manager_has_pending_redispatched(manager)); + record->callback(true, record->user_data); + EXPECT_EQ(g_redispatch_keyval, 0); + EXPECT_FALSE(fl_keyboard_manager_has_pending_redispatched(manager)); + + g_ptr_array_clear(call_records); + + /// Test 2: Two events that are unhandled by the framework g_redispatch_keyval = 0; } From 9373f2fcab3eab2021eb6bb5d38581be471ac3ec Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 6 Apr 2021 09:47:31 -0700 Subject: [PATCH 009/126] Format --- .../linux/fl_key_channel_responder.cc | 49 +++---- .../platform/linux/fl_key_channel_responder.h | 4 +- shell/platform/linux/fl_key_responder.cc | 8 +- shell/platform/linux/fl_key_responder.h | 12 +- shell/platform/linux/fl_keyboard_manager.cc | 122 ++++++++++-------- shell/platform/linux/fl_keyboard_manager.h | 13 +- .../linux/fl_keyboard_manager_test.cc | 82 ++++++------ shell/platform/linux/fl_view.cc | 23 ++-- 8 files changed, 176 insertions(+), 137 deletions(-) diff --git a/shell/platform/linux/fl_key_channel_responder.cc b/shell/platform/linux/fl_key_channel_responder.cc index 75f5c35055997..814a6530cc3aa 100644 --- a/shell/platform/linux/fl_key_channel_responder.cc +++ b/shell/platform/linux/fl_key_channel_responder.cc @@ -38,15 +38,14 @@ struct _FlKeyChannelResponder { uint64_t last_id; }; -static void fl_key_channel_responder_iface_init( - FlKeyResponderInterface* iface); +static void fl_key_channel_responder_iface_init(FlKeyResponderInterface* iface); G_DEFINE_TYPE_WITH_CODE( - FlKeyChannelResponder, - fl_key_channel_responder, - G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE(FL_TYPE_KEY_RESPONDER, - fl_key_channel_responder_iface_init)) + FlKeyChannelResponder, + fl_key_channel_responder, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE(FL_TYPE_KEY_RESPONDER, + fl_key_channel_responder_iface_init)) static void fl_key_channel_responder_handle_event( FlKeyResponder* responder, @@ -135,8 +134,9 @@ static void fl_key_event_response_data_dispose(GObject* object) { g_return_if_fail(FL_IS_KEY_EVENT_RESPONSE_DATA(object)); FlKeyEventResponseData* self = FL_KEY_EVENT_RESPONSE_DATA(object); if (self->responder != nullptr) { - g_object_remove_weak_pointer(G_OBJECT(self->responder), - reinterpret_cast(&(self->responder))); + g_object_remove_weak_pointer( + G_OBJECT(self->responder), + reinterpret_cast(&(self->responder))); self->responder = nullptr; } } @@ -150,13 +150,14 @@ static void fl_key_event_response_data_class_init( // Instance initialization method for FlKeyEventResponseData private class. static void fl_key_event_response_data_init(FlKeyEventResponseData* self) {} -// Creates a new FlKeyEventResponseData private class with a responder that created -// the request, a unique ID for tracking, and optional user data. -// Will keep a weak pointer to the responder. -FlKeyEventResponseData* fl_key_event_response_data_new(FlKeyChannelResponder* responder, - uint64_t id, - FlKeyResponderAsyncCallback callback, - gpointer user_data) { +// Creates a new FlKeyEventResponseData private class with a responder that +// created the request, a unique ID for tracking, and optional user data. Will +// keep a weak pointer to the responder. +FlKeyEventResponseData* fl_key_event_response_data_new( + FlKeyChannelResponder* responder, + uint64_t id, + FlKeyResponderAsyncCallback callback, + gpointer user_data) { FlKeyEventResponseData* self = FL_KEY_EVENT_RESPONSE_DATA( g_object_new(fl_key_event_response_data_get_type(), nullptr)); @@ -172,8 +173,9 @@ FlKeyEventResponseData* fl_key_event_response_data_new(FlKeyChannelResponder* re } // Finds an event in the event queue that was sent to the framework by its ID. -GdkEventKey* fl_key_channel_responder_find_pending_event(FlKeyChannelResponder* self, - uint64_t id) { +GdkEventKey* fl_key_channel_responder_find_pending_event( + FlKeyChannelResponder* self, + uint64_t id) { for (guint i = 0; i < self->pending_events->len; ++i) { if (FL_KEY_EVENT_PAIR(g_ptr_array_index(self->pending_events, i))->id == id) { @@ -253,7 +255,8 @@ static void fl_key_channel_responder_dispose(GObject* object) { } // Initializes the FlKeyChannelResponder class methods. -static void fl_key_channel_responder_class_init(FlKeyChannelResponderClass* klass) { +static void fl_key_channel_responder_class_init( + FlKeyChannelResponderClass* klass) { G_OBJECT_CLASS(klass)->dispose = fl_key_channel_responder_dispose; } @@ -270,14 +273,14 @@ FlKeyChannelResponder* fl_key_channel_responder_new( FlBinaryMessenger* messenger) { g_return_val_if_fail(FL_IS_BINARY_MESSENGER(messenger), nullptr); - FlKeyChannelResponder* self = FL_KEY_CHANNEL_RESPONDER(g_object_new(fl_key_channel_responder_get_type(), nullptr)); + FlKeyChannelResponder* self = FL_KEY_CHANNEL_RESPONDER( + g_object_new(fl_key_channel_responder_get_type(), nullptr)); self->last_id = 1; self->manager = manager; g_autoptr(FlJsonMessageCodec) codec = fl_json_message_codec_new(); - self->channel = fl_basic_message_channel_new( - messenger, kChannelName, - FL_MESSAGE_CODEC(codec)); + self->channel = fl_basic_message_channel_new(messenger, kChannelName, + FL_MESSAGE_CODEC(codec)); self->pending_events = g_ptr_array_new_with_free_func(g_object_unref); return self; diff --git a/shell/platform/linux/fl_key_channel_responder.h b/shell/platform/linux/fl_key_channel_responder.h index 900f6c3b50039..6f1d5d49e5633 100644 --- a/shell/platform/linux/fl_key_channel_responder.h +++ b/shell/platform/linux/fl_key_channel_responder.h @@ -5,8 +5,8 @@ #ifndef FLUTTER_SHELL_PLATFORM_LINUX_FL_KEY_CHANNEL_RESPONDER_H_ #define FLUTTER_SHELL_PLATFORM_LINUX_FL_KEY_CHANNEL_RESPONDER_H_ -#include "flutter/shell/platform/linux/fl_keyboard_manager.h" #include "flutter/shell/platform/linux/fl_key_responder.h" +#include "flutter/shell/platform/linux/fl_keyboard_manager.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_value.h" @@ -14,7 +14,7 @@ G_BEGIN_DECLS -#define FL_TYPE_KEY_CHANNEL_RESPONDER fl_key_channel_responder_get_type () +#define FL_TYPE_KEY_CHANNEL_RESPONDER fl_key_channel_responder_get_type() G_DECLARE_FINAL_TYPE(FlKeyChannelResponder, fl_key_channel_responder, FL, diff --git a/shell/platform/linux/fl_key_responder.cc b/shell/platform/linux/fl_key_responder.cc index 338fd27792120..5628786fc8ecc 100644 --- a/shell/platform/linux/fl_key_responder.cc +++ b/shell/platform/linux/fl_key_responder.cc @@ -8,10 +8,14 @@ G_DEFINE_INTERFACE(FlKeyResponder, fl_key_responder, G_TYPE_OBJECT) static void fl_key_responder_default_init(FlKeyResponderInterface* iface) {} -void fl_key_responder_handle_event(FlKeyResponder* self, GdkEventKey* event, FlKeyResponderAsyncCallback callback, gpointer user_data) { +void fl_key_responder_handle_event(FlKeyResponder* self, + GdkEventKey* event, + FlKeyResponderAsyncCallback callback, + gpointer user_data) { g_return_if_fail(FL_IS_KEY_RESPONDER(self)); g_return_if_fail(event != nullptr); g_return_if_fail(callback != nullptr); - FL_KEY_RESPONDER_GET_IFACE(self)->handle_event(self, event, callback, user_data); + FL_KEY_RESPONDER_GET_IFACE(self)->handle_event(self, event, callback, + user_data); } diff --git a/shell/platform/linux/fl_key_responder.h b/shell/platform/linux/fl_key_responder.h index efcb5581dba42..fb1135411a9c0 100644 --- a/shell/platform/linux/fl_key_responder.h +++ b/shell/platform/linux/fl_key_responder.h @@ -16,7 +16,7 @@ G_BEGIN_DECLS typedef struct _FlKeyboardManager FlKeyboardManager; typedef void (*FlKeyResponderAsyncCallback)(bool handled, gpointer user_data); -#define FL_TYPE_KEY_RESPONDER fl_key_responder_get_type () +#define FL_TYPE_KEY_RESPONDER fl_key_responder_get_type() G_DECLARE_INTERFACE(FlKeyResponder, fl_key_responder, @@ -36,7 +36,10 @@ struct _FlKeyResponderInterface { * * Returns: (transfer full): an #FlPluginRegistrar. */ - void (*handle_event)(FlKeyResponder* responder, GdkEventKey* event, FlKeyResponderAsyncCallback callback, gpointer user_data); + void (*handle_event)(FlKeyResponder* responder, + GdkEventKey* event, + FlKeyResponderAsyncCallback callback, + gpointer user_data); }; /** @@ -46,7 +49,10 @@ struct _FlKeyResponderInterface { * of SystemChannels.keyEvent from the Flutter services library. */ -void fl_key_responder_handle_event(FlKeyResponder* responder, GdkEventKey* event, FlKeyResponderAsyncCallback callback, gpointer user_data); +void fl_key_responder_handle_event(FlKeyResponder* responder, + GdkEventKey* event, + FlKeyResponderAsyncCallback callback, + gpointer user_data); G_END_DECLS diff --git a/shell/platform/linux/fl_keyboard_manager.cc b/shell/platform/linux/fl_keyboard_manager.cc index 0b9a6af7921f3..2b050576618e2 100644 --- a/shell/platform/linux/fl_keyboard_manager.cc +++ b/shell/platform/linux/fl_keyboard_manager.cc @@ -7,7 +7,8 @@ #include // Declare and define a private class to hold response data from the framework. -#define FL_TYPE_KEYBOARD_MANAGER_USER_DATA fl_keyboard_manager_user_data_get_type () +#define FL_TYPE_KEYBOARD_MANAGER_USER_DATA \ + fl_keyboard_manager_user_data_get_type() G_DECLARE_FINAL_TYPE(FlKeyboardManagerUserData, fl_keyboard_manager_user_data, FL, @@ -26,10 +27,12 @@ typedef struct { GdkEventKey* event; FlKeyboardManagerUserData* user_data; } DispatchPendingToResponderForeachData; -} +} // namespace // Definition for FlKeyboardManagerUserData private class. -G_DEFINE_TYPE(FlKeyboardManagerUserData, fl_keyboard_manager_user_data, G_TYPE_OBJECT) +G_DEFINE_TYPE(FlKeyboardManagerUserData, + fl_keyboard_manager_user_data, + G_TYPE_OBJECT) // Dispose method for FlKeyboardManagerUserData private class. static void fl_keyboard_manager_user_data_dispose(GObject* object) { @@ -49,13 +52,15 @@ static void fl_keyboard_manager_user_data_class_init( } // Instance initialization method for FlKeyboardManagerUserData private class. -static void fl_keyboard_manager_user_data_init(FlKeyboardManagerUserData* self) {} - -// Creates a new FlKeyboardManagerUserData private class with a responder that created -// the request, a unique ID for tracking, and optional user data. -// Will keep a weak pointer to the responder. -FlKeyboardManagerUserData* fl_keyboard_manager_user_data_new(FlKeyboardManager* manager, - uint64_t sequence_id) { +static void fl_keyboard_manager_user_data_init( + FlKeyboardManagerUserData* self) {} + +// Creates a new FlKeyboardManagerUserData private class with a responder that +// created the request, a unique ID for tracking, and optional user data. Will +// keep a weak pointer to the responder. +FlKeyboardManagerUserData* fl_keyboard_manager_user_data_new( + FlKeyboardManager* manager, + uint64_t sequence_id) { FlKeyboardManagerUserData* self = FL_KEYBOARD_MANAGER_USER_DATA( g_object_new(fl_keyboard_manager_user_data_get_type(), nullptr)); @@ -105,7 +110,8 @@ static void fl_keyboard_pending_event_dispose(GObject* object) { } // Class Initialization method for FlKeyboardPendingEvent class. -static void fl_keyboard_pending_event_class_init(FlKeyboardPendingEventClass* klass) { +static void fl_keyboard_pending_event_class_init( + FlKeyboardPendingEventClass* klass) { G_OBJECT_CLASS(klass)->dispose = fl_keyboard_pending_event_dispose; } @@ -124,11 +130,12 @@ static uint64_t fl_keyboard_manager_get_event_hash(GdkEventKey* event) { (static_cast(event->hardware_keycode) & 0xffff) << 48; } -FlKeyboardPendingEvent* fl_keyboard_pending_event_new( - GdkEventKey* event, uint64_t sequence_id, size_t to_reply) { +FlKeyboardPendingEvent* fl_keyboard_pending_event_new(GdkEventKey* event, + uint64_t sequence_id, + size_t to_reply) { printf("new pending 1\n"); - FlKeyboardPendingEvent* self = - FL_KEYBOARD_PENDING_EVENT(g_object_new(fl_keyboard_pending_event_get_type(), nullptr)); + FlKeyboardPendingEvent* self = FL_KEYBOARD_PENDING_EVENT( + g_object_new(fl_keyboard_pending_event_get_type(), nullptr)); printf("new pending 2\n"); FL_KEYBOARD_PENDING_EVENT(self); @@ -175,9 +182,7 @@ struct _FlKeyboardManager { uint64_t last_sequence_id; }; -G_DEFINE_TYPE(FlKeyboardManager, - fl_keyboard_manager, - G_TYPE_OBJECT); +G_DEFINE_TYPE(FlKeyboardManager, fl_keyboard_manager, G_TYPE_OBJECT); // Disposes of an FlKeyboardManager instance. static void fl_keyboard_manager_dispose(GObject* object) { @@ -199,32 +204,35 @@ static void fl_keyboard_manager_class_init(FlKeyboardManagerClass* klass) { G_OBJECT_CLASS(klass)->dispose = fl_keyboard_manager_dispose; } -static void fl_keyboard_manager_init(FlKeyboardManager* self) { -} +static void fl_keyboard_manager_init(FlKeyboardManager* self) {} // Compare a #FlKeyboardPendingEvent with the given sequence_id. The #needle // should be a pointer to uint64_t sequence_id. -static gboolean compare_pending_by_sequence_id(gconstpointer pending, gconstpointer needle_sequence_id) { +static gboolean compare_pending_by_sequence_id( + gconstpointer pending, + gconstpointer needle_sequence_id) { uint64_t sequence_id = *reinterpret_cast(needle_sequence_id); - return static_cast(pending)->sequence_id == sequence_id; + return static_cast(pending)->sequence_id == + sequence_id; } // Compare a #FlKeyboardPendingEvent with the given hash. The #needle should be // a pointer to uint64_t hash. -static gboolean compare_pending_by_hash(gconstpointer pending, gconstpointer needle_hash) { +static gboolean compare_pending_by_hash(gconstpointer pending, + gconstpointer needle_hash) { uint64_t hash = *reinterpret_cast(needle_hash); return static_cast(pending)->hash == hash; } -static bool fl_keyboard_manager_remove_redispatched(FlKeyboardManager* self, uint64_t hash) { +static bool fl_keyboard_manager_remove_redispatched(FlKeyboardManager* self, + uint64_t hash) { guint result_index; gboolean found = g_ptr_array_find_with_equal_func( - self->pending_redispatches, - static_cast(&hash), - compare_pending_by_hash, - &result_index); + self->pending_redispatches, static_cast(&hash), + compare_pending_by_hash, &result_index); if (found) { - gpointer removed = g_ptr_array_remove_index_fast(self->pending_redispatches, result_index); + gpointer removed = + g_ptr_array_remove_index_fast(self->pending_redispatches, result_index); g_return_val_if_fail(removed != nullptr, TRUE); g_object_unref(removed); return TRUE; @@ -233,21 +241,22 @@ static bool fl_keyboard_manager_remove_redispatched(FlKeyboardManager* self, uin } } -static void responder_handle_event_callback(bool handled, gpointer user_data_ptr) { +static void responder_handle_event_callback(bool handled, + gpointer user_data_ptr) { g_return_if_fail(FL_IS_KEYBOARD_MANAGER_USER_DATA(user_data_ptr)); - g_autoptr(FlKeyboardManagerUserData) user_data = FL_KEYBOARD_MANAGER_USER_DATA(user_data_ptr); + g_autoptr(FlKeyboardManagerUserData) user_data = + FL_KEYBOARD_MANAGER_USER_DATA(user_data_ptr); printf("callback 2\n"); FlKeyboardManager* self = user_data->manager; guint result_index; gboolean found = g_ptr_array_find_with_equal_func( - self->pending_responds, - &user_data->sequence_id, - compare_pending_by_sequence_id, - &result_index); + self->pending_responds, &user_data->sequence_id, + compare_pending_by_sequence_id, &result_index); g_return_if_fail(found); printf("callback 3\n"); - FlKeyboardPendingEvent* pending1 = reinterpret_cast(g_ptr_array_index(self->pending_responds, result_index)); + FlKeyboardPendingEvent* pending1 = reinterpret_cast( + g_ptr_array_index(self->pending_responds, result_index)); FlKeyboardPendingEvent* pending = FL_KEYBOARD_PENDING_EVENT(pending1); printf("callback 4\n"); g_return_if_fail(pending != nullptr); @@ -262,7 +271,9 @@ static void responder_handle_event_callback(bool handled, gpointer user_data_ptr if (!pending->any_handled) { printf("callback 6\n"); // If no responders have handled, send it to text plugin. - if (self->text_input_plugin != nullptr && !fl_text_input_plugin_filter_keypress(self->text_input_plugin, pending->event)) { + if (self->text_input_plugin != nullptr && + !fl_text_input_plugin_filter_keypress(self->text_input_plugin, + pending->event)) { // If text plugin doesn't handle either, redispatch. should_redispatch = true; } @@ -282,7 +293,9 @@ static void responder_handle_event_callback(bool handled, gpointer user_data_ptr FlKeyboardManager* fl_keyboard_manager_new( FlTextInputPlugin* text_input_plugin, FlKeyboardManagerRedispatcher redispatch_callback) { - g_return_val_if_fail(text_input_plugin == nullptr || FL_IS_TEXT_INPUT_PLUGIN(text_input_plugin), nullptr); + g_return_val_if_fail(text_input_plugin == nullptr || + FL_IS_TEXT_INPUT_PLUGIN(text_input_plugin), + nullptr); g_return_val_if_fail(redispatch_callback != nullptr, nullptr); FlKeyboardManager* self = FL_KEYBOARD_MANAGER( @@ -300,23 +313,27 @@ FlKeyboardManager* fl_keyboard_manager_new( return self; } -void fl_keyboard_manager_add_responder( - FlKeyboardManager* self, - FlKeyResponder* responder) { +void fl_keyboard_manager_add_responder(FlKeyboardManager* self, + FlKeyResponder* responder) { g_return_if_fail(FL_IS_KEYBOARD_MANAGER(self)); g_return_if_fail(responder != nullptr); g_ptr_array_add(self->responder_list, responder); } -static void dispatch_pending_to_responder(gpointer responder_data, gpointer foreach_data_ptr) { +static void dispatch_pending_to_responder(gpointer responder_data, + gpointer foreach_data_ptr) { DispatchPendingToResponderForeachData* foreach_data = - reinterpret_cast(foreach_data_ptr); + reinterpret_cast( + foreach_data_ptr); FlKeyResponder* responder = FL_KEY_RESPONDER(responder_data); - fl_key_responder_handle_event(responder, foreach_data->event, responder_handle_event_callback, foreach_data->user_data); + fl_key_responder_handle_event(responder, foreach_data->event, + responder_handle_event_callback, + foreach_data->user_data); } -gboolean fl_keyboard_manager_handle_event(FlKeyboardManager* self, GdkEventKey* event) { +gboolean fl_keyboard_manager_handle_event(FlKeyboardManager* self, + GdkEventKey* event) { g_return_val_if_fail(FL_IS_KEYBOARD_MANAGER(self), FALSE); g_return_val_if_fail(event != nullptr, FALSE); @@ -329,20 +346,19 @@ gboolean fl_keyboard_manager_handle_event(FlKeyboardManager* self, GdkEventKey* printf("Handle 2\n"); FlKeyboardPendingEvent* pending = fl_keyboard_pending_event_new( - event, - ++self->last_sequence_id, - self->responder_list->len); + event, ++self->last_sequence_id, self->responder_list->len); printf("Handle 2.5\n"); g_ptr_array_add(self->pending_responds, pending); printf("Handle 3\n"); - FlKeyboardManagerUserData* user_data = fl_keyboard_manager_user_data_new( - self, pending->sequence_id); + FlKeyboardManagerUserData* user_data = + fl_keyboard_manager_user_data_new(self, pending->sequence_id); DispatchPendingToResponderForeachData data{ - .event = event, - .user_data = user_data, + .event = event, + .user_data = user_data, }; - g_ptr_array_foreach(self->responder_list, dispatch_pending_to_responder, &data); + g_ptr_array_foreach(self->responder_list, dispatch_pending_to_responder, + &data); printf("Handle 4\n"); return TRUE; diff --git a/shell/platform/linux/fl_keyboard_manager.h b/shell/platform/linux/fl_keyboard_manager.h index 0f8826b05dff3..1ed962c5d21aa 100644 --- a/shell/platform/linux/fl_keyboard_manager.h +++ b/shell/platform/linux/fl_keyboard_manager.h @@ -7,8 +7,8 @@ #include -#include "flutter/shell/platform/linux/fl_text_input_plugin.h" #include "flutter/shell/platform/linux/fl_key_responder.h" +#include "flutter/shell/platform/linux/fl_text_input_plugin.h" /** * FlKeyEventPluginCallback: @@ -63,13 +63,14 @@ FlKeyboardManager* fl_keyboard_manager_new( FlTextInputPlugin* text_input_plugin, FlKeyboardManagerRedispatcher redispatch_callback); -void fl_keyboard_manager_add_responder( - FlKeyboardManager* manager, - FlKeyResponder* responder); +void fl_keyboard_manager_add_responder(FlKeyboardManager* manager, + FlKeyResponder* responder); -gboolean fl_keyboard_manager_handle_event(FlKeyboardManager* manager, GdkEventKey* event); +gboolean fl_keyboard_manager_handle_event(FlKeyboardManager* manager, + GdkEventKey* event); -gboolean fl_keyboard_manager_has_pending_redispatched(FlKeyboardManager* manager); +gboolean fl_keyboard_manager_has_pending_redispatched( + 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 bbaa99eb5d72e..a95b1de2d4802 100644 --- a/shell/platform/linux/fl_keyboard_manager_test.cc +++ b/shell/platform/linux/fl_keyboard_manager_test.cc @@ -9,12 +9,13 @@ #include "gtest/gtest.h" namespace { -typedef void (*CallbackHandler)(FlKeyResponderAsyncCallback callback, gpointer user_data); +typedef void (*CallbackHandler)(FlKeyResponderAsyncCallback callback, + gpointer user_data); } G_BEGIN_DECLS -#define FL_TYPE_KEYBOARD_CALL_RECORD fl_keyboard_call_record_get_type () +#define FL_TYPE_KEYBOARD_CALL_RECORD fl_keyboard_call_record_get_type() G_DECLARE_FINAL_TYPE(FlKeyboardCallRecord, fl_keyboard_call_record, FL, @@ -31,7 +32,7 @@ struct _FlKeyboardCallRecord { gpointer user_data; }; -#define FL_TYPE_KEY_MOCK_RESPONDER fl_key_mock_responder_get_type () +#define FL_TYPE_KEY_MOCK_RESPONDER fl_key_mock_responder_get_type() G_DECLARE_FINAL_TYPE(FlKeyMockResponder, fl_key_mock_responder, FL, @@ -63,7 +64,8 @@ static void fl_keyboard_call_record_dispose(GObject* object) { } // Class Initialization method for FlKeyboardCallRecord class. -static void fl_keyboard_call_record_class_init(FlKeyboardCallRecordClass* klass) { +static void fl_keyboard_call_record_class_init( + FlKeyboardCallRecordClass* klass) { G_OBJECT_CLASS(klass)->dispose = fl_keyboard_call_record_dispose; } @@ -77,7 +79,8 @@ static FlKeyboardCallRecord* fl_keyboard_call_record_new( g_return_val_if_fail(callback != nullptr, nullptr); g_return_val_if_fail(user_data != nullptr, nullptr); - FlKeyboardCallRecord* self = FL_KEYBOARD_CALL_RECORD(g_object_new(fl_keyboard_call_record_get_type(), nullptr)); + FlKeyboardCallRecord* self = FL_KEYBOARD_CALL_RECORD( + g_object_new(fl_keyboard_call_record_get_type(), nullptr)); self->responder = responder; self->event = event; @@ -87,23 +90,24 @@ static FlKeyboardCallRecord* fl_keyboard_call_record_new( return self; } -static void dont_respond(FlKeyResponderAsyncCallback callback, gpointer user_data) {} -// static void respond_true(FlKeyResponderAsyncCallback callback, gpointer user_data) { +static void dont_respond(FlKeyResponderAsyncCallback callback, + gpointer user_data) {} +// static void respond_true(FlKeyResponderAsyncCallback callback, gpointer +// user_data) { // callback(true, user_data); // } -// static void respond_false(FlKeyResponderAsyncCallback callback, gpointer user_data) { +// static void respond_false(FlKeyResponderAsyncCallback callback, gpointer +// user_data) { // callback(false, user_data); // } -static void fl_key_mock_responder_iface_init( - FlKeyResponderInterface* iface); +static void fl_key_mock_responder_iface_init(FlKeyResponderInterface* iface); -G_DEFINE_TYPE_WITH_CODE( - FlKeyMockResponder, - fl_key_mock_responder, - G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE(FL_TYPE_KEY_RESPONDER, - fl_key_mock_responder_iface_init)) +G_DEFINE_TYPE_WITH_CODE(FlKeyMockResponder, + fl_key_mock_responder, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE(FL_TYPE_KEY_RESPONDER, + fl_key_mock_responder_iface_init)) static void fl_key_mock_responder_handle_event( FlKeyResponder* responder, @@ -111,8 +115,7 @@ static void fl_key_mock_responder_handle_event( FlKeyResponderAsyncCallback callback, gpointer user_data); -static void fl_key_mock_responder_iface_init( - FlKeyResponderInterface* iface) { +static void fl_key_mock_responder_iface_init(FlKeyResponderInterface* iface) { iface->handle_event = fl_key_mock_responder_handle_event; } @@ -123,16 +126,17 @@ static void fl_key_mock_responder_handle_event( gpointer user_data) { printf("MockHandle 1\n"); FlKeyMockResponder* self = FL_KEY_MOCK_RESPONDER(responder); - g_ptr_array_add(self->call_records, FL_KEYBOARD_CALL_RECORD(fl_keyboard_call_record_new(self, event, callback, user_data))); - printf("MockHandle [0] %lx\n", (uint64_t)FL_KEYBOARD_CALL_RECORD(g_ptr_array_index(self->call_records, 0))); + g_ptr_array_add(self->call_records, + FL_KEYBOARD_CALL_RECORD(fl_keyboard_call_record_new( + self, event, callback, user_data))); + printf("MockHandle [0] %lx\n", (uint64_t)FL_KEYBOARD_CALL_RECORD( + g_ptr_array_index(self->call_records, 0))); self->callback_handler(callback, user_data); } -static void fl_key_mock_responder_class_init(FlKeyMockResponderClass* klass) { -} +static void fl_key_mock_responder_class_init(FlKeyMockResponderClass* klass) {} -static void fl_key_mock_responder_init(FlKeyMockResponder* self) { -} +static void fl_key_mock_responder_init(FlKeyMockResponder* self) {} static FlKeyMockResponder* fl_key_mock_responder_new( GPtrArray* call_records, @@ -140,7 +144,8 @@ static FlKeyMockResponder* fl_key_mock_responder_new( CallbackHandler callback_handler) { g_return_val_if_fail(callback_handler != nullptr, nullptr); - FlKeyMockResponder* self = FL_KEY_MOCK_RESPONDER(g_object_new(fl_key_mock_responder_get_type(), nullptr)); + FlKeyMockResponder* self = FL_KEY_MOCK_RESPONDER( + g_object_new(fl_key_mock_responder_get_type(), nullptr)); self->call_records = call_records; self->callback_handler = callback_handler; @@ -157,14 +162,13 @@ namespace { // A global variable to store new event. It is a global variable so that it can // be returned as a dynamically allocated object for easy use. GdkEventKey _g_key_event; -} +} // namespace -static GdkEventKey* key_event_new( - gboolean is_down, - guint keyval, - guint16 hardware_keycode, - guint state, - gboolean is_modifier) { +static GdkEventKey* key_event_new(gboolean is_down, + guint keyval, + guint16 hardware_keycode, + guint state, + gboolean is_modifier) { _g_key_event.type = is_down ? GDK_KEY_PRESS : GDK_KEY_RELEASE; _g_key_event.window = nullptr; _g_key_event.send_event = FALSE; @@ -183,7 +187,7 @@ namespace { // A global variable to store redispatched scancode. It is a global variable so // that it can be used in a function without user_data. int g_redispatch_keyval = 0; -} +} // namespace static void store_redispatch_keyval(const GdkEvent* event) { g_redispatch_keyval = reinterpret_cast(event)->keyval; @@ -194,17 +198,17 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { FlKeyboardCallRecord* record; gboolean manager_handled = false; - g_autoptr(FlKeyboardManager) manager = fl_keyboard_manager_new( - nullptr, store_redispatch_keyval); - fl_keyboard_manager_add_responder(manager, - FL_KEY_RESPONDER(fl_key_mock_responder_new(call_records, 1, dont_respond))); + g_autoptr(FlKeyboardManager) manager = + fl_keyboard_manager_new(nullptr, store_redispatch_keyval); + fl_keyboard_manager_add_responder( + manager, FL_KEY_RESPONDER( + fl_key_mock_responder_new(call_records, 1, dont_respond))); /// Test 1: One event that is handled by the framework // Dispatch a key event manager_handled = fl_keyboard_manager_handle_event( - manager, - key_event_new(true, GDK_KEY_a, 0x26, 0x10, false)); + manager, key_event_new(true, GDK_KEY_a, 0x26, 0x10, false)); EXPECT_EQ(manager_handled, true); EXPECT_EQ(g_redispatch_keyval, 0); EXPECT_EQ(call_records->len, 1u); diff --git a/shell/platform/linux/fl_view.cc b/shell/platform/linux/fl_view.cc index dedef95f8171d..cf9e384bd8644 100644 --- a/shell/platform/linux/fl_view.cc +++ b/shell/platform/linux/fl_view.cc @@ -10,8 +10,8 @@ #include "flutter/shell/platform/linux/fl_accessibility_plugin.h" #include "flutter/shell/platform/linux/fl_engine_private.h" -#include "flutter/shell/platform/linux/fl_keyboard_manager.h" #include "flutter/shell/platform/linux/fl_key_channel_responder.h" +#include "flutter/shell/platform/linux/fl_keyboard_manager.h" #include "flutter/shell/platform/linux/fl_mouse_cursor_plugin.h" #include "flutter/shell/platform/linux/fl_platform_plugin.h" #include "flutter/shell/platform/linux/fl_plugin_registrar_private.h" @@ -181,11 +181,10 @@ static void fl_view_constructed(GObject* object) { FlBinaryMessenger* messenger = fl_engine_get_binary_messenger(self->engine); self->accessibility_plugin = fl_accessibility_plugin_new(self); self->keyboard_manager = fl_keyboard_manager_new( - fl_text_input_plugin_new(messenger, self), - gdk_event_put); + fl_text_input_plugin_new(messenger, self), gdk_event_put); fl_keyboard_manager_add_responder( - self->keyboard_manager, - FL_KEY_RESPONDER(fl_key_channel_responder_new(self->keyboard_manager, messenger))); + self->keyboard_manager, FL_KEY_RESPONDER(fl_key_channel_responder_new( + self->keyboard_manager, messenger))); self->mouse_cursor_plugin = fl_mouse_cursor_plugin_new(messenger, self); self->platform_plugin = fl_platform_plugin_new(messenger); @@ -502,8 +501,11 @@ static gboolean event_box_motion_notify_event(GtkWidget* widget, static gboolean fl_view_key_press_event(GtkWidget* widget, GdkEventKey* event) { FlView* self = FL_VIEW(widget); - printf("#PRESS keyval 0x%x keycode 0x%x state 0x%x ismod %d snd %d grp %d time %d\n", - event->keyval, event->hardware_keycode, event->state, event->is_modifier, event->send_event, event->group, event->time); + printf( + "#PRESS keyval 0x%x keycode 0x%x state 0x%x ismod %d snd %d grp %d " + "time %d\n", + event->keyval, event->hardware_keycode, event->state, event->is_modifier, + event->send_event, event->group, event->time); fflush(stdout); return fl_keyboard_manager_handle_event(self->keyboard_manager, event); } @@ -513,8 +515,11 @@ static gboolean fl_view_key_release_event(GtkWidget* widget, GdkEventKey* event) { FlView* self = FL_VIEW(widget); - printf("#RELEASE keyval 0x%x keycode 0x%x state 0x%x ismod %d snd %d grp %d time %d\n", - event->keyval, event->hardware_keycode, event->state, event->is_modifier, event->send_event, event->group, event->time); + printf( + "#RELEASE keyval 0x%x keycode 0x%x state 0x%x ismod %d snd %d grp %d " + "time %d\n", + event->keyval, event->hardware_keycode, event->state, event->is_modifier, + event->send_event, event->group, event->time); fflush(stdout); return fl_keyboard_manager_handle_event(self->keyboard_manager, event); } From 8597c3dea211e33774499f9d7b39a7c83edfed4e Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 6 Apr 2021 10:04:04 -0700 Subject: [PATCH 010/126] Test 2 --- shell/platform/linux/fl_keyboard_manager.cc | 10 ++-- shell/platform/linux/fl_keyboard_manager.h | 2 +- .../linux/fl_keyboard_manager_test.cc | 50 ++++++++++++++++--- 3 files changed, 49 insertions(+), 13 deletions(-) diff --git a/shell/platform/linux/fl_keyboard_manager.cc b/shell/platform/linux/fl_keyboard_manager.cc index 2b050576618e2..ab7ded92b73cf 100644 --- a/shell/platform/linux/fl_keyboard_manager.cc +++ b/shell/platform/linux/fl_keyboard_manager.cc @@ -255,9 +255,7 @@ static void responder_handle_event_callback(bool handled, compare_pending_by_sequence_id, &result_index); g_return_if_fail(found); printf("callback 3\n"); - FlKeyboardPendingEvent* pending1 = reinterpret_cast( - g_ptr_array_index(self->pending_responds, result_index)); - FlKeyboardPendingEvent* pending = FL_KEYBOARD_PENDING_EVENT(pending1); + FlKeyboardPendingEvent* pending = FL_KEYBOARD_PENDING_EVENT(g_ptr_array_index(self->pending_responds, result_index)); printf("callback 4\n"); g_return_if_fail(pending != nullptr); g_return_if_fail(pending->unreplied > 0); @@ -271,7 +269,7 @@ static void responder_handle_event_callback(bool handled, if (!pending->any_handled) { printf("callback 6\n"); // If no responders have handled, send it to text plugin. - if (self->text_input_plugin != nullptr && + if (self->text_input_plugin == nullptr || !fl_text_input_plugin_filter_keypress(self->text_input_plugin, pending->event)) { // If text plugin doesn't handle either, redispatch. @@ -364,7 +362,7 @@ gboolean fl_keyboard_manager_handle_event(FlKeyboardManager* self, return TRUE; } -gboolean fl_keyboard_manager_has_pending_redispatched(FlKeyboardManager* self) { +gboolean fl_keyboard_manager_state_clear(FlKeyboardManager* self) { g_return_val_if_fail(FL_IS_KEYBOARD_MANAGER(self), FALSE); - return self->pending_redispatches->len > 0; + return self->pending_responds->len == 0 && self->pending_redispatches->len == 0; } diff --git a/shell/platform/linux/fl_keyboard_manager.h b/shell/platform/linux/fl_keyboard_manager.h index 1ed962c5d21aa..ce4990c8b8d0a 100644 --- a/shell/platform/linux/fl_keyboard_manager.h +++ b/shell/platform/linux/fl_keyboard_manager.h @@ -69,7 +69,7 @@ void fl_keyboard_manager_add_responder(FlKeyboardManager* manager, gboolean fl_keyboard_manager_handle_event(FlKeyboardManager* manager, GdkEventKey* event); -gboolean fl_keyboard_manager_has_pending_redispatched( +gboolean fl_keyboard_manager_state_clear( 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 a95b1de2d4802..b06bc5edb26d0 100644 --- a/shell/platform/linux/fl_keyboard_manager_test.cc +++ b/shell/platform/linux/fl_keyboard_manager_test.cc @@ -186,7 +186,7 @@ static GdkEventKey* key_event_new(gboolean is_down, namespace { // A global variable to store redispatched scancode. It is a global variable so // that it can be used in a function without user_data. -int g_redispatch_keyval = 0; +guint g_redispatch_keyval = 0; } // namespace static void store_redispatch_keyval(const GdkEvent* event) { @@ -210,7 +210,7 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { manager_handled = fl_keyboard_manager_handle_event( manager, key_event_new(true, GDK_KEY_a, 0x26, 0x10, false)); EXPECT_EQ(manager_handled, true); - EXPECT_EQ(g_redispatch_keyval, 0); + EXPECT_EQ(g_redispatch_keyval, 0u); EXPECT_EQ(call_records->len, 1u); gpointer record_ptr = g_ptr_array_index(call_records, 0); record = FL_KEYBOARD_CALL_RECORD(record_ptr); @@ -218,16 +218,54 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { EXPECT_EQ(record->event->keyval, 0x61u); EXPECT_EQ(record->event->hardware_keycode, 0x26u); - EXPECT_FALSE(fl_keyboard_manager_has_pending_redispatched(manager)); record->callback(true, record->user_data); - EXPECT_EQ(g_redispatch_keyval, 0); - EXPECT_FALSE(fl_keyboard_manager_has_pending_redispatched(manager)); + EXPECT_EQ(g_redispatch_keyval, 0u); + EXPECT_TRUE(fl_keyboard_manager_state_clear(manager)); g_ptr_array_clear(call_records); /// Test 2: Two events that are unhandled by the framework + manager_handled = fl_keyboard_manager_handle_event( + manager, key_event_new(true, GDK_KEY_a, 0x26, 0x10, false)); + EXPECT_EQ(manager_handled, true); + EXPECT_EQ(g_redispatch_keyval, 0u); + EXPECT_EQ(call_records->len, 1u); + record = FL_KEYBOARD_CALL_RECORD(g_ptr_array_index(call_records, 0)); + EXPECT_EQ(record->responder->delegate_id, 1); + EXPECT_EQ(record->event->keyval, 0x61u); + EXPECT_EQ(record->event->hardware_keycode, 0x26u); + + // Dispatch another key event + manager_handled = fl_keyboard_manager_handle_event( + manager, key_event_new(true, GDK_KEY_b, 0x38, 0x10, false)); + EXPECT_EQ(manager_handled, true); + EXPECT_EQ(g_redispatch_keyval, 0u); + EXPECT_EQ(call_records->len, 2u); + record = FL_KEYBOARD_CALL_RECORD(g_ptr_array_index(call_records, 1)); + EXPECT_EQ(record->responder->delegate_id, 1); + EXPECT_EQ(record->event->keyval, 0x62u); + EXPECT_EQ(record->event->hardware_keycode, 0x38u); + + // Resolve the second event first to test out-of-order response + record = FL_KEYBOARD_CALL_RECORD(g_ptr_array_index(call_records, 1)); + record->callback(false, record->user_data); + EXPECT_EQ(g_redispatch_keyval, 0x62u); + record = FL_KEYBOARD_CALL_RECORD(g_ptr_array_index(call_records, 0)); + record->callback(false, record->user_data); + EXPECT_EQ(g_redispatch_keyval, 0x61u); + + // Resolve redispatches + manager_handled = fl_keyboard_manager_handle_event( + manager, key_event_new(true, GDK_KEY_b, 0x38, 0x10, false)); + EXPECT_EQ(manager_handled, false); + manager_handled = fl_keyboard_manager_handle_event( + manager, key_event_new(true, GDK_KEY_a, 0x26, 0x10, false)); + EXPECT_EQ(manager_handled, false); + + EXPECT_TRUE(fl_keyboard_manager_state_clear(manager)); + g_ptr_array_clear(call_records); - g_redispatch_keyval = 0; + g_redispatch_keyval = 0u; } // #PRESS keyval 0x61 keycode 0x26 state 0x10 ismod 0 snd 0 grp 0 time 1762702987 From ba825e9c3a9cff4f3c52cb1bbe64de14bcb8fe05 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 6 Apr 2021 17:09:24 -0700 Subject: [PATCH 011/126] Better event storage --- .../linux/fl_keyboard_manager_test.cc | 49 ++++++++++++++----- 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/shell/platform/linux/fl_keyboard_manager_test.cc b/shell/platform/linux/fl_keyboard_manager_test.cc index b06bc5edb26d0..e3bd76ccab20b 100644 --- a/shell/platform/linux/fl_keyboard_manager_test.cc +++ b/shell/platform/linux/fl_keyboard_manager_test.cc @@ -158,9 +158,13 @@ static void g_ptr_array_clear(GPtrArray* array) { g_ptr_array_remove_range(array, 0, array->len); } +static gpointer g_ptr_array_last(GPtrArray* array) { + return g_ptr_array_index(array, array->len - 1); +} + namespace { // A global variable to store new event. It is a global variable so that it can -// be returned as a dynamically allocated object for easy use. +// be returned by key_event_new for easy use. GdkEventKey _g_key_event; } // namespace @@ -186,11 +190,29 @@ static GdkEventKey* key_event_new(gboolean is_down, namespace { // A global variable to store redispatched scancode. It is a global variable so // that it can be used in a function without user_data. -guint g_redispatch_keyval = 0; +GPtrArray* _g_redispatched_events; } // namespace -static void store_redispatch_keyval(const GdkEvent* event) { - g_redispatch_keyval = reinterpret_cast(event)->keyval; +static GdkEventKey* GDK_EVENT_KEY(gpointer pointer) { + return reinterpret_cast(pointer); +} + +static void gdk_event_destroy_notify(gpointer pointer) { + gdk_event_free((GdkEvent*)pointer); +} + +static GPtrArray* redispatched_events() { + if (_g_redispatched_events == nullptr) { + _g_redispatched_events = g_ptr_array_new_with_free_func(gdk_event_destroy_notify); + } + return _g_redispatched_events; +} +static void store_redispatched_event(const GdkEvent* event) { + // We don't use gdk_event_copy here because it crashes, likely because + // _g_key_event is statically allocated. + GdkEvent* new_event = gdk_event_new(event->type); + *new_event = *event; + g_ptr_array_add(redispatched_events(), new_event); } TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { @@ -199,7 +221,7 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { gboolean manager_handled = false; g_autoptr(FlKeyboardManager) manager = - fl_keyboard_manager_new(nullptr, store_redispatch_keyval); + fl_keyboard_manager_new(nullptr, store_redispatched_event); fl_keyboard_manager_add_responder( manager, FL_KEY_RESPONDER( fl_key_mock_responder_new(call_records, 1, dont_respond))); @@ -210,7 +232,7 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { manager_handled = fl_keyboard_manager_handle_event( manager, key_event_new(true, GDK_KEY_a, 0x26, 0x10, false)); EXPECT_EQ(manager_handled, true); - EXPECT_EQ(g_redispatch_keyval, 0u); + EXPECT_EQ(redispatched_events()->len, 0u); EXPECT_EQ(call_records->len, 1u); gpointer record_ptr = g_ptr_array_index(call_records, 0); record = FL_KEYBOARD_CALL_RECORD(record_ptr); @@ -219,7 +241,7 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { EXPECT_EQ(record->event->hardware_keycode, 0x26u); record->callback(true, record->user_data); - EXPECT_EQ(g_redispatch_keyval, 0u); + EXPECT_EQ(redispatched_events()->len, 0u); EXPECT_TRUE(fl_keyboard_manager_state_clear(manager)); g_ptr_array_clear(call_records); @@ -228,7 +250,7 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { manager_handled = fl_keyboard_manager_handle_event( manager, key_event_new(true, GDK_KEY_a, 0x26, 0x10, false)); EXPECT_EQ(manager_handled, true); - EXPECT_EQ(g_redispatch_keyval, 0u); + EXPECT_EQ(redispatched_events()->len, 0u); EXPECT_EQ(call_records->len, 1u); record = FL_KEYBOARD_CALL_RECORD(g_ptr_array_index(call_records, 0)); EXPECT_EQ(record->responder->delegate_id, 1); @@ -239,7 +261,7 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { manager_handled = fl_keyboard_manager_handle_event( manager, key_event_new(true, GDK_KEY_b, 0x38, 0x10, false)); EXPECT_EQ(manager_handled, true); - EXPECT_EQ(g_redispatch_keyval, 0u); + EXPECT_EQ(redispatched_events()->len, 0u); EXPECT_EQ(call_records->len, 2u); record = FL_KEYBOARD_CALL_RECORD(g_ptr_array_index(call_records, 1)); EXPECT_EQ(record->responder->delegate_id, 1); @@ -249,10 +271,12 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { // Resolve the second event first to test out-of-order response record = FL_KEYBOARD_CALL_RECORD(g_ptr_array_index(call_records, 1)); record->callback(false, record->user_data); - EXPECT_EQ(g_redispatch_keyval, 0x62u); + EXPECT_EQ(redispatched_events()->len, 1u); + EXPECT_EQ(GDK_EVENT_KEY(g_ptr_array_last(redispatched_events()))->keyval, 0x62u); record = FL_KEYBOARD_CALL_RECORD(g_ptr_array_index(call_records, 0)); record->callback(false, record->user_data); - EXPECT_EQ(g_redispatch_keyval, 0x61u); + EXPECT_EQ(redispatched_events()->len, 2u); + EXPECT_EQ(GDK_EVENT_KEY(g_ptr_array_last(redispatched_events()))->keyval, 0x61u); // Resolve redispatches manager_handled = fl_keyboard_manager_handle_event( @@ -265,8 +289,9 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { EXPECT_TRUE(fl_keyboard_manager_state_clear(manager)); g_ptr_array_clear(call_records); - g_redispatch_keyval = 0u; + g_ptr_array_clear(redispatched_events()); } + // #PRESS keyval 0x61 keycode 0x26 state 0x10 ismod 0 snd 0 grp 0 time 1762702987 // #RELEASE keyval 0x61 keycode 0x26 state 0x10 ismod 0 snd 0 grp 0 time 1762703128 From 53363e439da70cf99d6e125cc5ccc157fd86b16a Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 6 Apr 2021 17:19:16 -0700 Subject: [PATCH 012/126] Better async test --- .../linux/fl_keyboard_manager_test.cc | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/shell/platform/linux/fl_keyboard_manager_test.cc b/shell/platform/linux/fl_keyboard_manager_test.cc index e3bd76ccab20b..519e547b79014 100644 --- a/shell/platform/linux/fl_keyboard_manager_test.cc +++ b/shell/platform/linux/fl_keyboard_manager_test.cc @@ -11,6 +11,9 @@ namespace { typedef void (*CallbackHandler)(FlKeyResponderAsyncCallback callback, gpointer user_data); + +constexpr guint16 kKeyCodeKeyA = 0x26u; +constexpr guint16 kKeyCodeKeyB = 0x38u; } G_BEGIN_DECLS @@ -230,7 +233,7 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { // Dispatch a key event manager_handled = fl_keyboard_manager_handle_event( - manager, key_event_new(true, GDK_KEY_a, 0x26, 0x10, false)); + manager, key_event_new(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); EXPECT_EQ(manager_handled, true); EXPECT_EQ(redispatched_events()->len, 0u); EXPECT_EQ(call_records->len, 1u); @@ -248,7 +251,7 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { /// Test 2: Two events that are unhandled by the framework manager_handled = fl_keyboard_manager_handle_event( - manager, key_event_new(true, GDK_KEY_a, 0x26, 0x10, false)); + manager, key_event_new(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); EXPECT_EQ(manager_handled, true); EXPECT_EQ(redispatched_events()->len, 0u); EXPECT_EQ(call_records->len, 1u); @@ -259,7 +262,7 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { // Dispatch another key event manager_handled = fl_keyboard_manager_handle_event( - manager, key_event_new(true, GDK_KEY_b, 0x38, 0x10, false)); + manager, key_event_new(true, GDK_KEY_b, kKeyCodeKeyB, 0x10, false)); EXPECT_EQ(manager_handled, true); EXPECT_EQ(redispatched_events()->len, 0u); EXPECT_EQ(call_records->len, 2u); @@ -278,20 +281,30 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { EXPECT_EQ(redispatched_events()->len, 2u); EXPECT_EQ(GDK_EVENT_KEY(g_ptr_array_last(redispatched_events()))->keyval, 0x61u); + g_ptr_array_clear(call_records); + // Resolve redispatches manager_handled = fl_keyboard_manager_handle_event( - manager, key_event_new(true, GDK_KEY_b, 0x38, 0x10, false)); + manager, GDK_EVENT_KEY(g_ptr_array_index(redispatched_events(), 0))); EXPECT_EQ(manager_handled, false); manager_handled = fl_keyboard_manager_handle_event( - manager, key_event_new(true, GDK_KEY_a, 0x26, 0x10, false)); + manager, GDK_EVENT_KEY(g_ptr_array_index(redispatched_events(), 1))); EXPECT_EQ(manager_handled, false); + EXPECT_EQ(call_records->len, 0u); + g_ptr_array_clear(redispatched_events()); EXPECT_TRUE(fl_keyboard_manager_state_clear(manager)); - g_ptr_array_clear(call_records); - g_ptr_array_clear(redispatched_events()); -} + /// Test 3: Dispatch the same event again to ensure that prevention from + /// redispatching only works once. + manager_handled = fl_keyboard_manager_handle_event( + manager, key_event_new(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); + EXPECT_EQ(manager_handled, true); + EXPECT_EQ(redispatched_events()->len, 0u); + EXPECT_EQ(call_records->len, 1u); + record = FL_KEYBOARD_CALL_RECORD(g_ptr_array_index(call_records, 0)); + record->callback(true, record->user_data); -// #PRESS keyval 0x61 keycode 0x26 state 0x10 ismod 0 snd 0 grp 0 time 1762702987 -// #RELEASE keyval 0x61 keycode 0x26 state 0x10 ismod 0 snd 0 grp 0 time 1762703128 + g_ptr_array_clear(redispatched_events()); +} From 61df3cf19397e001961b3d559af6f5075dd470b9 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 6 Apr 2021 18:13:51 -0700 Subject: [PATCH 013/126] Sync test --- .../linux/fl_keyboard_manager_test.cc | 80 +++++++++++++++---- 1 file changed, 63 insertions(+), 17 deletions(-) diff --git a/shell/platform/linux/fl_keyboard_manager_test.cc b/shell/platform/linux/fl_keyboard_manager_test.cc index 519e547b79014..2763019090bb3 100644 --- a/shell/platform/linux/fl_keyboard_manager_test.cc +++ b/shell/platform/linux/fl_keyboard_manager_test.cc @@ -95,14 +95,12 @@ static FlKeyboardCallRecord* fl_keyboard_call_record_new( static void dont_respond(FlKeyResponderAsyncCallback callback, gpointer user_data) {} -// static void respond_true(FlKeyResponderAsyncCallback callback, gpointer -// user_data) { -// callback(true, user_data); -// } -// static void respond_false(FlKeyResponderAsyncCallback callback, gpointer -// user_data) { -// callback(false, user_data); -// } +static void respond_true(FlKeyResponderAsyncCallback callback, gpointer user_data) { + callback(true, user_data); +} +static void respond_false(FlKeyResponderAsyncCallback callback, gpointer user_data) { + callback(false, user_data); +} static void fl_key_mock_responder_iface_init(FlKeyResponderInterface* iface); @@ -143,15 +141,12 @@ static void fl_key_mock_responder_init(FlKeyMockResponder* self) {} static FlKeyMockResponder* fl_key_mock_responder_new( GPtrArray* call_records, - int delegate_id, - CallbackHandler callback_handler) { - g_return_val_if_fail(callback_handler != nullptr, nullptr); - + int delegate_id) { FlKeyMockResponder* self = FL_KEY_MOCK_RESPONDER( g_object_new(fl_key_mock_responder_get_type(), nullptr)); self->call_records = call_records; - self->callback_handler = callback_handler; + self->callback_handler = dont_respond; self->delegate_id = delegate_id; return self; @@ -226,8 +221,7 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { g_autoptr(FlKeyboardManager) manager = fl_keyboard_manager_new(nullptr, store_redispatched_event); fl_keyboard_manager_add_responder( - manager, FL_KEY_RESPONDER( - fl_key_mock_responder_new(call_records, 1, dont_respond))); + manager, FL_KEY_RESPONDER(fl_key_mock_responder_new(call_records, 1))); /// Test 1: One event that is handled by the framework @@ -237,8 +231,7 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { EXPECT_EQ(manager_handled, true); EXPECT_EQ(redispatched_events()->len, 0u); EXPECT_EQ(call_records->len, 1u); - gpointer record_ptr = g_ptr_array_index(call_records, 0); - record = FL_KEYBOARD_CALL_RECORD(record_ptr); + record = FL_KEYBOARD_CALL_RECORD(g_ptr_array_index(call_records, 0)); EXPECT_EQ(record->responder->delegate_id, 1); EXPECT_EQ(record->event->keyval, 0x61u); EXPECT_EQ(record->event->hardware_keycode, 0x26u); @@ -308,3 +301,56 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { g_ptr_array_clear(redispatched_events()); } + +TEST(FlKeyboardManagerTest, SingleDelegateWithSyncResponds) { + GPtrArray* call_records = g_ptr_array_new_with_free_func(g_object_unref); + FlKeyboardCallRecord* record; + + gboolean manager_handled = false; + g_autoptr(FlKeyboardManager) manager = + fl_keyboard_manager_new(nullptr, store_redispatched_event); + FlKeyMockResponder* responder = fl_key_mock_responder_new(call_records, 1); + fl_keyboard_manager_add_responder(manager, FL_KEY_RESPONDER(responder)); + + /// Test 1: One event that is handled by the framework + + // Dispatch a key event + responder->callback_handler = respond_true; + manager_handled = fl_keyboard_manager_handle_event( + manager, key_event_new(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); + EXPECT_EQ(manager_handled, true); + EXPECT_EQ(call_records->len, 1u); + record = FL_KEYBOARD_CALL_RECORD(g_ptr_array_index(call_records, 0)); + EXPECT_EQ(record->responder->delegate_id, 1); + EXPECT_EQ(record->event->keyval, 0x61u); + EXPECT_EQ(record->event->hardware_keycode, 0x26u); + EXPECT_EQ(redispatched_events()->len, 0u); + + EXPECT_TRUE(fl_keyboard_manager_state_clear(manager)); + + EXPECT_TRUE(fl_keyboard_manager_state_clear(manager)); + g_ptr_array_clear(call_records); + + /// Test 2: An event unhandled by the framework + responder->callback_handler = respond_false; + manager_handled = fl_keyboard_manager_handle_event( + manager, key_event_new(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); + EXPECT_EQ(manager_handled, true); + EXPECT_EQ(call_records->len, 1u); + record = FL_KEYBOARD_CALL_RECORD(g_ptr_array_index(call_records, 0)); + EXPECT_EQ(record->responder->delegate_id, 1); + EXPECT_EQ(record->event->keyval, 0x61u); + EXPECT_EQ(record->event->hardware_keycode, 0x26u); + EXPECT_EQ(redispatched_events()->len, 1u); + + g_ptr_array_clear(call_records); + + // Resolve redispatch + manager_handled = fl_keyboard_manager_handle_event( + manager, GDK_EVENT_KEY(g_ptr_array_index(redispatched_events(), 0))); + EXPECT_EQ(manager_handled, false); + EXPECT_EQ(call_records->len, 0u); + + EXPECT_TRUE(fl_keyboard_manager_state_clear(manager)); + g_ptr_array_clear(redispatched_events()); +} From c544bd21028d583a41d5c30e8e7694a2b4805cb2 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 6 Apr 2021 18:58:09 -0700 Subject: [PATCH 014/126] Two async --- shell/platform/linux/fl_keyboard_manager.cc | 10 +-- .../linux/fl_keyboard_manager_test.cc | 66 +++++++++++++++++++ 2 files changed, 72 insertions(+), 4 deletions(-) diff --git a/shell/platform/linux/fl_keyboard_manager.cc b/shell/platform/linux/fl_keyboard_manager.cc index ab7ded92b73cf..d62e5e95b1756 100644 --- a/shell/platform/linux/fl_keyboard_manager.cc +++ b/shell/platform/linux/fl_keyboard_manager.cc @@ -244,19 +244,19 @@ static bool fl_keyboard_manager_remove_redispatched(FlKeyboardManager* self, static void responder_handle_event_callback(bool handled, gpointer user_data_ptr) { g_return_if_fail(FL_IS_KEYBOARD_MANAGER_USER_DATA(user_data_ptr)); - g_autoptr(FlKeyboardManagerUserData) user_data = + FlKeyboardManagerUserData* user_data = FL_KEYBOARD_MANAGER_USER_DATA(user_data_ptr); printf("callback 2\n"); FlKeyboardManager* self = user_data->manager; - guint result_index; + guint result_index = -1; gboolean found = g_ptr_array_find_with_equal_func( self->pending_responds, &user_data->sequence_id, compare_pending_by_sequence_id, &result_index); g_return_if_fail(found); printf("callback 3\n"); FlKeyboardPendingEvent* pending = FL_KEYBOARD_PENDING_EVENT(g_ptr_array_index(self->pending_responds, result_index)); - printf("callback 4\n"); + printf("callback 4 unrep %zu\n", pending->unreplied); g_return_if_fail(pending != nullptr); g_return_if_fail(pending->unreplied > 0); pending->unreplied -= 1; @@ -264,6 +264,7 @@ static void responder_handle_event_callback(bool handled, // All responders have replied. if (pending->unreplied == 0) { printf("callback 5\n"); + g_object_unref(user_data_ptr); g_ptr_array_remove_index_fast(self->pending_responds, result_index); bool should_redispatch = false; if (!pending->any_handled) { @@ -317,6 +318,7 @@ void fl_keyboard_manager_add_responder(FlKeyboardManager* self, g_return_if_fail(responder != nullptr); g_ptr_array_add(self->responder_list, responder); + printf("after add len %u\n", self->responder_list->len); } static void dispatch_pending_to_responder(gpointer responder_data, @@ -342,7 +344,7 @@ gboolean fl_keyboard_manager_handle_event(FlKeyboardManager* self, return FALSE; } - printf("Handle 2\n"); + printf("Handle 2 len %u\n", self->responder_list->len); FlKeyboardPendingEvent* pending = fl_keyboard_pending_event_new( event, ++self->last_sequence_id, self->responder_list->len); diff --git a/shell/platform/linux/fl_keyboard_manager_test.cc b/shell/platform/linux/fl_keyboard_manager_test.cc index 2763019090bb3..0d08a0f93278f 100644 --- a/shell/platform/linux/fl_keyboard_manager_test.cc +++ b/shell/platform/linux/fl_keyboard_manager_test.cc @@ -354,3 +354,69 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithSyncResponds) { EXPECT_TRUE(fl_keyboard_manager_state_clear(manager)); g_ptr_array_clear(redispatched_events()); } + +TEST(FlKeyboardManagerTest, WithTwoAsyncDelegates) { + GPtrArray* call_records = g_ptr_array_new_with_free_func(g_object_unref); + FlKeyboardCallRecord* record; + + gboolean manager_handled = false; + g_autoptr(FlKeyboardManager) manager = + fl_keyboard_manager_new(nullptr, store_redispatched_event); + fl_keyboard_manager_add_responder( + manager, FL_KEY_RESPONDER(fl_key_mock_responder_new(call_records, 1))); + fl_keyboard_manager_add_responder( + manager, FL_KEY_RESPONDER(fl_key_mock_responder_new(call_records, 2))); + + /// Test 1: One delegate responds true, the other false + + manager_handled = fl_keyboard_manager_handle_event( + manager, key_event_new(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); + + EXPECT_EQ(manager_handled, true); + EXPECT_EQ(redispatched_events()->len, 0u); + EXPECT_EQ(call_records->len, 2u); + record = FL_KEYBOARD_CALL_RECORD(g_ptr_array_index(call_records, 0)); + EXPECT_EQ(record->responder->delegate_id, 1); + EXPECT_EQ(record->event->keyval, 0x61u); + record = FL_KEYBOARD_CALL_RECORD(g_ptr_array_index(call_records, 1)); + EXPECT_EQ(record->responder->delegate_id, 2); + EXPECT_EQ(record->event->keyval, 0x61u); + + record = FL_KEYBOARD_CALL_RECORD(g_ptr_array_index(call_records, 0)); + record->callback(true, record->user_data); + printf("T1 mid\n"); + record = FL_KEYBOARD_CALL_RECORD(g_ptr_array_index(call_records, 1)); + record->callback(false, record->user_data); + EXPECT_EQ(redispatched_events()->len, 0u); + + EXPECT_TRUE(fl_keyboard_manager_state_clear(manager)); + g_ptr_array_clear(call_records); + + /// Test 2: All delegates respond false + manager_handled = fl_keyboard_manager_handle_event( + manager, key_event_new(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); + + EXPECT_EQ(manager_handled, true); + EXPECT_EQ(redispatched_events()->len, 0u); + EXPECT_EQ(call_records->len, 2u); + + record = FL_KEYBOARD_CALL_RECORD(g_ptr_array_index(call_records, 0)); + record->callback(false, record->user_data); + EXPECT_EQ(redispatched_events()->len, 0u); + record = FL_KEYBOARD_CALL_RECORD(g_ptr_array_index(call_records, 1)); + record->callback(false, record->user_data); + EXPECT_EQ(redispatched_events()->len, 1u); + + g_ptr_array_clear(call_records); + + // Resolve redispatch + manager_handled = fl_keyboard_manager_handle_event( + manager, GDK_EVENT_KEY(g_ptr_array_index(redispatched_events(), 0))); + EXPECT_EQ(manager_handled, false); + EXPECT_EQ(call_records->len, 0u); + + EXPECT_TRUE(fl_keyboard_manager_state_clear(manager)); + g_ptr_array_clear(call_records); + + g_ptr_array_clear(redispatched_events()); +} From 74e5a0aaf8ee3a07bb22d4901172e8f4b0386e74 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Wed, 7 Apr 2021 05:14:35 -0700 Subject: [PATCH 015/126] Remove manager from responder --- shell/platform/linux/fl_key_channel_responder.cc | 3 --- shell/platform/linux/fl_key_channel_responder.h | 4 +--- shell/platform/linux/fl_view.cc | 3 +-- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/shell/platform/linux/fl_key_channel_responder.cc b/shell/platform/linux/fl_key_channel_responder.cc index 814a6530cc3aa..ea769f55be3af 100644 --- a/shell/platform/linux/fl_key_channel_responder.cc +++ b/shell/platform/linux/fl_key_channel_responder.cc @@ -32,7 +32,6 @@ static constexpr uint64_t kMaxPendingEvents = 1000; struct _FlKeyChannelResponder { GObject parent_instance; - FlKeyboardManager* manager; FlBasicMessageChannel* channel; GPtrArray* pending_events; uint64_t last_id; @@ -269,14 +268,12 @@ static void fl_key_channel_responder_init(FlKeyChannelResponder* self) {} // an optional callback to call when a response is received, and an optional // channel name to use when sending messages. FlKeyChannelResponder* fl_key_channel_responder_new( - FlKeyboardManager* manager, FlBinaryMessenger* messenger) { g_return_val_if_fail(FL_IS_BINARY_MESSENGER(messenger), nullptr); FlKeyChannelResponder* self = FL_KEY_CHANNEL_RESPONDER( g_object_new(fl_key_channel_responder_get_type(), nullptr)); self->last_id = 1; - self->manager = manager; g_autoptr(FlJsonMessageCodec) codec = fl_json_message_codec_new(); self->channel = fl_basic_message_channel_new(messenger, kChannelName, diff --git a/shell/platform/linux/fl_key_channel_responder.h b/shell/platform/linux/fl_key_channel_responder.h index 6f1d5d49e5633..67dd41b94db32 100644 --- a/shell/platform/linux/fl_key_channel_responder.h +++ b/shell/platform/linux/fl_key_channel_responder.h @@ -48,9 +48,7 @@ G_DECLARE_FINAL_TYPE(FlKeyChannelResponder, * * Returns: a new #FlKeyChannelResponder. */ -FlKeyChannelResponder* fl_key_channel_responder_new( - FlKeyboardManager* manager, - FlBinaryMessenger* messenger); +FlKeyChannelResponder* fl_key_channel_responder_new(FlBinaryMessenger* messenger); G_END_DECLS diff --git a/shell/platform/linux/fl_view.cc b/shell/platform/linux/fl_view.cc index cf9e384bd8644..e30b85ade5e81 100644 --- a/shell/platform/linux/fl_view.cc +++ b/shell/platform/linux/fl_view.cc @@ -183,8 +183,7 @@ static void fl_view_constructed(GObject* object) { self->keyboard_manager = fl_keyboard_manager_new( fl_text_input_plugin_new(messenger, self), gdk_event_put); fl_keyboard_manager_add_responder( - self->keyboard_manager, FL_KEY_RESPONDER(fl_key_channel_responder_new( - self->keyboard_manager, messenger))); + self->keyboard_manager, FL_KEY_RESPONDER(fl_key_channel_responder_new(messenger))); self->mouse_cursor_plugin = fl_mouse_cursor_plugin_new(messenger, self); self->platform_plugin = fl_platform_plugin_new(messenger); From ac0162302f2525014897707d5ec99e3dc2e7bc56 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Wed, 7 Apr 2021 05:27:15 -0700 Subject: [PATCH 016/126] FlKeyChannelResponderTest, SendKeyEvent (but other error) --- shell/platform/linux/BUILD.gn | 1 + .../linux/fl_key_channel_responder.cc | 12 +- .../platform/linux/fl_key_channel_responder.h | 10 +- .../linux/fl_key_channel_responder_test.cc | 200 ++++++++++++++++++ 4 files changed, 220 insertions(+), 3 deletions(-) create mode 100644 shell/platform/linux/fl_key_channel_responder_test.cc diff --git a/shell/platform/linux/BUILD.gn b/shell/platform/linux/BUILD.gn index a1a0adb664f5c..77e66e5250eb4 100644 --- a/shell/platform/linux/BUILD.gn +++ b/shell/platform/linux/BUILD.gn @@ -169,6 +169,7 @@ executable("flutter_linux_unittests") { "fl_json_message_codec_test.cc", "fl_json_method_codec_test.cc", "fl_keyboard_manager_test.cc", + "fl_key_channel_responder_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_channel_responder.cc b/shell/platform/linux/fl_key_channel_responder.cc index ea769f55be3af..e03082d1e0913 100644 --- a/shell/platform/linux/fl_key_channel_responder.cc +++ b/shell/platform/linux/fl_key_channel_responder.cc @@ -35,6 +35,8 @@ struct _FlKeyChannelResponder { FlBasicMessageChannel* channel; GPtrArray* pending_events; uint64_t last_id; + + FlKeyChannelResponderMock* mock; }; static void fl_key_channel_responder_iface_init(FlKeyResponderInterface* iface); @@ -232,6 +234,9 @@ static void handle_response(GObject* object, FlBasicMessageChannel* messageChannel = FL_BASIC_MESSAGE_CHANNEL(object); FlValue* message = fl_basic_message_channel_send_finish(messageChannel, result, &error); + if (self->mock != nullptr && self->mock->value_converter != nullptr) { + message = self->mock->value_converter(message); + } if (error != nullptr) { g_warning("Unable to retrieve framework response: %s", error->message); return; @@ -268,15 +273,18 @@ static void fl_key_channel_responder_init(FlKeyChannelResponder* self) {} // an optional callback to call when a response is received, and an optional // channel name to use when sending messages. FlKeyChannelResponder* fl_key_channel_responder_new( - FlBinaryMessenger* messenger) { + FlBinaryMessenger* messenger, + FlKeyChannelResponderMock* mock) { g_return_val_if_fail(FL_IS_BINARY_MESSENGER(messenger), nullptr); FlKeyChannelResponder* self = FL_KEY_CHANNEL_RESPONDER( g_object_new(fl_key_channel_responder_get_type(), nullptr)); self->last_id = 1; + self->mock = mock; g_autoptr(FlJsonMessageCodec) codec = fl_json_message_codec_new(); - self->channel = fl_basic_message_channel_new(messenger, kChannelName, + const char* channel_name = mock == nullptr ? kChannelName : mock->channel_name; + self->channel = fl_basic_message_channel_new(messenger, channel_name, FL_MESSAGE_CODEC(codec)); self->pending_events = g_ptr_array_new_with_free_func(g_object_unref); diff --git a/shell/platform/linux/fl_key_channel_responder.h b/shell/platform/linux/fl_key_channel_responder.h index 67dd41b94db32..18d53c78a0f50 100644 --- a/shell/platform/linux/fl_key_channel_responder.h +++ b/shell/platform/linux/fl_key_channel_responder.h @@ -12,6 +12,13 @@ #include +typedef FlValue* (*FlValueConverter)(FlValue*); + +typedef struct _FlKeyChannelResponderMock { + FlValueConverter value_converter; + const char* channel_name; +} FlKeyChannelResponderMock; + G_BEGIN_DECLS #define FL_TYPE_KEY_CHANNEL_RESPONDER fl_key_channel_responder_get_type() @@ -48,7 +55,8 @@ G_DECLARE_FINAL_TYPE(FlKeyChannelResponder, * * Returns: a new #FlKeyChannelResponder. */ -FlKeyChannelResponder* fl_key_channel_responder_new(FlBinaryMessenger* messenger); +FlKeyChannelResponder* fl_key_channel_responder_new(FlBinaryMessenger* messenger, + FlKeyChannelResponderMock* mock = nullptr); G_END_DECLS diff --git a/shell/platform/linux/fl_key_channel_responder_test.cc b/shell/platform/linux/fl_key_channel_responder_test.cc new file mode 100644 index 0000000000000..355c078522ebb --- /dev/null +++ b/shell/platform/linux/fl_key_channel_responder_test.cc @@ -0,0 +1,200 @@ +// 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_key_channel_responder.h" + +#include "gtest/gtest.h" + +#include "flutter/shell/platform/linux/fl_engine_private.h" +#include "flutter/shell/platform/linux/fl_binary_messenger_private.h" +#include "flutter/shell/platform/linux/testing/fl_test.h" + +// namespace { +// struct EchoResponseData { +// GMainLoop* loop; +// } +// } + +static const char* expected_value = nullptr; +static gboolean expected_handled = FALSE; + +static FlValue* echo_response_cb(FlValue* echoed_value) { + gchar* text = fl_value_to_string(echoed_value); + printf("echo 1 %s\n", expected_value);fflush(stdout); + EXPECT_STREQ(text, expected_value); + printf("echo 2 %s\n", expected_value);fflush(stdout); + + FlValue* value = fl_value_new_map(); + fl_value_set_string_take(value, "handled", fl_value_new_bool(expected_handled)); + printf("newvalue %s\n", fl_value_to_string(value)); + return value; +} + +static void responder_callback(bool handled, gpointer user_data) { + EXPECT_EQ(handled, expected_handled); + g_main_loop_quit(static_cast(user_data)); +} + +// Test sending a letter "A"; +TEST(FlKeyChannelResponderTest, SendKeyEvent) { + g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); + + g_autoptr(FlEngine) engine = make_mock_engine(); + g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine); + FlKeyChannelResponderMock mock{ + .value_converter = echo_response_cb, + .channel_name = "test/echo", + }; + g_autoptr(FlKeyResponder) responder = FL_KEY_RESPONDER(fl_key_channel_responder_new( + messenger, &mock)); + + char string[] = "A"; + GdkEventKey key_event = GdkEventKey{ + GDK_KEY_PRESS, // event type + nullptr, // window (not needed) + FALSE, // event was sent explicitly + 12345, // time + 0x0, // modifier state + GDK_KEY_A, // key code + 1, // length of string representation + reinterpret_cast(&string[0]), // string representation + 0x04, // scan code + 0, // keyboard group + 0, // is a modifier + }; + + // printf("Test 1 %s\n", expected_value);fflush(stdout); + fl_key_responder_handle_event(responder, &key_event, responder_callback, loop); + // printf("Test 2 %s\n", expected_value);fflush(stdout); + expected_value = + "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, keyCode: 65, " + "modifiers: 0, unicodeScalarValues: 65}"; + expected_handled = FALSE; + + // Blocks here until echo_response_cb is called. + g_main_loop_run(loop); + + key_event = GdkEventKey{ + GDK_KEY_RELEASE, // event type + nullptr, // window (not needed) + FALSE, // event was sent explicitly + 23456, // time + 0x0, // modifier state + GDK_KEY_A, // key code + 1, // length of string representation + reinterpret_cast(&string[0]), // string representation + 0x04, // scan code + 0, // keyboard group + 0, // is a modifier + }; + + fl_key_responder_handle_event(responder, &key_event, responder_callback, loop); + expected_value = + "{type: keyup, keymap: linux, scanCode: 4, toolkit: gtk, keyCode: 65, " + "modifiers: 0, unicodeScalarValues: 65}"; + expected_handled = FALSE; + + // Blocks here until echo_response_cb is called. + g_main_loop_run(loop); +} + +// void test_lock_event(guint key_code, +// const char* down_expected, +// const char* up_expected) { +// g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); + +// FlBinaryMessenger* messenger = fl_binary_messenger_new(engine); +// g_autoptr(FlKeyChannelResponder) responder = fl_key_channel_responder_new( +// messenger, text_input_plugin, echo_response_cb, "test/echo"); + +// GdkEventKey key_event = GdkEventKey{ +// GDK_KEY_PRESS, // event type +// nullptr, // window (not needed) +// FALSE, // event was sent explicitly +// 12345, // time +// 0x10, // modifier state +// key_code, // key code +// 1, // length of string representation +// nullptr, // string representation +// 0x04, // scan code +// 0, // keyboard group +// 0, // is a modifier +// }; + +// expected_value = down_expected; +// expected_handled = FALSE; +// bool handled = fl_key_responder_handle_event(responder, &key_event, loop); +// EXPECT_TRUE(handled); + +// // Blocks here until echo_response_cb is called. +// g_main_loop_run(loop); + +// key_event.type = GDK_KEY_RELEASE; +// key_event.time++; + +// expected_value = up_expected; +// expected_handled = FALSE; +// fl_key_responder_handle_event(responder, &key_event, loop); + +// // Blocks here until echo_response_cb is called. +// g_main_loop_run(loop); +// } + +// // Test sending a "NumLock" keypress. +// TEST(FlKeyChannelResponderTest, SendNumLockKeyEvent) { +// test_lock_event(GDK_KEY_Num_Lock, +// "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, " +// "keyCode: 65407, modifiers: 16}", +// "{type: keyup, keymap: linux, scanCode: 4, toolkit: gtk, " +// "keyCode: 65407, modifiers: 0}"); +// } + +// // Test sending a "CapsLock" keypress. +// TEST(FlKeyChannelResponderTest, SendCapsLockKeyEvent) { +// test_lock_event(GDK_KEY_Caps_Lock, +// "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, " +// "keyCode: 65509, modifiers: 2}", +// "{type: keyup, keymap: linux, scanCode: 4, toolkit: gtk, " +// "keyCode: 65509, modifiers: 0}"); +// } + +// // Test sending a "ShiftLock" keypress. +// TEST(FlKeyChannelResponderTest, SendShiftLockKeyEvent) { +// test_lock_event(GDK_KEY_Shift_Lock, +// "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, " +// "keyCode: 65510, modifiers: 2}", +// "{type: keyup, keymap: linux, scanCode: 4, toolkit: gtk, " +// "keyCode: 65510, modifiers: 0}"); +// } + +// TEST(FlKeyChannelResponderTest, TestKeyEventHandledByFramework) { +// g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); + +// FlBinaryMessenger* messenger = fl_binary_messenger_new(engine); +// g_autoptr(FlKeyChannelResponder) responder = fl_key_channel_responder_new( +// messenger, text_input_plugin, echo_response_cb, "test/key-event-handled"); + +// GdkEventKey key_event = GdkEventKey{ +// GDK_KEY_PRESS, // event type +// nullptr, // window (not needed) +// FALSE, // event was sent explicitly +// 12345, // time +// 0x10, // modifier state +// GDK_KEY_A, // key code +// 1, // length of string representation +// nullptr, // string representation +// 0x04, // scan code +// 0, // keyboard group +// 0, // is a modifier +// }; + +// expected_value = "{handled: true}"; +// expected_handled = TRUE; +// bool handled = fl_key_responder_handle_event(responder, &key_event, loop); +// // Should always be true, because the event was delayed. +// EXPECT_TRUE(handled); + +// // Blocks here until echo_response_cb is called. +// g_main_loop_run(loop); +// } From b2a63fb1c7fb979862ab41c95ba783f3c907dc73 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Wed, 7 Apr 2021 06:00:04 -0700 Subject: [PATCH 017/126] Fix other tests --- .../linux/fl_key_channel_responder.cc | 102 ------------------ .../linux/fl_key_channel_responder_test.cc | 10 +- shell/platform/linux/fl_message_codec_test.cc | 4 + 3 files changed, 5 insertions(+), 111 deletions(-) diff --git a/shell/platform/linux/fl_key_channel_responder.cc b/shell/platform/linux/fl_key_channel_responder.cc index e03082d1e0913..e3a082edbdc06 100644 --- a/shell/platform/linux/fl_key_channel_responder.cc +++ b/shell/platform/linux/fl_key_channel_responder.cc @@ -25,15 +25,12 @@ static constexpr char kUnicodeScalarValuesKey[] = "unicodeScalarValues"; static constexpr char kGtkToolkit[] = "gtk"; static constexpr char kLinuxKeymap[] = "linux"; -static constexpr uint64_t kMaxPendingEvents = 1000; - // Definition of the FlKeyChannelResponder GObject class. struct _FlKeyChannelResponder { GObject parent_instance; FlBasicMessageChannel* channel; - GPtrArray* pending_events; uint64_t last_id; FlKeyChannelResponderMock* mock; @@ -59,58 +56,6 @@ static void fl_key_channel_responder_iface_init( iface->handle_event = fl_key_channel_responder_handle_event; } -// Declare and define a private pair object to bind the id and the event -// together. - -G_DECLARE_FINAL_TYPE(FlKeyEventPair, - fl_key_event_pair, - FL, - KEY_EVENT_PAIR, - GObject); - -struct _FlKeyEventPair { - GObject parent_instance; - - uint64_t id; - GdkEventKey* event; -}; - -G_DEFINE_TYPE(FlKeyEventPair, fl_key_event_pair, G_TYPE_OBJECT) - -// Dispose method for FlKeyEventPair. -static void fl_key_event_pair_dispose(GObject* object) { - // Redundant, but added so that we don't get a warning about unused function - // for FL_IS_KEY_EVENT_PAIR. - g_return_if_fail(FL_IS_KEY_EVENT_PAIR(object)); - - FlKeyEventPair* self = FL_KEY_EVENT_PAIR(object); - g_clear_pointer(&self->event, gdk_event_free); - G_OBJECT_CLASS(fl_key_event_pair_parent_class)->dispose(object); -} - -// Class Initialization method for FlKeyEventPair class. -static void fl_key_event_pair_class_init(FlKeyEventPairClass* klass) { - G_OBJECT_CLASS(klass)->dispose = fl_key_event_pair_dispose; -} - -// Initialization for FlKeyEventPair instances. -static void fl_key_event_pair_init(FlKeyEventPair* self) {} - -// Creates a new FlKeyEventPair instance, given a unique ID, and an event struct -// to keep. -FlKeyEventPair* fl_key_event_pair_new(uint64_t id, GdkEventKey* event) { - FlKeyEventPair* self = - FL_KEY_EVENT_PAIR(g_object_new(fl_key_event_pair_get_type(), nullptr)); - - // Copy the event to preserve refcounts for referenced values (mainly the - // window). - GdkEventKey* event_copy = reinterpret_cast( - gdk_event_copy(reinterpret_cast(event))); - self->id = id; - self->event = event_copy; - return self; -} - // Declare and define a private class to hold response data from the framework. G_DECLARE_FINAL_TYPE(FlKeyEventResponseData, fl_key_event_response_data, @@ -173,48 +118,6 @@ FlKeyEventResponseData* fl_key_event_response_data_new( return self; } -// Finds an event in the event queue that was sent to the framework by its ID. -GdkEventKey* fl_key_channel_responder_find_pending_event( - FlKeyChannelResponder* self, - uint64_t id) { - for (guint i = 0; i < self->pending_events->len; ++i) { - if (FL_KEY_EVENT_PAIR(g_ptr_array_index(self->pending_events, i))->id == - id) { - return FL_KEY_EVENT_PAIR(g_ptr_array_index(self->pending_events, i)) - ->event; - } - } - return nullptr; -} - -// Removes an event from the pending event queue. -static void remove_pending_event(FlKeyChannelResponder* self, uint64_t id) { - for (guint i = 0; i < self->pending_events->len; ++i) { - if (FL_KEY_EVENT_PAIR(g_ptr_array_index(self->pending_events, i))->id == - id) { - g_ptr_array_remove_index(self->pending_events, i); - return; - } - } - g_warning("Tried to remove pending event with id %" PRIu64 - ", but the event was not found.", - id); -} - -// Adds an GdkEventKey to the pending event queue, with a unique ID, and the -// responder that added it. -static void add_pending_event(FlKeyChannelResponder* self, - uint64_t id, - GdkEventKey* event) { - if (self->pending_events->len > kMaxPendingEvents) { - g_warning( - "There are %d keyboard events that have not yet received a " - "response from the framework. Are responses being sent?", - self->pending_events->len); - } - g_ptr_array_add(self->pending_events, fl_key_event_pair_new(id, event)); -} - // Handles a response from the framework to a key event sent to the framework // earlier. static void handle_response(GObject* object, @@ -244,7 +147,6 @@ static void handle_response(GObject* object, g_autoptr(FlValue) handled_value = fl_value_lookup_string(message, "handled"); bool handled = fl_value_get_bool(handled_value); - remove_pending_event(self, data->id); data->callback(handled, data->user_data); } @@ -253,7 +155,6 @@ static void fl_key_channel_responder_dispose(GObject* object) { FlKeyChannelResponder* self = FL_KEY_CHANNEL_RESPONDER(object); g_clear_object(&self->channel); - g_ptr_array_free(self->pending_events, TRUE); G_OBJECT_CLASS(fl_key_channel_responder_parent_class)->dispose(object); } @@ -287,7 +188,6 @@ FlKeyChannelResponder* fl_key_channel_responder_new( self->channel = fl_basic_message_channel_new(messenger, channel_name, FL_MESSAGE_CODEC(codec)); - self->pending_events = g_ptr_array_new_with_free_func(g_object_unref); return self; } @@ -381,8 +281,6 @@ static void fl_key_channel_responder_handle_event( fl_value_new_int(unicodeScalarValues)); } - // Track the event as pending a response from the framework. - add_pending_event(self, id, event); FlKeyEventResponseData* data = fl_key_event_response_data_new(self, id, callback, user_data); // Send the message off to the framework for handling (or not). diff --git a/shell/platform/linux/fl_key_channel_responder_test.cc b/shell/platform/linux/fl_key_channel_responder_test.cc index 355c078522ebb..4498c240c4e06 100644 --- a/shell/platform/linux/fl_key_channel_responder_test.cc +++ b/shell/platform/linux/fl_key_channel_responder_test.cc @@ -10,24 +10,16 @@ #include "flutter/shell/platform/linux/fl_binary_messenger_private.h" #include "flutter/shell/platform/linux/testing/fl_test.h" -// namespace { -// struct EchoResponseData { -// GMainLoop* loop; -// } -// } - static const char* expected_value = nullptr; static gboolean expected_handled = FALSE; static FlValue* echo_response_cb(FlValue* echoed_value) { gchar* text = fl_value_to_string(echoed_value); - printf("echo 1 %s\n", expected_value);fflush(stdout); EXPECT_STREQ(text, expected_value); - printf("echo 2 %s\n", expected_value);fflush(stdout); + g_free(text); FlValue* value = fl_value_new_map(); fl_value_set_string_take(value, "handled", fl_value_new_bool(expected_handled)); - printf("newvalue %s\n", fl_value_to_string(value)); return value; } diff --git a/shell/platform/linux/fl_message_codec_test.cc b/shell/platform/linux/fl_message_codec_test.cc index c2555ae9182ef..69390803354ac 100644 --- a/shell/platform/linux/fl_message_codec_test.cc +++ b/shell/platform/linux/fl_message_codec_test.cc @@ -67,12 +67,16 @@ static FlTestCodec* fl_test_codec_new() { } TEST(FlMessageCodecTest, EncodeMessage) { + printf("T0\n"); g_autoptr(FlTestCodec) codec = fl_test_codec_new(); + printf("T1\n"); g_autoptr(FlValue) value = fl_value_new_int(1); g_autoptr(GError) error = nullptr; + printf("T2\n"); g_autoptr(GBytes) message = fl_message_codec_encode_message(FL_MESSAGE_CODEC(codec), value, &error); + printf("T3\n"); EXPECT_NE(message, nullptr); EXPECT_EQ(error, nullptr); EXPECT_EQ(g_bytes_get_size(message), static_cast(1)); From 421b32473cb623edd0a3404886c56de3fb6848d5 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Thu, 8 Apr 2021 16:00:53 -0700 Subject: [PATCH 018/126] WIP embedder --- shell/platform/linux/BUILD.gn | 2 + shell/platform/linux/fl_engine.cc | 13 + shell/platform/linux/fl_engine_private.h | 6 + .../linux/fl_key_channel_responder.cc | 11 +- .../platform/linux/fl_key_channel_responder.h | 6 +- .../linux/fl_key_embedder_responder.cc | 309 +++++++++++++ .../linux/fl_key_embedder_responder.h | 57 +++ shell/platform/linux/key_mapping.cc | 412 ++++++++++++++++++ shell/platform/linux/key_mapping.h | 18 + 9 files changed, 822 insertions(+), 12 deletions(-) create mode 100644 shell/platform/linux/fl_key_embedder_responder.cc create mode 100644 shell/platform/linux/fl_key_embedder_responder.h create mode 100644 shell/platform/linux/key_mapping.cc create mode 100644 shell/platform/linux/key_mapping.h diff --git a/shell/platform/linux/BUILD.gn b/shell/platform/linux/BUILD.gn index 77e66e5250eb4..e15ee1443b4b4 100644 --- a/shell/platform/linux/BUILD.gn +++ b/shell/platform/linux/BUILD.gn @@ -82,6 +82,7 @@ source_set("flutter_linux_sources") { "fl_method_codec_private.h", "fl_plugin_registrar_private.h", "fl_standard_message_codec_private.h", + "key_mapping.h", ] configs += [ "//flutter/shell/platform/linux/config:gtk" ] @@ -122,6 +123,7 @@ source_set("flutter_linux_sources") { "fl_value.cc", "fl_view.cc", "fl_view_accessible.cc", + "key_mapping.cc", ] # Set flag to stop headers being directly included (library users should not do this) diff --git a/shell/platform/linux/fl_engine.cc b/shell/platform/linux/fl_engine.cc index 2212b68ed6489..0a35efacb4a53 100644 --- a/shell/platform/linux/fl_engine.cc +++ b/shell/platform/linux/fl_engine.cc @@ -696,6 +696,19 @@ void fl_engine_send_mouse_pointer_event(FlEngine* self, self->embedder_api.SendPointerEvent(self->engine, &fl_event, 1); } +void fl_engine_send_key_event(FlEngine* engine, + const FlutterKeyEvent* event, + FlutterKeyEventCallback callback, + void* user_data) { + g_return_if_fail(FL_IS_ENGINE(self)); + + if (self->engine == nullptr) { + return; + } + + self->embedder_api.SendKeyEvent(self->engine, fl_event, callback, user_data); +} + void fl_engine_dispatch_semantics_action(FlEngine* self, uint64_t id, FlutterSemanticsAction action, diff --git a/shell/platform/linux/fl_engine_private.h b/shell/platform/linux/fl_engine_private.h index 23f186921fca6..27d5fd29ead6f 100644 --- a/shell/platform/linux/fl_engine_private.h +++ b/shell/platform/linux/fl_engine_private.h @@ -162,6 +162,12 @@ void fl_engine_send_mouse_pointer_event(FlEngine* engine, double scroll_delta_y, int64_t buttons); +void fl_engine_send_key_event(FlEngine* engine, + const FlutterKeyEvent* event, + FlutterKeyEventCallback callback, + void* user_data); + + /** * fl_engine_dispatch_semantics_action: * @engine: an #FlEngine. diff --git a/shell/platform/linux/fl_key_channel_responder.cc b/shell/platform/linux/fl_key_channel_responder.cc index e3a082edbdc06..ec3e4a81c9b39 100644 --- a/shell/platform/linux/fl_key_channel_responder.cc +++ b/shell/platform/linux/fl_key_channel_responder.cc @@ -31,7 +31,6 @@ struct _FlKeyChannelResponder { GObject parent_instance; FlBasicMessageChannel* channel; - uint64_t last_id; FlKeyChannelResponderMock* mock; }; @@ -67,7 +66,6 @@ struct _FlKeyEventResponseData { GObject parent_instance; FlKeyChannelResponder* responder; - uint64_t id; FlKeyResponderAsyncCallback callback; gpointer user_data; }; @@ -99,9 +97,8 @@ static void fl_key_event_response_data_init(FlKeyEventResponseData* self) {} // Creates a new FlKeyEventResponseData private class with a responder that // created the request, a unique ID for tracking, and optional user data. Will // keep a weak pointer to the responder. -FlKeyEventResponseData* fl_key_event_response_data_new( +static FlKeyEventResponseData* fl_key_event_response_data_new( FlKeyChannelResponder* responder, - uint64_t id, FlKeyResponderAsyncCallback callback, gpointer user_data) { FlKeyEventResponseData* self = FL_KEY_EVENT_RESPONSE_DATA( @@ -112,7 +109,6 @@ FlKeyEventResponseData* fl_key_event_response_data_new( // while the framework was responding. g_object_add_weak_pointer(G_OBJECT(responder), reinterpret_cast(&(self->responder))); - self->id = id; self->callback = callback; self->user_data = user_data; return self; @@ -180,7 +176,6 @@ FlKeyChannelResponder* fl_key_channel_responder_new( FlKeyChannelResponder* self = FL_KEY_CHANNEL_RESPONDER( g_object_new(fl_key_channel_responder_get_type(), nullptr)); - self->last_id = 1; self->mock = mock; g_autoptr(FlJsonMessageCodec) codec = fl_json_message_codec_new(); @@ -201,8 +196,6 @@ static void fl_key_channel_responder_handle_event( g_return_if_fail(event != nullptr); g_return_if_fail(callback != nullptr); - uint64_t id = (++self->last_id); - const gchar* type; switch (event->type) { case GDK_KEY_PRESS: @@ -282,7 +275,7 @@ static void fl_key_channel_responder_handle_event( } FlKeyEventResponseData* data = - fl_key_event_response_data_new(self, id, callback, user_data); + fl_key_event_response_data_new(self, callback, user_data); // Send the message off to the framework for handling (or not). fl_basic_message_channel_send(self->channel, message, nullptr, handle_response, data); diff --git a/shell/platform/linux/fl_key_channel_responder.h b/shell/platform/linux/fl_key_channel_responder.h index 18d53c78a0f50..fbf5f17c73267 100644 --- a/shell/platform/linux/fl_key_channel_responder.h +++ b/shell/platform/linux/fl_key_channel_responder.h @@ -5,13 +5,13 @@ #ifndef FLUTTER_SHELL_PLATFORM_LINUX_FL_KEY_CHANNEL_RESPONDER_H_ #define FLUTTER_SHELL_PLATFORM_LINUX_FL_KEY_CHANNEL_RESPONDER_H_ +#include + #include "flutter/shell/platform/linux/fl_key_responder.h" #include "flutter/shell/platform/linux/fl_keyboard_manager.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_value.h" -#include - typedef FlValue* (*FlValueConverter)(FlValue*); typedef struct _FlKeyChannelResponderMock { @@ -21,7 +21,7 @@ typedef struct _FlKeyChannelResponderMock { G_BEGIN_DECLS -#define FL_TYPE_KEY_CHANNEL_RESPONDER fl_key_channel_responder_get_type() +#define FL_TYPE_KEY_CHANNEL_RESPONDER fl_key_channel_responder_get_type () G_DECLARE_FINAL_TYPE(FlKeyChannelResponder, fl_key_channel_responder, FL, diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc new file mode 100644 index 0000000000000..04d9b2425e26b --- /dev/null +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -0,0 +1,309 @@ +// 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_key_embedder_responder.h" + +#include +#include + +#include "flutter/shell/platform/linux/key_mapping.h" +#include "flutter/shell/platform/linux/fl_keyboard_manager.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_basic_message_embedder.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_json_message_codec.h" + +struct _FlKeyEmbedderResponder { + GObject parent_instance; + + FlEngine* engine; + + // Stores pressed keys, mapping their Flutter physical key to Flutter logical key. + // + // Both keys and values are directly stored uint64s. + GHashTable* pressing_records; + + // A static map from XKB to Flutter's physical key code + GHashTable* xkb_to_physical_key; + + // A static map from GTK keyval to Flutter's logical key code + GHashTable* keyval_to_logical_key; + + gchar* character_to_free; +}; + +static void fl_key_embedder_responder_iface_init(FlKeyResponderInterface* iface); + +G_DEFINE_TYPE_WITH_CODE( + FlKeyEmbedderResponder, + fl_key_embedder_responder, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE(FL_TYPE_KEY_RESPONDER, + fl_key_embedder_responder_iface_init)) + +static void fl_key_embedder_responder_handle_event( + FlKeyResponder* responder, + GdkEventKey* event, + FlKeyResponderAsyncCallback callback, + gpointer user_data); + +static void fl_key_embedder_responder_iface_init( + FlKeyResponderInterface* iface) { + iface->handle_event = fl_key_embedder_responder_handle_event; +} + +// Declare and define a private class to hold response data from the framework. +G_DECLARE_FINAL_TYPE(FlKeyEventResponseData, + fl_key_event_response_data, + FL, + KEY_EVENT_RESPONSE_DATA, + GObject); + +struct _FlKeyEventResponseData { + GObject parent_instance; + + FlKeyEmbedderResponder* responder; + FlKeyResponderAsyncCallback callback; + gpointer user_data; +}; + +// Definition for FlKeyEventResponseData private class. +G_DEFINE_TYPE(FlKeyEventResponseData, fl_key_event_response_data, G_TYPE_OBJECT) + +// Dispose method for FlKeyEventResponseData private class. +static void fl_key_event_response_data_dispose(GObject* object) { + g_return_if_fail(FL_IS_KEY_EVENT_RESPONSE_DATA(object)); + FlKeyEventResponseData* self = FL_KEY_EVENT_RESPONSE_DATA(object); + if (self->responder != nullptr) { + g_object_remove_weak_pointer( + G_OBJECT(self->responder), + reinterpret_cast(&(self->responder))); + self->responder = nullptr; + } +} + +// Class initialization method for FlKeyEventResponseData private class. +static void fl_key_event_response_data_class_init( + FlKeyEventResponseDataClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_key_event_response_data_dispose; +} + +// Instance initialization method for FlKeyEventResponseData private class. +static void fl_key_event_response_data_init(FlKeyEventResponseData* self) {} + +// Creates a new FlKeyEventResponseData private class with a responder that +// created the request, a unique ID for tracking, and optional user data. Will +// keep a weak pointer to the responder. +static FlKeyEventResponseData* fl_key_event_response_data_new( + FlKeyEmbedderResponder* responder, + FlKeyResponderAsyncCallback callback, + gpointer user_data) { + FlKeyEventResponseData* self = FL_KEY_EVENT_RESPONSE_DATA( + g_object_new(fl_key_event_response_data_get_type(), nullptr)); + + self->responder = responder; + // Add a weak pointer so we can know if the key event responder disappeared + // while the framework was responding. + g_object_add_weak_pointer(G_OBJECT(responder), + reinterpret_cast(&(self->responder))); + self->id = id; + self->callback = callback; + self->user_data = user_data; + return self; +} + +// Disposes of an FlKeyEmbedderResponder instance. +static void fl_key_embedder_responder_dispose(GObject* object) { + FlKeyEmbedderResponder* self = FL_KEY_EMBEDDER_RESPONDER(object); + + g_clear_pointer(&self->pressing_records, g_hash_table_unref); + g_clear_pointer(&self->xkb_to_physical_key, g_hash_table_unref); + g_clear_pointer(&self->keyval_to_logical_key, g_hash_table_unref); + if (self->character_to_free != nullptr) { + g_free(self->character_to_free); + } + + G_OBJECT_CLASS(fl_key_embedder_responder_parent_class)->dispose(object); +} + +// Initializes the FlKeyEmbedderResponder class methods. +static void fl_key_embedder_responder_class_init( + FlKeyEmbedderResponderClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_key_embedder_responder_dispose; +} + +// Initializes an FlKeyEmbedderResponder instance. +static void fl_key_embedder_responder_init(FlKeyEmbedderResponder* self) {} + +// Creates a new FlKeyEmbedderResponder instance, with a messenger used to send +// messages to the framework, an FlTextInputPlugin used to handle key events +// that the framework doesn't handle. Mainly for testing purposes, it also takes +// an optional callback to call when a response is received, and an optional +// embedder name to use when sending messages. +FlKeyEmbedderResponder* fl_key_embedder_responder_new( + FlEngine* engine) { + g_return_val_if_fail(FL_IS_ENGINE(engine), nullptr); + + FlKeyEmbedderResponder* self = FL_KEY_EMBEDDER_RESPONDER( + g_object_new(fl_key_embedder_responder_get_type(), nullptr)); + + self->engine = engine; + // Add a weak pointer so we can know if the key event responder disappeared + // while the framework was responding. + g_object_add_weak_pointer(G_OBJECT(engine), + reinterpret_cast(&(self->engine))); + + self->pressing_records = g_hash_table_new(g_direct_hash, g_direct_equal); + self->xkb_to_physical_key = g_hash_table_new(g_direct_hash, g_direct_equal); + initialize_xkb_to_physical_key(self->xkb_to_physical_key); + self->keyval_to_logical_key = g_hash_table_new(g_direct_hash, g_direct_equal); + initialize_gtk_keyval_to_logical_key(self->keyval_to_logical_key); + self->character_to_free = nullptr; + + return self; +} + +static uint64_t event_to_physical_key(const GdkEventKey* event, GHashTable* table) { + gpointer record = g_hash_table_lookup(table, GUINT_TO_POINTER(event->hardware_keycode)); + if (record != nullptr) { + return GPOINTER_TO_UINT(record); + } + // Auto-generate key + return kAutogeneratedMask | kLinuxKeyIdPlane | event->hardware_keycode; +} + +static uint64_t event_to_logical_key(const GdkEventKey* event, GHashTable* table) { + guint keyval = event->keyval; + gpointer record = g_hash_table_lookup(table, GUINT_TO_POINTER(keyval)); + if (record != nullptr) { + return GPOINTER_TO_UINT(record); + } + // ASCII // TODO + if (keyval < 256) { + return keyval; + } + // Auto-generate key + return kAutogeneratedMask | kLinuxKeyIdPlane | keyval; +} + +static uint64_t event_to_timestamp(const GdkEventKey* event) { + return kMicrosecondsPerMillisecond * (double)event->time; +} + +// Returns a newly accocated UTF-8 string from event->keyval that must be +// freed later with g_free(). +static char* event_to_character(const GdkEventKey* event) { + gunichar unicodeChar = gdk_keyval_to_unicode(event->keyval); + glong items_written; + gchar* result = g_ucs4_to_utf8(&unicodeChar, 1, NULL, &items_written, NULL); + if (items_written == 0) { + if (result != NULL) + g_free(result); + return nullptr; + } + return result; +} + +static uint64_t gpointerToUint64(gpointer pointer) { + return pointer == nullptr ? 0 : reinterpret_cast(pointer); +} + +static gpointer uint64ToGpointer(uint64_t number) { + return reinterpret_cast(number); +} + +// Return the logical key corresponding to the physical key. +// +// Returns 0 if not found. +static uint64_t pressed_logical_for_physical(GHashTable* pressing_records, uint64_t physical) { + return gpointerToUint64(g_hash_table_lookup(pressing_records, uint64ToGpointer(physical))); +} + +static size_t fl_keyboard_manager_convert_key_event(FlKeyboardManager* self, + const GdkEventKey* event, + FlKeyDatum* results) { +} + +// Handles a response from the framework to a key event sent to the framework +// earlier. +static void handle_response(bool handled, + gpointer user_data) { + g_autoptr(FlKeyEventResponseData) data = + FL_KEY_EVENT_RESPONSE_DATA(user_data); + + // Return if the weak pointer has been destroyed. + if (data->responder == nullptr) { + return; + } + + // Return if callback is not requested (happens for synthesized events). + if (data->callback == nullptr) { + return; + } + + data->callback(handled, data->user_data); +} + +// Sends a key event to the framework. +static void fl_key_embedder_responder_handle_event( + FlKeyResponder* responder, + GdkEventKey* event, + FlKeyResponderAsyncCallback callback, + gpointer user_data) { + FlKeyEmbedderResponder* self = FL_KEY_EMBEDDER_RESPONDER(responder); + g_return_if_fail(event != nullptr); + g_return_if_fail(callback != nullptr); + + printf("===START=== state %d\n", event->state); + if (self->character_to_free != nullptr) { + g_free(self->character_to_free); + self->character_to_free = nullptr; + } + uint64_t physical_key = event_to_physical_key(event, self->xkb_to_physical_key); + uint64_t logical_key = event_to_logical_key(event, self->keyval_to_logical_key); + bool is_physical_down = event->type == GDK_KEY_PRESS; + + uint64_t last_logical_record = pressed_logical_for_physical(self->pressing_records, physical_key); + uint64_t next_logical_record = is_physical_down ? last_logical_record : 0; + + char* character_to_free = nullptr; + + printf("last %lu next %lu down %d type %d\n", last_logical_record, next_logical_record, is_physical_down, event->type); + fflush(stdout); + + FlutterKeyEvent event; + event->struct_size = sizeof(event); + event->type = kFlutterKeyEventTypeDown; + event->physical = physical_key; + event->logical = physical_key; + event->character = character_to_free; + event->synthesized = false; + + base_event->timestamp = event_to_timestamp(event); + base_event->synthesized = false; + + if (is_physical_down) { + character_to_free = event_to_character(event); // Might be null + base_event->character = character_to_free; + + if (last_logical_record) { + // GTK doesn't report repeat events separatedly, therefore we can't + // distinguish a repeat event from a down event after a missed up event. + base_event->kind = kFlKeyDataKindRepeat; + base_event->logical = last_logical_record; + } else { + base_event->kind = kFlKeyDataKindDown; + base_event->logical = logical_key; + } + } else { // is_physical_down false + base_event->character = nullptr; + base_event->kind = kFlKeyDataKindUp; + base_event->logical = logical_key; + } + + FlKeyEventResponseData* response_data = fl_key_event_response_data_new( + self, callback, user_data); + + fl_engine_send_key_event(self->engine, &event, handle_response, response_data); + + return 1; +} diff --git a/shell/platform/linux/fl_key_embedder_responder.h b/shell/platform/linux/fl_key_embedder_responder.h new file mode 100644 index 0000000000000..296c845b9a760 --- /dev/null +++ b/shell/platform/linux/fl_key_embedder_responder.h @@ -0,0 +1,57 @@ +// 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_KEY_EMBEDDER_RESPONDER_H_ +#define FLUTTER_SHELL_PLATFORM_LINUX_FL_KEY_EMBEDDER_RESPONDER_H_ + +#include + +#include "flutter/shell/platform/linux/fl_key_responder.h" +#include "flutter/shell/platform/linux/fl_keyboard_manager.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_value.h" + +constexpr int kMaxConvertedKeyData = 3; + +G_BEGIN_DECLS + +#define FL_TYPE_KEY_EMBEDDER_RESPONDER fl_key_embedder_responder_get_type () +G_DECLARE_FINAL_TYPE(FlKeyEmbedderResponder, + fl_key_embedder_responder, + FL, + KEY_EMBEDDER_RESPONDER, + GObject); + +/** + * FlKeyEmbedderResponder: + * + * #FlKeyEmbedderResponder is a plugin that implements the shell side + * of SystemEmbedders.keyEvent from the Flutter services library. + */ + +/** + * fl_key_embedder_responder_new: + * @messenger: an #FlBinaryMessenger. + * @response_callback: the callback to call when a response is received. If not + * given (nullptr), then the default response callback is + * used. Typically used for tests to receive event + * information. If specified, unhandled events will not be + * re-dispatched. + * @text_input_plugin: The #FlTextInputPlugin to send key events to if the + * framework doesn't handle them. + * @embedder_name: the name of the embedder to send key events to the framework + * on. If not given (nullptr), then the standard key event + * embedder name is used. Typically used for tests to send on a + * test embedder. + * + * Creates a new plugin that implements SystemEmbedders.keyEvent from the + * Flutter services library. + * + * Returns: a new #FlKeyEmbedderResponder. + */ +FlKeyEmbedderResponder* fl_key_embedder_responder_new(FlEngine* engine); + +G_END_DECLS + +#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_KEY_EMBEDDER_RESPONDER_H_ diff --git a/shell/platform/linux/key_mapping.cc b/shell/platform/linux/key_mapping.cc new file mode 100644 index 0000000000000..60d4e76f59246 --- /dev/null +++ b/shell/platform/linux/key_mapping.cc @@ -0,0 +1,412 @@ +// Copyright 2014 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 +#include + +// DO NOT EDIT -- DO NOT EDIT -- DO NOT EDIT +// This file is generated by flutter/flutter@dev/tools/gen_keycodes/bin/gen_keycodes.dart and +// should not be edited directly. +// +// Edit the template dev/tools/gen_keycodes/data/gtk_keyboard_map_cc.tmpl instead. +// See dev/tools/gen_keycodes/README.md for more information. + +// Insert a new entry into a hashtable from uint64 to uint64. +// +// Returns whether the newly added value was already in the hash table or not. +static bool insert_record(GHashTable* table, guint64 xkb, guint64 fl_key) { + return g_hash_table_insert(table, GUINT_TO_POINTER(xkb), GUINT_TO_POINTER(fl_key)); +} + +void initialize_xkb_to_physical_key(GHashTable* table) { + insert_record(table, 0x00000281, 0x00000017); // privacyScreenToggle + insert_record(table, 0x00000096, 0x00010082); // sleep + insert_record(table, 0x00000097, 0x00010083); // wakeUp + insert_record(table, 0x000000eb, 0x000100b5); // displayToggleIntExt + insert_record(table, 0x00000026, 0x00070004); // keyA + insert_record(table, 0x00000038, 0x00070005); // keyB + insert_record(table, 0x00000036, 0x00070006); // keyC + insert_record(table, 0x00000028, 0x00070007); // keyD + insert_record(table, 0x0000001a, 0x00070008); // keyE + insert_record(table, 0x00000029, 0x00070009); // keyF + insert_record(table, 0x0000002a, 0x0007000a); // keyG + insert_record(table, 0x0000002b, 0x0007000b); // keyH + insert_record(table, 0x0000001f, 0x0007000c); // keyI + insert_record(table, 0x0000002c, 0x0007000d); // keyJ + insert_record(table, 0x0000002d, 0x0007000e); // keyK + insert_record(table, 0x0000002e, 0x0007000f); // keyL + insert_record(table, 0x0000003a, 0x00070010); // keyM + insert_record(table, 0x00000039, 0x00070011); // keyN + insert_record(table, 0x00000020, 0x00070012); // keyO + insert_record(table, 0x00000021, 0x00070013); // keyP + insert_record(table, 0x00000018, 0x00070014); // keyQ + insert_record(table, 0x0000001b, 0x00070015); // keyR + insert_record(table, 0x00000027, 0x00070016); // keyS + insert_record(table, 0x0000001c, 0x00070017); // keyT + insert_record(table, 0x0000001e, 0x00070018); // keyU + insert_record(table, 0x00000037, 0x00070019); // keyV + insert_record(table, 0x00000019, 0x0007001a); // keyW + insert_record(table, 0x00000035, 0x0007001b); // keyX + insert_record(table, 0x0000001d, 0x0007001c); // keyY + insert_record(table, 0x00000034, 0x0007001d); // keyZ + insert_record(table, 0x0000000a, 0x0007001e); // digit1 + insert_record(table, 0x0000000b, 0x0007001f); // digit2 + insert_record(table, 0x0000000c, 0x00070020); // digit3 + insert_record(table, 0x0000000d, 0x00070021); // digit4 + insert_record(table, 0x0000000e, 0x00070022); // digit5 + insert_record(table, 0x0000000f, 0x00070023); // digit6 + insert_record(table, 0x00000010, 0x00070024); // digit7 + insert_record(table, 0x00000011, 0x00070025); // digit8 + insert_record(table, 0x00000012, 0x00070026); // digit9 + insert_record(table, 0x00000013, 0x00070027); // digit0 + insert_record(table, 0x00000024, 0x00070028); // enter + insert_record(table, 0x00000009, 0x00070029); // escape + insert_record(table, 0x00000016, 0x0007002a); // backspace + insert_record(table, 0x00000017, 0x0007002b); // tab + insert_record(table, 0x00000041, 0x0007002c); // space + insert_record(table, 0x00000014, 0x0007002d); // minus + insert_record(table, 0x00000015, 0x0007002e); // equal + insert_record(table, 0x00000022, 0x0007002f); // bracketLeft + insert_record(table, 0x00000023, 0x00070030); // bracketRight + insert_record(table, 0x00000033, 0x00070031); // backslash + insert_record(table, 0x0000002f, 0x00070033); // semicolon + insert_record(table, 0x00000030, 0x00070034); // quote + insert_record(table, 0x00000031, 0x00070035); // backquote + insert_record(table, 0x0000003b, 0x00070036); // comma + insert_record(table, 0x0000003c, 0x00070037); // period + insert_record(table, 0x0000003d, 0x00070038); // slash + insert_record(table, 0x00000042, 0x00070039); // capsLock + insert_record(table, 0x00000043, 0x0007003a); // f1 + insert_record(table, 0x00000044, 0x0007003b); // f2 + insert_record(table, 0x00000045, 0x0007003c); // f3 + insert_record(table, 0x00000046, 0x0007003d); // f4 + insert_record(table, 0x00000047, 0x0007003e); // f5 + insert_record(table, 0x00000048, 0x0007003f); // f6 + insert_record(table, 0x00000049, 0x00070040); // f7 + insert_record(table, 0x0000004a, 0x00070041); // f8 + insert_record(table, 0x0000004b, 0x00070042); // f9 + insert_record(table, 0x0000004c, 0x00070043); // f10 + insert_record(table, 0x0000005f, 0x00070044); // f11 + insert_record(table, 0x00000060, 0x00070045); // f12 + insert_record(table, 0x0000006b, 0x00070046); // printScreen + insert_record(table, 0x0000004e, 0x00070047); // scrollLock + insert_record(table, 0x0000007f, 0x00070048); // pause + insert_record(table, 0x00000076, 0x00070049); // insert + insert_record(table, 0x0000006e, 0x0007004a); // home + insert_record(table, 0x00000070, 0x0007004b); // pageUp + insert_record(table, 0x00000077, 0x0007004c); // delete + insert_record(table, 0x00000073, 0x0007004d); // end + insert_record(table, 0x00000075, 0x0007004e); // pageDown + insert_record(table, 0x00000072, 0x0007004f); // arrowRight + insert_record(table, 0x00000071, 0x00070050); // arrowLeft + insert_record(table, 0x00000074, 0x00070051); // arrowDown + insert_record(table, 0x0000006f, 0x00070052); // arrowUp + insert_record(table, 0x0000004d, 0x00070053); // numLock + insert_record(table, 0x0000006a, 0x00070054); // numpadDivide + insert_record(table, 0x0000003f, 0x00070055); // numpadMultiply + insert_record(table, 0x00000052, 0x00070056); // numpadSubtract + insert_record(table, 0x00000056, 0x00070057); // numpadAdd + insert_record(table, 0x00000068, 0x00070058); // numpadEnter + insert_record(table, 0x00000057, 0x00070059); // numpad1 + insert_record(table, 0x00000058, 0x0007005a); // numpad2 + insert_record(table, 0x00000059, 0x0007005b); // numpad3 + insert_record(table, 0x00000053, 0x0007005c); // numpad4 + insert_record(table, 0x00000054, 0x0007005d); // numpad5 + insert_record(table, 0x00000055, 0x0007005e); // numpad6 + insert_record(table, 0x0000004f, 0x0007005f); // numpad7 + insert_record(table, 0x00000050, 0x00070060); // numpad8 + insert_record(table, 0x00000051, 0x00070061); // numpad9 + insert_record(table, 0x0000005a, 0x00070062); // numpad0 + insert_record(table, 0x0000005b, 0x00070063); // numpadDecimal + insert_record(table, 0x0000005e, 0x00070064); // intlBackslash + insert_record(table, 0x00000087, 0x00070065); // contextMenu + insert_record(table, 0x0000007c, 0x00070066); // power + insert_record(table, 0x0000007d, 0x00070067); // numpadEqual + insert_record(table, 0x000000bf, 0x00070068); // f13 + insert_record(table, 0x000000c0, 0x00070069); // f14 + insert_record(table, 0x000000c1, 0x0007006a); // f15 + insert_record(table, 0x000000c2, 0x0007006b); // f16 + insert_record(table, 0x000000c3, 0x0007006c); // f17 + insert_record(table, 0x000000c4, 0x0007006d); // f18 + insert_record(table, 0x000000c5, 0x0007006e); // f19 + insert_record(table, 0x000000c6, 0x0007006f); // f20 + insert_record(table, 0x000000c7, 0x00070070); // f21 + insert_record(table, 0x000000c8, 0x00070071); // f22 + insert_record(table, 0x000000c9, 0x00070072); // f23 + insert_record(table, 0x000000ca, 0x00070073); // f24 + insert_record(table, 0x0000008e, 0x00070074); // open + insert_record(table, 0x00000092, 0x00070075); // help + insert_record(table, 0x0000008c, 0x00070077); // select + insert_record(table, 0x00000089, 0x00070079); // again + insert_record(table, 0x0000008b, 0x0007007a); // undo + insert_record(table, 0x00000091, 0x0007007b); // cut + insert_record(table, 0x0000008d, 0x0007007c); // copy + insert_record(table, 0x0000008f, 0x0007007d); // paste + insert_record(table, 0x00000090, 0x0007007e); // find + insert_record(table, 0x00000079, 0x0007007f); // audioVolumeMute + insert_record(table, 0x0000007b, 0x00070080); // audioVolumeUp + insert_record(table, 0x0000007a, 0x00070081); // audioVolumeDown + insert_record(table, 0x00000081, 0x00070085); // numpadComma + insert_record(table, 0x00000061, 0x00070087); // intlRo + insert_record(table, 0x00000065, 0x00070088); // kanaMode + insert_record(table, 0x00000084, 0x00070089); // intlYen + insert_record(table, 0x00000064, 0x0007008a); // convert + insert_record(table, 0x00000066, 0x0007008b); // nonConvert + insert_record(table, 0x00000082, 0x00070090); // lang1 + insert_record(table, 0x00000083, 0x00070091); // lang2 + insert_record(table, 0x00000062, 0x00070092); // lang3 + insert_record(table, 0x00000063, 0x00070093); // lang4 + insert_record(table, 0x0000005d, 0x00070094); // lang5 + insert_record(table, 0x000000bb, 0x000700b6); // numpadParenLeft + insert_record(table, 0x000000bc, 0x000700b7); // numpadParenRight + insert_record(table, 0x0000007e, 0x000700d7); // numpadSignChange + insert_record(table, 0x00000025, 0x000700e0); // controlLeft + insert_record(table, 0x00000032, 0x000700e1); // shiftLeft + insert_record(table, 0x00000040, 0x000700e2); // altLeft + insert_record(table, 0x00000085, 0x000700e3); // metaLeft + insert_record(table, 0x00000069, 0x000700e4); // controlRight + insert_record(table, 0x0000003e, 0x000700e5); // shiftRight + insert_record(table, 0x0000006c, 0x000700e6); // altRight + insert_record(table, 0x00000086, 0x000700e7); // metaRight + insert_record(table, 0x0000016e, 0x000c0060); // info + insert_record(table, 0x0000017a, 0x000c0061); // closedCaptionToggle + insert_record(table, 0x000000e9, 0x000c006f); // brightnessUp + insert_record(table, 0x000000e8, 0x000c0070); // brightnessDown + insert_record(table, 0x000001b7, 0x000c0072); // brightnessToggle + insert_record(table, 0x00000258, 0x000c0073); // brightnessMinimum + insert_record(table, 0x00000259, 0x000c0074); // brightnessMaximum + insert_record(table, 0x000000fc, 0x000c0075); // brightnessAuto + insert_record(table, 0x000000ee, 0x000c0079); // kbdIllumUp + insert_record(table, 0x000000ed, 0x000c007a); // kbdIllumDown + insert_record(table, 0x0000019d, 0x000c0083); // mediaLast + insert_record(table, 0x000000b1, 0x000c008c); // launchPhone + insert_record(table, 0x00000172, 0x000c008d); // programGuide + insert_record(table, 0x000000b6, 0x000c0094); // exit + insert_record(table, 0x000001a2, 0x000c009c); // channelUp + insert_record(table, 0x000001a3, 0x000c009d); // channelDown + insert_record(table, 0x000000d7, 0x000c00b0); // mediaPlay + insert_record(table, 0x000000d1, 0x000c00b1); // mediaPause + insert_record(table, 0x000000af, 0x000c00b2); // mediaRecord + insert_record(table, 0x000000d8, 0x000c00b3); // mediaFastForward + insert_record(table, 0x000000b0, 0x000c00b4); // mediaRewind + insert_record(table, 0x000000ab, 0x000c00b5); // mediaTrackNext + insert_record(table, 0x000000ad, 0x000c00b6); // mediaTrackPrevious + insert_record(table, 0x000000ae, 0x000c00b7); // mediaStop + insert_record(table, 0x000000a9, 0x000c00b8); // eject + insert_record(table, 0x000000ac, 0x000c00cd); // mediaPlayPause + insert_record(table, 0x0000024e, 0x000c00cf); // speechInputToggle + insert_record(table, 0x000000d9, 0x000c00e5); // bassBoost + insert_record(table, 0x000000b3, 0x000c0183); // mediaSelect + insert_record(table, 0x000001ad, 0x000c0184); // launchWordProcessor + insert_record(table, 0x000001af, 0x000c0186); // launchSpreadsheet + insert_record(table, 0x000000a3, 0x000c018a); // launchMail + insert_record(table, 0x000001b5, 0x000c018d); // launchContacts + insert_record(table, 0x00000195, 0x000c018e); // launchCalendar + insert_record(table, 0x00000094, 0x000c0192); // launchApp2 + insert_record(table, 0x00000098, 0x000c0194); // launchApp1 + insert_record(table, 0x0000009e, 0x000c0196); // launchInternetBrowser + insert_record(table, 0x000001b9, 0x000c019c); // logOff + insert_record(table, 0x000000a0, 0x000c019e); // lockScreen + insert_record(table, 0x0000024b, 0x000c019f); // launchControlPanel + insert_record(table, 0x0000024c, 0x000c01a2); // selectTask + insert_record(table, 0x000000f3, 0x000c01a7); // launchDocuments + insert_record(table, 0x000001b8, 0x000c01ab); // spellCheck + insert_record(table, 0x0000017e, 0x000c01ae); // launchKeyboardLayout + insert_record(table, 0x0000024d, 0x000c01b1); // launchScreenSaver + insert_record(table, 0x0000024f, 0x000c01cb); // launchAssistant + insert_record(table, 0x00000190, 0x000c01b7); // launchAudioBrowser + insert_record(table, 0x000000bd, 0x000c0201); // newKey + insert_record(table, 0x000000d6, 0x000c0203); // close + insert_record(table, 0x000000f2, 0x000c0207); // save + insert_record(table, 0x000000da, 0x000c0208); // print + insert_record(table, 0x000000e1, 0x000c0221); // browserSearch + insert_record(table, 0x000000b4, 0x000c0223); // browserHome + insert_record(table, 0x000000a6, 0x000c0224); // browserBack + insert_record(table, 0x000000a7, 0x000c0225); // browserForward + insert_record(table, 0x00000088, 0x000c0226); // browserStop + insert_record(table, 0x000000b5, 0x000c0227); // browserRefresh + insert_record(table, 0x000000a4, 0x000c022a); // browserFavorites + insert_record(table, 0x000001aa, 0x000c022d); // zoomIn + insert_record(table, 0x000001ab, 0x000c022e); // zoomOut + insert_record(table, 0x0000017c, 0x000c0232); // zoomToggle + insert_record(table, 0x000000be, 0x000c0279); // redo + insert_record(table, 0x000000f0, 0x000c0289); // mailReply + insert_record(table, 0x000000f1, 0x000c028b); // mailForward + insert_record(table, 0x000000ef, 0x000c028c); // mailSend + insert_record(table, 0x00000250, 0x000c029d); // keyboardLayoutSelect + insert_record(table, 0x00000080, 0x000c029f); // showAllWindows +} + +void initialize_gtk_keyval_to_logical_key(GHashTable* table) { + insert_record(table, 0x0000ff08, 0x00000008); // BackSpace + insert_record(table, 0x0000ff09, 0x00000009); // Tab + insert_record(table, 0x0000ff89, 0x00000009); // KP_Tab + insert_record(table, 0x0000fe20, 0x00000009); // ISO_Left_Tab + insert_record(table, 0x0000ff0d, 0x0000000d); // Return + insert_record(table, 0x0000fe34, 0x0000000d); // ISO_Enter + insert_record(table, 0x0000fd1e, 0x0000000d); // 3270_Enter + insert_record(table, 0x0000ff1b, 0x0000001b); // Escape + insert_record(table, 0x0000ff80, 0x00000020); // KP_Space + insert_record(table, 0x0000ffae, 0x0000002e); // KP_Decimal + insert_record(table, 0x0000ffff, 0x0000007f); // Delete + insert_record(table, 0x0000ffe5, 0x00000104); // Caps_Lock + insert_record(table, 0x0000ffed, 0x00000108); // Hyper_L + insert_record(table, 0x0000ffee, 0x00000108); // Hyper_R + insert_record(table, 0x0000ff7f, 0x0000010a); // Num_Lock + insert_record(table, 0x0000ff14, 0x0000010c); // Scroll_Lock + insert_record(table, 0x0000ffeb, 0x0000010e); // Super_L + insert_record(table, 0x0000ffec, 0x0000010e); // Super_R + insert_record(table, 0x0000ff54, 0x00000301); // Down + insert_record(table, 0x0000ff51, 0x00000302); // Left + insert_record(table, 0x0000ff53, 0x00000303); // Right + insert_record(table, 0x0000ff52, 0x00000304); // Up + insert_record(table, 0x0000ff57, 0x00000305); // End + insert_record(table, 0x0000ff50, 0x00000306); // Home + insert_record(table, 0x0000ff56, 0x00000307); // Page_Down + insert_record(table, 0x0000ff55, 0x00000308); // Page_Up + insert_record(table, 0x0000ff0b, 0x00000401); // Clear + insert_record(table, 0x0000fd15, 0x00000402); // 3270_Copy + insert_record(table, 0x1008ff57, 0x00000402); // Copy + insert_record(table, 0x1008ff58, 0x00000404); // Cut + insert_record(table, 0x0000fd06, 0x00000405); // 3270_EraseEOF + insert_record(table, 0x0000fd1b, 0x00000406); // 3270_ExSelect + insert_record(table, 0x0000ff63, 0x00000407); // Insert + insert_record(table, 0x1008ff6d, 0x00000408); // Paste + insert_record(table, 0x0000ff66, 0x00000409); // Redo + insert_record(table, 0x0000ff65, 0x0000040a); // Undo + insert_record(table, 0x0000fd0e, 0x00000503); // 3270_Attn + insert_record(table, 0x0000ff69, 0x00000504); // Cancel + insert_record(table, 0x0000ff67, 0x00000505); // Menu + insert_record(table, 0x0000ff62, 0x00000506); // Execute + insert_record(table, 0x0000ff68, 0x00000507); // Find + insert_record(table, 0x0000ff6a, 0x00000508); // Help + insert_record(table, 0x0000ff13, 0x00000509); // Pause + insert_record(table, 0x0000ff60, 0x0000050c); // Select + insert_record(table, 0x1008ff8b, 0x0000050d); // ZoomIn + insert_record(table, 0x1008ff8c, 0x0000050e); // ZoomOut + insert_record(table, 0x1008ff03, 0x00000601); // MonBrightnessDown + insert_record(table, 0x1008ff02, 0x00000602); // MonBrightnessUp + insert_record(table, 0x1008ff2c, 0x00000604); // Eject + insert_record(table, 0x1008ff61, 0x00000605); // LogOff + insert_record(table, 0x1008ff2a, 0x00000607); // PowerOff + insert_record(table, 0x0000fd1d, 0x00000608); // 3270_PrintScreen + insert_record(table, 0x1008ff10, 0x0000060a); // Standby + insert_record(table, 0x1008ff2b, 0x0000060b); // WakeUp + insert_record(table, 0x0000ff37, 0x00000703); // Codeinput + insert_record(table, 0x0000fe0c, 0x00000707); // ISO_First_Group + insert_record(table, 0x0000fe0e, 0x00000708); // ISO_Last_Group + insert_record(table, 0x0000fe08, 0x00000709); // ISO_Next_Group + insert_record(table, 0x0000fe0a, 0x0000070a); // ISO_Prev_Group + insert_record(table, 0x0000ff7e, 0x0000070b); // Mode_switch + insert_record(table, 0x0000ff3e, 0x0000070e); // PreviousCandidate + insert_record(table, 0x0000ff3c, 0x00000710); // SingleCandidate + insert_record(table, 0x0000ff31, 0x00000711); // Hangul + insert_record(table, 0x0000ff34, 0x00000712); // Hangul_Hanja + insert_record(table, 0x0000ff2f, 0x00000714); // Eisu_Shift + insert_record(table, 0x0000ff29, 0x00000715); // Hankaku + insert_record(table, 0x0000ff25, 0x00000716); // Hiragana + insert_record(table, 0x0000ff27, 0x00000717); // Hiragana_Katakana + insert_record(table, 0x0000ff7e, 0x00000718); // kana_switch + insert_record(table, 0x0000ff21, 0x00000719); // Kanji + insert_record(table, 0x0000ff26, 0x0000071a); // Katakana + insert_record(table, 0x0000ff24, 0x0000071b); // Romaji + insert_record(table, 0x0000ff28, 0x0000071c); // Zenkaku + insert_record(table, 0x0000ff2a, 0x0000071d); // Zenkaku_Hankaku + insert_record(table, 0x0000ff91, 0x00000801); // KP_F1 + insert_record(table, 0x0000ffbe, 0x00000801); // F1 + insert_record(table, 0x0000ff92, 0x00000802); // KP_F2 + insert_record(table, 0x0000ffbf, 0x00000802); // F2 + insert_record(table, 0x0000ff93, 0x00000803); // KP_F3 + insert_record(table, 0x0000ffc0, 0x00000803); // F3 + insert_record(table, 0x0000ff94, 0x00000804); // KP_F4 + insert_record(table, 0x0000ffc1, 0x00000804); // F4 + insert_record(table, 0x0000ffc2, 0x00000805); // F5 + insert_record(table, 0x0000ffc3, 0x00000806); // F6 + insert_record(table, 0x0000ffc4, 0x00000807); // F7 + insert_record(table, 0x0000ffc5, 0x00000808); // F8 + insert_record(table, 0x0000ffc6, 0x00000809); // F9 + insert_record(table, 0x0000ffc7, 0x0000080a); // F10 + insert_record(table, 0x0000ffc8, 0x0000080b); // F11 + insert_record(table, 0x0000ffc9, 0x0000080c); // F12 + insert_record(table, 0x0000ffca, 0x0000080d); // F13 + insert_record(table, 0x0000ffcb, 0x0000080e); // F14 + insert_record(table, 0x0000ffcc, 0x0000080f); // F15 + insert_record(table, 0x0000ffcd, 0x00000810); // F16 + insert_record(table, 0x0000ffce, 0x00000811); // F17 + insert_record(table, 0x0000ffcf, 0x00000812); // F18 + insert_record(table, 0x0000ffd0, 0x00000813); // F19 + insert_record(table, 0x0000ffd1, 0x00000814); // F20 + insert_record(table, 0x0000ffd2, 0x00000815); // F21 + insert_record(table, 0x0000ffd3, 0x00000816); // F22 + insert_record(table, 0x0000ffd4, 0x00000817); // F23 + insert_record(table, 0x0000ffd5, 0x00000818); // F24 + insert_record(table, 0x1008ff56, 0x00000a01); // Close + insert_record(table, 0x1008ff90, 0x00000a02); // MailForward + insert_record(table, 0x1008ff72, 0x00000a03); // Reply + insert_record(table, 0x1008ff7b, 0x00000a04); // Send + insert_record(table, 0x1008ff15, 0x00000a07); // AudioStop + insert_record(table, 0x1008ff17, 0x00000a08); // AudioNext + insert_record(table, 0x1008ff16, 0x00000a09); // AudioPrev + insert_record(table, 0x1008ff68, 0x00000a0a); // New + insert_record(table, 0x1008ff6b, 0x00000a0b); // Open + insert_record(table, 0x0000ff61, 0x00000a0c); // Print + insert_record(table, 0x1008ff77, 0x00000a0d); // Save + insert_record(table, 0x1008ff7c, 0x00000a0e); // Spell + insert_record(table, 0x1008ff11, 0x00000a0f); // AudioLowerVolume + insert_record(table, 0x1008ff13, 0x00000a10); // AudioRaiseVolume + insert_record(table, 0x1008ff12, 0x00000a11); // AudioMute + insert_record(table, 0x1008ff20, 0x00000b02); // Calendar + insert_record(table, 0x1008ff19, 0x00000b03); // Mail + insert_record(table, 0x1008ff2d, 0x00000b07); // ScreenSaver + insert_record(table, 0x1008ff6e, 0x00000b0d); // Phone + insert_record(table, 0x1008ff26, 0x00000c01); // Back + insert_record(table, 0x1008ff30, 0x00000c02); // Favorites + insert_record(table, 0x1008ff27, 0x00000c03); // Forward + insert_record(table, 0x1008ff18, 0x00000c04); // HomePage + insert_record(table, 0x1008ff29, 0x00000c05); // Refresh + insert_record(table, 0x1008ff1b, 0x00000c06); // Search + insert_record(table, 0x1008ff28, 0x00000c07); // Stop + insert_record(table, 0x1008ff97, 0x00000d2c); // AudioForward + insert_record(table, 0x1008ff31, 0x00000d2e); // AudioPause + insert_record(table, 0x0000fd16, 0x00000d2f); // 3270_Play + insert_record(table, 0x1008ff14, 0x00000d2f); // AudioPlay + insert_record(table, 0x1008ff1c, 0x00000d30); // AudioRecord + insert_record(table, 0x1008ff3e, 0x00000d31); // AudioRewind + insert_record(table, 0x1008ffa7, 0x100000014); // Suspend + insert_record(table, 0x1008ff2f, 0x100010082); // Sleep + insert_record(table, 0x0000ff8d, 0x20000000d); // KP_Enter + insert_record(table, 0x0000ffaa, 0x20000002a); // KP_Multiply + insert_record(table, 0x0000ffab, 0x20000002b); // KP_Add + insert_record(table, 0x0000ffad, 0x20000002d); // KP_Subtract + insert_record(table, 0x0000ff9f, 0x20000002e); // KP_Delete + insert_record(table, 0x0000ffaf, 0x20000002f); // KP_Divide + insert_record(table, 0x0000ff9e, 0x200000030); // KP_Insert + insert_record(table, 0x0000ffb0, 0x200000030); // KP_0 + insert_record(table, 0x0000ff9c, 0x200000031); // KP_End + insert_record(table, 0x0000ffb1, 0x200000031); // KP_1 + insert_record(table, 0x0000ff99, 0x200000032); // KP_Down + insert_record(table, 0x0000ffb2, 0x200000032); // KP_2 + insert_record(table, 0x0000ff9b, 0x200000033); // KP_Page_Down + insert_record(table, 0x0000ffb3, 0x200000033); // KP_3 + insert_record(table, 0x0000ff96, 0x200000034); // KP_Left + insert_record(table, 0x0000ffb4, 0x200000034); // KP_4 + insert_record(table, 0x0000ffb5, 0x200000035); // KP_5 + insert_record(table, 0x0000ff98, 0x200000036); // KP_Right + insert_record(table, 0x0000ffb6, 0x200000036); // KP_6 + insert_record(table, 0x0000ff95, 0x200000037); // KP_Home + insert_record(table, 0x0000ffb7, 0x200000037); // KP_7 + insert_record(table, 0x0000ff97, 0x200000038); // KP_Up + insert_record(table, 0x0000ffb8, 0x200000038); // KP_8 + insert_record(table, 0x0000ff9a, 0x200000039); // KP_Page_Up + insert_record(table, 0x0000ffb9, 0x200000039); // KP_9 + insert_record(table, 0x0000ffbd, 0x20000003d); // KP_Equal + insert_record(table, 0x0000ffe9, 0x300000102); // Alt_L + insert_record(table, 0x0000ffe3, 0x300000105); // Control_L + insert_record(table, 0x0000ffe7, 0x300000109); // Meta_L + insert_record(table, 0x0000ffe1, 0x30000010d); // Shift_L + insert_record(table, 0x0000ffea, 0x400000102); // Alt_R + insert_record(table, 0x0000ffe4, 0x400000105); // Control_R + insert_record(table, 0x0000ffe8, 0x400000109); // Meta_R + insert_record(table, 0x0000ffe2, 0x40000010d); // Shift_R +} diff --git a/shell/platform/linux/key_mapping.h b/shell/platform/linux/key_mapping.h new file mode 100644 index 0000000000000..f4cda7b1bc2d7 --- /dev/null +++ b/shell/platform/linux/key_mapping.h @@ -0,0 +1,18 @@ +// 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 KEYBOARD_MAP_H_ +#define KEYBOARD_MAP_H_ + +#include + +// Initialize a hashtable that maps XKB specific key code values to +// Flutter's physical key code values. +void initialize_xkb_to_physical_key(GHashTable* table); + +// Initialize a hashtable that maps GDK keyval values to +// Flutter's logical key code values. +void initialize_gtk_keyval_to_logical_key(GHashTable* table); + +#endif // KEYBOARD_MAP_H_ From 600bd638759d5553107ed47b309c3e1314912708 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Fri, 9 Apr 2021 13:10:02 -0700 Subject: [PATCH 019/126] Test wip --- .../linux/fl_key_embedder_responder_test.cc | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 shell/platform/linux/fl_key_embedder_responder_test.cc diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc new file mode 100644 index 0000000000000..aaf1df60b7752 --- /dev/null +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -0,0 +1,97 @@ +// 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_key_embedder_responder.h" + +#include "gtest/gtest.h" + +#include "flutter/shell/platform/linux/fl_engine_private.h" +#include "flutter/shell/platform/linux/fl_binary_messenger_private.h" +#include "flutter/shell/platform/linux/testing/fl_test.h" + +static const char* expected_value = nullptr; +static gboolean expected_handled = FALSE; + +static FlValue* echo_response_cb(FlValue* echoed_value) { + gchar* text = fl_value_to_string(echoed_value); + EXPECT_STREQ(text, expected_value); + g_free(text); + + FlValue* value = fl_value_new_map(); + fl_value_set_string_take(value, "handled", fl_value_new_bool(expected_handled)); + return value; +} + +static void responder_callback(bool handled, gpointer user_data) { + EXPECT_EQ(handled, expected_handled); + g_main_loop_quit(static_cast(user_data)); +} + +// Test sending a letter "A"; +TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { + g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); + + g_autoptr(FlEngine) engine = make_mock_engine(); + FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); + + FlutterEngineSendKeyEventFnPtr old_handler = + embedder_api->SendKeyEvent; + embedder_api->SendKeyEvent = + + FlKeyEmbedderResponderMock mock{ + .value_converter = echo_response_cb, + .embedder_name = "test/echo", + }; + g_autoptr(FlKeyResponder) responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new( + engine)); + + char string[] = "A"; + GdkEventKey key_event = GdkEventKey{ + GDK_KEY_PRESS, // event type + nullptr, // window (not needed) + FALSE, // event was sent explicitly + 12345, // time + 0x0, // modifier state + GDK_KEY_A, // key code + 1, // length of string representation + reinterpret_cast(&string[0]), // string representation + 0x04, // scan code + 0, // keyboard group + 0, // is a modifier + }; + + // printf("Test 1 %s\n", expected_value);fflush(stdout); + fl_key_responder_handle_event(responder, &key_event, responder_callback, loop); + // printf("Test 2 %s\n", expected_value);fflush(stdout); + expected_value = + "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, keyCode: 65, " + "modifiers: 0, unicodeScalarValues: 65}"; + expected_handled = FALSE; + + // Blocks here until echo_response_cb is called. + g_main_loop_run(loop); + + key_event = GdkEventKey{ + GDK_KEY_RELEASE, // event type + nullptr, // window (not needed) + FALSE, // event was sent explicitly + 23456, // time + 0x0, // modifier state + GDK_KEY_A, // key code + 1, // length of string representation + reinterpret_cast(&string[0]), // string representation + 0x04, // scan code + 0, // keyboard group + 0, // is a modifier + }; + + fl_key_responder_handle_event(responder, &key_event, responder_callback, loop); + expected_value = + "{type: keyup, keymap: linux, scanCode: 4, toolkit: gtk, keyCode: 65, " + "modifiers: 0, unicodeScalarValues: 65}"; + expected_handled = FALSE; + + // Blocks here until echo_response_cb is called. + g_main_loop_run(loop); +} From 1e3e22f7a6cd8ec757e03c582295535bf0cdc5c8 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Sat, 10 Apr 2021 04:16:26 -0700 Subject: [PATCH 020/126] Compilable --- .../test_utils/proc_table_replacement.h | 2 +- shell/platform/linux/BUILD.gn | 3 + shell/platform/linux/fl_engine.cc | 4 +- shell/platform/linux/fl_engine_private.h | 4 +- .../linux/fl_key_channel_responder.cc | 4 +- .../platform/linux/fl_key_channel_responder.h | 7 +- .../linux/fl_key_channel_responder_test.cc | 34 +- .../linux/fl_key_embedder_responder.cc | 178 ++-- .../linux/fl_key_embedder_responder.h | 2 +- .../linux/fl_key_embedder_responder_test.cc | 97 ++- shell/platform/linux/fl_keyboard_manager.cc | 6 +- shell/platform/linux/fl_keyboard_manager.h | 3 +- .../linux/fl_keyboard_manager_test.cc | 28 +- shell/platform/linux/fl_view.cc | 3 +- shell/platform/linux/key_mapping.cc | 786 +++++++++--------- .../windows/keyboard_key_embedder_handler.cc | 2 + 16 files changed, 625 insertions(+), 538 deletions(-) diff --git a/shell/platform/embedder/test_utils/proc_table_replacement.h b/shell/platform/embedder/test_utils/proc_table_replacement.h index 6981ee97b42ae..2d64f374cea6d 100644 --- a/shell/platform/embedder/test_utils/proc_table_replacement.h +++ b/shell/platform/embedder/test_utils/proc_table_replacement.h @@ -13,7 +13,7 @@ // to run multiple times (e.g., using gtest_repeat). // // |proc| should be the name of an entry in FlutterEngineProcTable, such as -// "initialize". |mock_impl| should be a lamba that replaces its implementation, +// "Initialize". |mock_impl| should be a lamba that replaces its implementation, // taking the same arguments and returning the same type. #define MOCK_ENGINE_PROC(proc, mock_impl) \ ([&]() { \ diff --git a/shell/platform/linux/BUILD.gn b/shell/platform/linux/BUILD.gn index e15ee1443b4b4..0e406df1e7e44 100644 --- a/shell/platform/linux/BUILD.gn +++ b/shell/platform/linux/BUILD.gn @@ -77,6 +77,7 @@ source_set("flutter_linux_sources") { "fl_keyboard_manager.h", "fl_key_responder.h", "fl_key_channel_responder.h", + "fl_key_embedder_responder.h", "fl_method_call_private.h", "fl_method_channel_private.h", "fl_method_codec_private.h", @@ -103,6 +104,7 @@ source_set("flutter_linux_sources") { "fl_keyboard_manager.cc", "fl_key_responder.cc", "fl_key_channel_responder.cc", + "fl_key_embedder_responder.cc", "fl_message_codec.cc", "fl_method_call.cc", "fl_method_channel.cc", @@ -172,6 +174,7 @@ executable("flutter_linux_unittests") { "fl_json_method_codec_test.cc", "fl_keyboard_manager_test.cc", "fl_key_channel_responder_test.cc", + "fl_key_embedder_responder_test.cc", "fl_message_codec_test.cc", "fl_method_channel_test.cc", "fl_method_codec_test.cc", diff --git a/shell/platform/linux/fl_engine.cc b/shell/platform/linux/fl_engine.cc index 0a35efacb4a53..ba71160bd93cc 100644 --- a/shell/platform/linux/fl_engine.cc +++ b/shell/platform/linux/fl_engine.cc @@ -696,7 +696,7 @@ void fl_engine_send_mouse_pointer_event(FlEngine* self, self->embedder_api.SendPointerEvent(self->engine, &fl_event, 1); } -void fl_engine_send_key_event(FlEngine* engine, +void fl_engine_send_key_event(FlEngine* self, const FlutterKeyEvent* event, FlutterKeyEventCallback callback, void* user_data) { @@ -706,7 +706,7 @@ void fl_engine_send_key_event(FlEngine* engine, return; } - self->embedder_api.SendKeyEvent(self->engine, fl_event, callback, user_data); + self->embedder_api.SendKeyEvent(self->engine, event, callback, user_data); } void fl_engine_dispatch_semantics_action(FlEngine* self, diff --git a/shell/platform/linux/fl_engine_private.h b/shell/platform/linux/fl_engine_private.h index 27d5fd29ead6f..5840cf314c796 100644 --- a/shell/platform/linux/fl_engine_private.h +++ b/shell/platform/linux/fl_engine_private.h @@ -162,12 +162,14 @@ void fl_engine_send_mouse_pointer_event(FlEngine* engine, double scroll_delta_y, int64_t buttons); +/** + * fl_engine_send_key_event: + */ void fl_engine_send_key_event(FlEngine* engine, const FlutterKeyEvent* event, FlutterKeyEventCallback callback, void* user_data); - /** * fl_engine_dispatch_semantics_action: * @engine: an #FlEngine. diff --git a/shell/platform/linux/fl_key_channel_responder.cc b/shell/platform/linux/fl_key_channel_responder.cc index ec3e4a81c9b39..e9274c46afb96 100644 --- a/shell/platform/linux/fl_key_channel_responder.cc +++ b/shell/platform/linux/fl_key_channel_responder.cc @@ -7,7 +7,6 @@ #include #include -#include "flutter/shell/platform/linux/fl_keyboard_manager.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_basic_message_channel.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_json_message_codec.h" @@ -179,7 +178,8 @@ FlKeyChannelResponder* fl_key_channel_responder_new( self->mock = mock; g_autoptr(FlJsonMessageCodec) codec = fl_json_message_codec_new(); - const char* channel_name = mock == nullptr ? kChannelName : mock->channel_name; + const char* channel_name = + mock == nullptr ? kChannelName : mock->channel_name; self->channel = fl_basic_message_channel_new(messenger, channel_name, FL_MESSAGE_CODEC(codec)); diff --git a/shell/platform/linux/fl_key_channel_responder.h b/shell/platform/linux/fl_key_channel_responder.h index fbf5f17c73267..75d14b693fe00 100644 --- a/shell/platform/linux/fl_key_channel_responder.h +++ b/shell/platform/linux/fl_key_channel_responder.h @@ -21,7 +21,7 @@ typedef struct _FlKeyChannelResponderMock { G_BEGIN_DECLS -#define FL_TYPE_KEY_CHANNEL_RESPONDER fl_key_channel_responder_get_type () +#define FL_TYPE_KEY_CHANNEL_RESPONDER fl_key_channel_responder_get_type() G_DECLARE_FINAL_TYPE(FlKeyChannelResponder, fl_key_channel_responder, FL, @@ -55,8 +55,9 @@ G_DECLARE_FINAL_TYPE(FlKeyChannelResponder, * * Returns: a new #FlKeyChannelResponder. */ -FlKeyChannelResponder* fl_key_channel_responder_new(FlBinaryMessenger* messenger, - FlKeyChannelResponderMock* mock = nullptr); +FlKeyChannelResponder* fl_key_channel_responder_new( + FlBinaryMessenger* messenger, + FlKeyChannelResponderMock* mock = nullptr); G_END_DECLS diff --git a/shell/platform/linux/fl_key_channel_responder_test.cc b/shell/platform/linux/fl_key_channel_responder_test.cc index 4498c240c4e06..00d46230b4d15 100644 --- a/shell/platform/linux/fl_key_channel_responder_test.cc +++ b/shell/platform/linux/fl_key_channel_responder_test.cc @@ -6,8 +6,8 @@ #include "gtest/gtest.h" -#include "flutter/shell/platform/linux/fl_engine_private.h" #include "flutter/shell/platform/linux/fl_binary_messenger_private.h" +#include "flutter/shell/platform/linux/fl_engine_private.h" #include "flutter/shell/platform/linux/testing/fl_test.h" static const char* expected_value = nullptr; @@ -19,7 +19,8 @@ static FlValue* echo_response_cb(FlValue* echoed_value) { g_free(text); FlValue* value = fl_value_new_map(); - fl_value_set_string_take(value, "handled", fl_value_new_bool(expected_handled)); + fl_value_set_string_take(value, "handled", + fl_value_new_bool(expected_handled)); return value; } @@ -35,11 +36,11 @@ TEST(FlKeyChannelResponderTest, SendKeyEvent) { g_autoptr(FlEngine) engine = make_mock_engine(); g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine); FlKeyChannelResponderMock mock{ - .value_converter = echo_response_cb, - .channel_name = "test/echo", + .value_converter = echo_response_cb, + .channel_name = "test/echo", }; - g_autoptr(FlKeyResponder) responder = FL_KEY_RESPONDER(fl_key_channel_responder_new( - messenger, &mock)); + g_autoptr(FlKeyResponder) responder = + FL_KEY_RESPONDER(fl_key_channel_responder_new(messenger, &mock)); char string[] = "A"; GdkEventKey key_event = GdkEventKey{ @@ -57,7 +58,8 @@ TEST(FlKeyChannelResponderTest, SendKeyEvent) { }; // printf("Test 1 %s\n", expected_value);fflush(stdout); - fl_key_responder_handle_event(responder, &key_event, responder_callback, loop); + fl_key_responder_handle_event(responder, &key_event, responder_callback, + loop); // printf("Test 2 %s\n", expected_value);fflush(stdout); expected_value = "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, keyCode: 65, " @@ -81,7 +83,8 @@ TEST(FlKeyChannelResponderTest, SendKeyEvent) { 0, // is a modifier }; - fl_key_responder_handle_event(responder, &key_event, responder_callback, loop); + fl_key_responder_handle_event(responder, &key_event, responder_callback, + loop); expected_value = "{type: keyup, keymap: linux, scanCode: 4, toolkit: gtk, keyCode: 65, " "modifiers: 0, unicodeScalarValues: 65}"; @@ -136,8 +139,8 @@ TEST(FlKeyChannelResponderTest, SendKeyEvent) { // // Test sending a "NumLock" keypress. // TEST(FlKeyChannelResponderTest, SendNumLockKeyEvent) { // test_lock_event(GDK_KEY_Num_Lock, -// "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, " -// "keyCode: 65407, modifiers: 16}", +// "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, +// " "keyCode: 65407, modifiers: 16}", // "{type: keyup, keymap: linux, scanCode: 4, toolkit: gtk, " // "keyCode: 65407, modifiers: 0}"); // } @@ -145,8 +148,8 @@ TEST(FlKeyChannelResponderTest, SendKeyEvent) { // // Test sending a "CapsLock" keypress. // TEST(FlKeyChannelResponderTest, SendCapsLockKeyEvent) { // test_lock_event(GDK_KEY_Caps_Lock, -// "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, " -// "keyCode: 65509, modifiers: 2}", +// "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, +// " "keyCode: 65509, modifiers: 2}", // "{type: keyup, keymap: linux, scanCode: 4, toolkit: gtk, " // "keyCode: 65509, modifiers: 0}"); // } @@ -154,8 +157,8 @@ TEST(FlKeyChannelResponderTest, SendKeyEvent) { // // Test sending a "ShiftLock" keypress. // TEST(FlKeyChannelResponderTest, SendShiftLockKeyEvent) { // test_lock_event(GDK_KEY_Shift_Lock, -// "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, " -// "keyCode: 65510, modifiers: 2}", +// "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, +// " "keyCode: 65510, modifiers: 2}", // "{type: keyup, keymap: linux, scanCode: 4, toolkit: gtk, " // "keyCode: 65510, modifiers: 0}"); // } @@ -165,7 +168,8 @@ TEST(FlKeyChannelResponderTest, SendKeyEvent) { // FlBinaryMessenger* messenger = fl_binary_messenger_new(engine); // g_autoptr(FlKeyChannelResponder) responder = fl_key_channel_responder_new( -// messenger, text_input_plugin, echo_response_cb, "test/key-event-handled"); +// messenger, text_input_plugin, echo_response_cb, +// "test/key-event-handled"); // GdkEventKey key_event = GdkEventKey{ // GDK_KEY_PRESS, // event type diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index 04d9b2425e26b..618759933a666 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -7,49 +7,20 @@ #include #include +#include "flutter/shell/platform/embedder/embedder.h" +#include "flutter/shell/platform/linux/fl_engine_private.h" #include "flutter/shell/platform/linux/key_mapping.h" -#include "flutter/shell/platform/linux/fl_keyboard_manager.h" -#include "flutter/shell/platform/linux/public/flutter_linux/fl_basic_message_embedder.h" -#include "flutter/shell/platform/linux/public/flutter_linux/fl_json_message_codec.h" -struct _FlKeyEmbedderResponder { - GObject parent_instance; - - FlEngine* engine; - - // Stores pressed keys, mapping their Flutter physical key to Flutter logical key. - // - // Both keys and values are directly stored uint64s. - GHashTable* pressing_records; - - // A static map from XKB to Flutter's physical key code - GHashTable* xkb_to_physical_key; +namespace { +const uint64_t kAutogeneratedMask = 0x10000000000; - // A static map from GTK keyval to Flutter's logical key code - GHashTable* keyval_to_logical_key; - - gchar* character_to_free; -}; +/** + * The code prefix for keys from Linux which do not have a Unicode + * representation. + */ +constexpr uint64_t kLinuxKeyIdPlane = 0x00600000000; -static void fl_key_embedder_responder_iface_init(FlKeyResponderInterface* iface); - -G_DEFINE_TYPE_WITH_CODE( - FlKeyEmbedderResponder, - fl_key_embedder_responder, - G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE(FL_TYPE_KEY_RESPONDER, - fl_key_embedder_responder_iface_init)) - -static void fl_key_embedder_responder_handle_event( - FlKeyResponder* responder, - GdkEventKey* event, - FlKeyResponderAsyncCallback callback, - gpointer user_data); - -static void fl_key_embedder_responder_iface_init( - FlKeyResponderInterface* iface) { - iface->handle_event = fl_key_embedder_responder_handle_event; -} +constexpr uint64_t kMicrosecondsPerMillisecond = 1000; // Declare and define a private class to hold response data from the framework. G_DECLARE_FINAL_TYPE(FlKeyEventResponseData, @@ -105,12 +76,54 @@ static FlKeyEventResponseData* fl_key_event_response_data_new( // while the framework was responding. g_object_add_weak_pointer(G_OBJECT(responder), reinterpret_cast(&(self->responder))); - self->id = id; self->callback = callback; self->user_data = user_data; return self; } +} // namespace + +struct _FlKeyEmbedderResponder { + GObject parent_instance; + + FlEngine* engine; + + // Stores pressed keys, mapping their Flutter physical key to Flutter logical + // key. + // + // Both keys and values are directly stored uint64s. + GHashTable* pressing_records; + + // A static map from XKB to Flutter's physical key code + GHashTable* xkb_to_physical_key; + + // A static map from GTK keyval to Flutter's logical key code + GHashTable* keyval_to_logical_key; + + gchar* character_to_free; +}; + +static void fl_key_embedder_responder_iface_init( + FlKeyResponderInterface* iface); + +G_DEFINE_TYPE_WITH_CODE( + FlKeyEmbedderResponder, + fl_key_embedder_responder, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE(FL_TYPE_KEY_RESPONDER, + fl_key_embedder_responder_iface_init)) + +static void fl_key_embedder_responder_handle_event( + FlKeyResponder* responder, + GdkEventKey* event, + FlKeyResponderAsyncCallback callback, + gpointer user_data); + +static void fl_key_embedder_responder_iface_init( + FlKeyResponderInterface* iface) { + iface->handle_event = fl_key_embedder_responder_handle_event; +} + // Disposes of an FlKeyEmbedderResponder instance. static void fl_key_embedder_responder_dispose(GObject* object) { FlKeyEmbedderResponder* self = FL_KEY_EMBEDDER_RESPONDER(object); @@ -139,8 +152,7 @@ static void fl_key_embedder_responder_init(FlKeyEmbedderResponder* self) {} // that the framework doesn't handle. Mainly for testing purposes, it also takes // an optional callback to call when a response is received, and an optional // embedder name to use when sending messages. -FlKeyEmbedderResponder* fl_key_embedder_responder_new( - FlEngine* engine) { +FlKeyEmbedderResponder* fl_key_embedder_responder_new(FlEngine* engine) { g_return_val_if_fail(FL_IS_ENGINE(engine), nullptr); FlKeyEmbedderResponder* self = FL_KEY_EMBEDDER_RESPONDER( @@ -162,8 +174,10 @@ FlKeyEmbedderResponder* fl_key_embedder_responder_new( return self; } -static uint64_t event_to_physical_key(const GdkEventKey* event, GHashTable* table) { - gpointer record = g_hash_table_lookup(table, GUINT_TO_POINTER(event->hardware_keycode)); +static uint64_t event_to_physical_key(const GdkEventKey* event, + GHashTable* table) { + gpointer record = + g_hash_table_lookup(table, GUINT_TO_POINTER(event->hardware_keycode)); if (record != nullptr) { return GPOINTER_TO_UINT(record); } @@ -171,7 +185,8 @@ static uint64_t event_to_physical_key(const GdkEventKey* event, GHashTable* tabl return kAutogeneratedMask | kLinuxKeyIdPlane | event->hardware_keycode; } -static uint64_t event_to_logical_key(const GdkEventKey* event, GHashTable* table) { +static uint64_t event_to_logical_key(const GdkEventKey* event, + GHashTable* table) { guint keyval = event->keyval; gpointer record = g_hash_table_lookup(table, GUINT_TO_POINTER(keyval)); if (record != nullptr) { @@ -214,19 +229,15 @@ static gpointer uint64ToGpointer(uint64_t number) { // Return the logical key corresponding to the physical key. // // Returns 0 if not found. -static uint64_t pressed_logical_for_physical(GHashTable* pressing_records, uint64_t physical) { - return gpointerToUint64(g_hash_table_lookup(pressing_records, uint64ToGpointer(physical))); -} - -static size_t fl_keyboard_manager_convert_key_event(FlKeyboardManager* self, - const GdkEventKey* event, - FlKeyDatum* results) { +static uint64_t pressed_logical_for_physical(GHashTable* pressing_records, + uint64_t physical) { + return gpointerToUint64( + g_hash_table_lookup(pressing_records, uint64ToGpointer(physical))); } // Handles a response from the framework to a key event sent to the framework // earlier. -static void handle_response(bool handled, - gpointer user_data) { +static void handle_response(bool handled, gpointer user_data) { g_autoptr(FlKeyEventResponseData) data = FL_KEY_EVENT_RESPONSE_DATA(user_data); @@ -258,52 +269,53 @@ static void fl_key_embedder_responder_handle_event( g_free(self->character_to_free); self->character_to_free = nullptr; } - uint64_t physical_key = event_to_physical_key(event, self->xkb_to_physical_key); - uint64_t logical_key = event_to_logical_key(event, self->keyval_to_logical_key); + uint64_t physical_key = + event_to_physical_key(event, self->xkb_to_physical_key); + uint64_t logical_key = + event_to_logical_key(event, self->keyval_to_logical_key); bool is_physical_down = event->type == GDK_KEY_PRESS; - uint64_t last_logical_record = pressed_logical_for_physical(self->pressing_records, physical_key); + uint64_t last_logical_record = + pressed_logical_for_physical(self->pressing_records, physical_key); uint64_t next_logical_record = is_physical_down ? last_logical_record : 0; char* character_to_free = nullptr; - printf("last %lu next %lu down %d type %d\n", last_logical_record, next_logical_record, is_physical_down, event->type); + printf("last %lu next %lu down %d type %d\n", last_logical_record, + next_logical_record, is_physical_down, event->type); fflush(stdout); - FlutterKeyEvent event; - event->struct_size = sizeof(event); - event->type = kFlutterKeyEventTypeDown; - event->physical = physical_key; - event->logical = physical_key; - event->character = character_to_free; - event->synthesized = false; - - base_event->timestamp = event_to_timestamp(event); - base_event->synthesized = false; + FlutterKeyEvent out_event; + out_event.struct_size = sizeof(out_event); + out_event.type = kFlutterKeyEventTypeDown; + out_event.timestamp = event_to_timestamp(event); + out_event.physical = physical_key; + out_event.logical = physical_key; + out_event.character = character_to_free; + out_event.synthesized = false; if (is_physical_down) { - character_to_free = event_to_character(event); // Might be null - base_event->character = character_to_free; + character_to_free = event_to_character(event); // Might be null + out_event.character = character_to_free; if (last_logical_record) { // GTK doesn't report repeat events separatedly, therefore we can't // distinguish a repeat event from a down event after a missed up event. - base_event->kind = kFlKeyDataKindRepeat; - base_event->logical = last_logical_record; + out_event.type = kFlutterKeyEventTypeRepeat; + out_event.logical = last_logical_record; } else { - base_event->kind = kFlKeyDataKindDown; - base_event->logical = logical_key; + out_event.type = kFlutterKeyEventTypeDown; + out_event.logical = logical_key; } - } else { // is_physical_down false - base_event->character = nullptr; - base_event->kind = kFlKeyDataKindUp; - base_event->logical = logical_key; + } else { // is_physical_down false + out_event.character = nullptr; + out_event.type = kFlutterKeyEventTypeUp; + out_event.logical = logical_key; } - FlKeyEventResponseData* response_data = fl_key_event_response_data_new( - self, callback, user_data); - - fl_engine_send_key_event(self->engine, &event, handle_response, response_data); + FlKeyEventResponseData* response_data = + fl_key_event_response_data_new(self, callback, user_data); - return 1; + fl_engine_send_key_event(self->engine, &out_event, handle_response, + response_data); } diff --git a/shell/platform/linux/fl_key_embedder_responder.h b/shell/platform/linux/fl_key_embedder_responder.h index 296c845b9a760..849d57039ea87 100644 --- a/shell/platform/linux/fl_key_embedder_responder.h +++ b/shell/platform/linux/fl_key_embedder_responder.h @@ -16,7 +16,7 @@ constexpr int kMaxConvertedKeyData = 3; G_BEGIN_DECLS -#define FL_TYPE_KEY_EMBEDDER_RESPONDER fl_key_embedder_responder_get_type () +#define FL_TYPE_KEY_EMBEDDER_RESPONDER fl_key_embedder_responder_get_type() G_DECLARE_FINAL_TYPE(FlKeyEmbedderResponder, fl_key_embedder_responder, FL, diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index aaf1df60b7752..014014208d6ad 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -6,21 +6,72 @@ #include "gtest/gtest.h" -#include "flutter/shell/platform/linux/fl_engine_private.h" +#include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h" #include "flutter/shell/platform/linux/fl_binary_messenger_private.h" +#include "flutter/shell/platform/linux/fl_engine_private.h" #include "flutter/shell/platform/linux/testing/fl_test.h" static const char* expected_value = nullptr; static gboolean expected_handled = FALSE; -static FlValue* echo_response_cb(FlValue* echoed_value) { - gchar* text = fl_value_to_string(echoed_value); - EXPECT_STREQ(text, expected_value); - g_free(text); +namespace { +G_DECLARE_FINAL_TYPE(FlKeyboardCallRecord, + fl_keyboard_call_record, + FL, + KEYBOARD_CALL_RECORD, + GObject); + +struct _FlKeyboardCallRecord { + GObject parent_instance; + + FlutterKeyEvent* event; + FlutterKeyEventCallback callback; + gpointer user_data; +}; + +G_DEFINE_TYPE(FlKeyboardCallRecord, fl_keyboard_call_record, G_TYPE_OBJECT) + +static void fl_keyboard_call_record_init(FlKeyboardCallRecord* self) {} + +// Dispose method for FlKeyboardCallRecord. +static void fl_keyboard_call_record_dispose(GObject* object) { + g_return_if_fail(FL_IS_KEYBOARD_CALL_RECORD(object)); - FlValue* value = fl_value_new_map(); - fl_value_set_string_take(value, "handled", fl_value_new_bool(expected_handled)); - return value; + FlKeyboardCallRecord* self = FL_KEYBOARD_CALL_RECORD(object); + if (self->event != nullptr) { + g_free(const_cast(self->event->character)); + g_free(self->event); + } + G_OBJECT_CLASS(fl_keyboard_call_record_parent_class)->dispose(object); +} + +// Class Initialization method for FlKeyboardCallRecord class. +static void fl_keyboard_call_record_class_init( + FlKeyboardCallRecordClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_keyboard_call_record_dispose; +} + +static FlKeyboardCallRecord* fl_keyboard_call_record_new( + const FlutterKeyEvent* event, + FlutterKeyEventCallback callback, + gpointer user_data) { + g_return_val_if_fail(event != nullptr, nullptr); + + FlKeyboardCallRecord* self = FL_KEYBOARD_CALL_RECORD( + g_object_new(fl_keyboard_call_record_get_type(), nullptr)); + + FlutterKeyEvent* clone_event = g_new(FlutterKeyEvent, 1); + *clone_event = *event; + if (event->character != nullptr) { + size_t character_length = strlen(event->character); + char* clone_character = g_new(char, character_length + 1); + strcpy(clone_character, event->character); + clone_event->character = clone_character; + } + self->callback = callback; + self->user_data = user_data; + + return self; } static void responder_callback(bool handled, gpointer user_data) { @@ -31,20 +82,24 @@ static void responder_callback(bool handled, gpointer user_data) { // Test sending a letter "A"; TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); + g_autoptr(GPtrArray) call_records = + g_ptr_array_new_with_free_func(g_object_unref); g_autoptr(FlEngine) engine = make_mock_engine(); FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); - FlutterEngineSendKeyEventFnPtr old_handler = - embedder_api->SendKeyEvent; - embedder_api->SendKeyEvent = + embedder_api->SendKeyEvent = MOCK_ENGINE_PROC( + SendKeyEvent, ([&call_records](auto engine, const FlutterKeyEvent* event, + FlutterKeyEventCallback callback, + void* user_data) -> FlutterEngineResult { + g_ptr_array_add(call_records, fl_keyboard_call_record_new( + event, callback, user_data)); - FlKeyEmbedderResponderMock mock{ - .value_converter = echo_response_cb, - .embedder_name = "test/echo", - }; - g_autoptr(FlKeyResponder) responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new( - engine)); + return kSuccess; + })); + + g_autoptr(FlKeyResponder) responder = + FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); char string[] = "A"; GdkEventKey key_event = GdkEventKey{ @@ -62,7 +117,8 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { }; // printf("Test 1 %s\n", expected_value);fflush(stdout); - fl_key_responder_handle_event(responder, &key_event, responder_callback, loop); + fl_key_responder_handle_event(responder, &key_event, responder_callback, + loop); // printf("Test 2 %s\n", expected_value);fflush(stdout); expected_value = "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, keyCode: 65, " @@ -86,7 +142,8 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { 0, // is a modifier }; - fl_key_responder_handle_event(responder, &key_event, responder_callback, loop); + fl_key_responder_handle_event(responder, &key_event, responder_callback, + loop); expected_value = "{type: keyup, keymap: linux, scanCode: 4, toolkit: gtk, keyCode: 65, " "modifiers: 0, unicodeScalarValues: 65}"; @@ -95,3 +152,5 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { // Blocks here until echo_response_cb is called. g_main_loop_run(loop); } + +} // namespace diff --git a/shell/platform/linux/fl_keyboard_manager.cc b/shell/platform/linux/fl_keyboard_manager.cc index d62e5e95b1756..a6a0fff4beffb 100644 --- a/shell/platform/linux/fl_keyboard_manager.cc +++ b/shell/platform/linux/fl_keyboard_manager.cc @@ -255,7 +255,8 @@ static void responder_handle_event_callback(bool handled, compare_pending_by_sequence_id, &result_index); g_return_if_fail(found); printf("callback 3\n"); - FlKeyboardPendingEvent* pending = FL_KEYBOARD_PENDING_EVENT(g_ptr_array_index(self->pending_responds, result_index)); + FlKeyboardPendingEvent* pending = FL_KEYBOARD_PENDING_EVENT( + g_ptr_array_index(self->pending_responds, result_index)); printf("callback 4 unrep %zu\n", pending->unreplied); g_return_if_fail(pending != nullptr); g_return_if_fail(pending->unreplied > 0); @@ -366,5 +367,6 @@ gboolean fl_keyboard_manager_handle_event(FlKeyboardManager* self, gboolean fl_keyboard_manager_state_clear(FlKeyboardManager* self) { g_return_val_if_fail(FL_IS_KEYBOARD_MANAGER(self), FALSE); - return self->pending_responds->len == 0 && self->pending_redispatches->len == 0; + return self->pending_responds->len == 0 && + self->pending_redispatches->len == 0; } diff --git a/shell/platform/linux/fl_keyboard_manager.h b/shell/platform/linux/fl_keyboard_manager.h index ce4990c8b8d0a..e8021280404b0 100644 --- a/shell/platform/linux/fl_keyboard_manager.h +++ b/shell/platform/linux/fl_keyboard_manager.h @@ -69,8 +69,7 @@ void fl_keyboard_manager_add_responder(FlKeyboardManager* manager, gboolean fl_keyboard_manager_handle_event(FlKeyboardManager* manager, GdkEventKey* event); -gboolean fl_keyboard_manager_state_clear( - FlKeyboardManager* manager); +gboolean fl_keyboard_manager_state_clear(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 0d08a0f93278f..cf65993c1a513 100644 --- a/shell/platform/linux/fl_keyboard_manager_test.cc +++ b/shell/platform/linux/fl_keyboard_manager_test.cc @@ -14,11 +14,7 @@ typedef void (*CallbackHandler)(FlKeyResponderAsyncCallback callback, constexpr guint16 kKeyCodeKeyA = 0x26u; constexpr guint16 kKeyCodeKeyB = 0x38u; -} - -G_BEGIN_DECLS -#define FL_TYPE_KEYBOARD_CALL_RECORD fl_keyboard_call_record_get_type() G_DECLARE_FINAL_TYPE(FlKeyboardCallRecord, fl_keyboard_call_record, FL, @@ -51,8 +47,6 @@ struct _FlKeyMockResponder { int delegate_id; }; -G_END_DECLS - G_DEFINE_TYPE(FlKeyboardCallRecord, fl_keyboard_call_record, G_TYPE_OBJECT) static void fl_keyboard_call_record_init(FlKeyboardCallRecord* self) {} @@ -95,10 +89,12 @@ static FlKeyboardCallRecord* fl_keyboard_call_record_new( static void dont_respond(FlKeyResponderAsyncCallback callback, gpointer user_data) {} -static void respond_true(FlKeyResponderAsyncCallback callback, gpointer user_data) { +static void respond_true(FlKeyResponderAsyncCallback callback, + gpointer user_data) { callback(true, user_data); } -static void respond_false(FlKeyResponderAsyncCallback callback, gpointer user_data) { +static void respond_false(FlKeyResponderAsyncCallback callback, + gpointer user_data) { callback(false, user_data); } @@ -139,9 +135,8 @@ static void fl_key_mock_responder_class_init(FlKeyMockResponderClass* klass) {} static void fl_key_mock_responder_init(FlKeyMockResponder* self) {} -static FlKeyMockResponder* fl_key_mock_responder_new( - GPtrArray* call_records, - int delegate_id) { +static FlKeyMockResponder* fl_key_mock_responder_new(GPtrArray* call_records, + int delegate_id) { FlKeyMockResponder* self = FL_KEY_MOCK_RESPONDER( g_object_new(fl_key_mock_responder_get_type(), nullptr)); @@ -201,7 +196,8 @@ static void gdk_event_destroy_notify(gpointer pointer) { static GPtrArray* redispatched_events() { if (_g_redispatched_events == nullptr) { - _g_redispatched_events = g_ptr_array_new_with_free_func(gdk_event_destroy_notify); + _g_redispatched_events = + g_ptr_array_new_with_free_func(gdk_event_destroy_notify); } return _g_redispatched_events; } @@ -268,11 +264,13 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { record = FL_KEYBOARD_CALL_RECORD(g_ptr_array_index(call_records, 1)); record->callback(false, record->user_data); EXPECT_EQ(redispatched_events()->len, 1u); - EXPECT_EQ(GDK_EVENT_KEY(g_ptr_array_last(redispatched_events()))->keyval, 0x62u); + EXPECT_EQ(GDK_EVENT_KEY(g_ptr_array_last(redispatched_events()))->keyval, + 0x62u); record = FL_KEYBOARD_CALL_RECORD(g_ptr_array_index(call_records, 0)); record->callback(false, record->user_data); EXPECT_EQ(redispatched_events()->len, 2u); - EXPECT_EQ(GDK_EVENT_KEY(g_ptr_array_last(redispatched_events()))->keyval, 0x61u); + EXPECT_EQ(GDK_EVENT_KEY(g_ptr_array_last(redispatched_events()))->keyval, + 0x61u); g_ptr_array_clear(call_records); @@ -420,3 +418,5 @@ TEST(FlKeyboardManagerTest, WithTwoAsyncDelegates) { g_ptr_array_clear(redispatched_events()); } + +} // namespace diff --git a/shell/platform/linux/fl_view.cc b/shell/platform/linux/fl_view.cc index e30b85ade5e81..72131e1b8d7d3 100644 --- a/shell/platform/linux/fl_view.cc +++ b/shell/platform/linux/fl_view.cc @@ -183,7 +183,8 @@ static void fl_view_constructed(GObject* object) { self->keyboard_manager = fl_keyboard_manager_new( fl_text_input_plugin_new(messenger, self), gdk_event_put); fl_keyboard_manager_add_responder( - self->keyboard_manager, FL_KEY_RESPONDER(fl_key_channel_responder_new(messenger))); + self->keyboard_manager, + FL_KEY_RESPONDER(fl_key_channel_responder_new(messenger))); self->mouse_cursor_plugin = fl_mouse_cursor_plugin_new(messenger, self); self->platform_plugin = fl_platform_plugin_new(messenger); diff --git a/shell/platform/linux/key_mapping.cc b/shell/platform/linux/key_mapping.cc index 60d4e76f59246..3e26d486a39f6 100644 --- a/shell/platform/linux/key_mapping.cc +++ b/shell/platform/linux/key_mapping.cc @@ -2,411 +2,413 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include #include +#include // DO NOT EDIT -- DO NOT EDIT -- DO NOT EDIT -// This file is generated by flutter/flutter@dev/tools/gen_keycodes/bin/gen_keycodes.dart and -// should not be edited directly. +// This file is generated by +// flutter/flutter@dev/tools/gen_keycodes/bin/gen_keycodes.dart and should not +// be edited directly. // -// Edit the template dev/tools/gen_keycodes/data/gtk_keyboard_map_cc.tmpl instead. -// See dev/tools/gen_keycodes/README.md for more information. +// Edit the template dev/tools/gen_keycodes/data/gtk_keyboard_map_cc.tmpl +// instead. See dev/tools/gen_keycodes/README.md for more information. // Insert a new entry into a hashtable from uint64 to uint64. // // Returns whether the newly added value was already in the hash table or not. static bool insert_record(GHashTable* table, guint64 xkb, guint64 fl_key) { - return g_hash_table_insert(table, GUINT_TO_POINTER(xkb), GUINT_TO_POINTER(fl_key)); + return g_hash_table_insert(table, GUINT_TO_POINTER(xkb), + GUINT_TO_POINTER(fl_key)); } void initialize_xkb_to_physical_key(GHashTable* table) { - insert_record(table, 0x00000281, 0x00000017); // privacyScreenToggle - insert_record(table, 0x00000096, 0x00010082); // sleep - insert_record(table, 0x00000097, 0x00010083); // wakeUp - insert_record(table, 0x000000eb, 0x000100b5); // displayToggleIntExt - insert_record(table, 0x00000026, 0x00070004); // keyA - insert_record(table, 0x00000038, 0x00070005); // keyB - insert_record(table, 0x00000036, 0x00070006); // keyC - insert_record(table, 0x00000028, 0x00070007); // keyD - insert_record(table, 0x0000001a, 0x00070008); // keyE - insert_record(table, 0x00000029, 0x00070009); // keyF - insert_record(table, 0x0000002a, 0x0007000a); // keyG - insert_record(table, 0x0000002b, 0x0007000b); // keyH - insert_record(table, 0x0000001f, 0x0007000c); // keyI - insert_record(table, 0x0000002c, 0x0007000d); // keyJ - insert_record(table, 0x0000002d, 0x0007000e); // keyK - insert_record(table, 0x0000002e, 0x0007000f); // keyL - insert_record(table, 0x0000003a, 0x00070010); // keyM - insert_record(table, 0x00000039, 0x00070011); // keyN - insert_record(table, 0x00000020, 0x00070012); // keyO - insert_record(table, 0x00000021, 0x00070013); // keyP - insert_record(table, 0x00000018, 0x00070014); // keyQ - insert_record(table, 0x0000001b, 0x00070015); // keyR - insert_record(table, 0x00000027, 0x00070016); // keyS - insert_record(table, 0x0000001c, 0x00070017); // keyT - insert_record(table, 0x0000001e, 0x00070018); // keyU - insert_record(table, 0x00000037, 0x00070019); // keyV - insert_record(table, 0x00000019, 0x0007001a); // keyW - insert_record(table, 0x00000035, 0x0007001b); // keyX - insert_record(table, 0x0000001d, 0x0007001c); // keyY - insert_record(table, 0x00000034, 0x0007001d); // keyZ - insert_record(table, 0x0000000a, 0x0007001e); // digit1 - insert_record(table, 0x0000000b, 0x0007001f); // digit2 - insert_record(table, 0x0000000c, 0x00070020); // digit3 - insert_record(table, 0x0000000d, 0x00070021); // digit4 - insert_record(table, 0x0000000e, 0x00070022); // digit5 - insert_record(table, 0x0000000f, 0x00070023); // digit6 - insert_record(table, 0x00000010, 0x00070024); // digit7 - insert_record(table, 0x00000011, 0x00070025); // digit8 - insert_record(table, 0x00000012, 0x00070026); // digit9 - insert_record(table, 0x00000013, 0x00070027); // digit0 - insert_record(table, 0x00000024, 0x00070028); // enter - insert_record(table, 0x00000009, 0x00070029); // escape - insert_record(table, 0x00000016, 0x0007002a); // backspace - insert_record(table, 0x00000017, 0x0007002b); // tab - insert_record(table, 0x00000041, 0x0007002c); // space - insert_record(table, 0x00000014, 0x0007002d); // minus - insert_record(table, 0x00000015, 0x0007002e); // equal - insert_record(table, 0x00000022, 0x0007002f); // bracketLeft - insert_record(table, 0x00000023, 0x00070030); // bracketRight - insert_record(table, 0x00000033, 0x00070031); // backslash - insert_record(table, 0x0000002f, 0x00070033); // semicolon - insert_record(table, 0x00000030, 0x00070034); // quote - insert_record(table, 0x00000031, 0x00070035); // backquote - insert_record(table, 0x0000003b, 0x00070036); // comma - insert_record(table, 0x0000003c, 0x00070037); // period - insert_record(table, 0x0000003d, 0x00070038); // slash - insert_record(table, 0x00000042, 0x00070039); // capsLock - insert_record(table, 0x00000043, 0x0007003a); // f1 - insert_record(table, 0x00000044, 0x0007003b); // f2 - insert_record(table, 0x00000045, 0x0007003c); // f3 - insert_record(table, 0x00000046, 0x0007003d); // f4 - insert_record(table, 0x00000047, 0x0007003e); // f5 - insert_record(table, 0x00000048, 0x0007003f); // f6 - insert_record(table, 0x00000049, 0x00070040); // f7 - insert_record(table, 0x0000004a, 0x00070041); // f8 - insert_record(table, 0x0000004b, 0x00070042); // f9 - insert_record(table, 0x0000004c, 0x00070043); // f10 - insert_record(table, 0x0000005f, 0x00070044); // f11 - insert_record(table, 0x00000060, 0x00070045); // f12 - insert_record(table, 0x0000006b, 0x00070046); // printScreen - insert_record(table, 0x0000004e, 0x00070047); // scrollLock - insert_record(table, 0x0000007f, 0x00070048); // pause - insert_record(table, 0x00000076, 0x00070049); // insert - insert_record(table, 0x0000006e, 0x0007004a); // home - insert_record(table, 0x00000070, 0x0007004b); // pageUp - insert_record(table, 0x00000077, 0x0007004c); // delete - insert_record(table, 0x00000073, 0x0007004d); // end - insert_record(table, 0x00000075, 0x0007004e); // pageDown - insert_record(table, 0x00000072, 0x0007004f); // arrowRight - insert_record(table, 0x00000071, 0x00070050); // arrowLeft - insert_record(table, 0x00000074, 0x00070051); // arrowDown - insert_record(table, 0x0000006f, 0x00070052); // arrowUp - insert_record(table, 0x0000004d, 0x00070053); // numLock - insert_record(table, 0x0000006a, 0x00070054); // numpadDivide - insert_record(table, 0x0000003f, 0x00070055); // numpadMultiply - insert_record(table, 0x00000052, 0x00070056); // numpadSubtract - insert_record(table, 0x00000056, 0x00070057); // numpadAdd - insert_record(table, 0x00000068, 0x00070058); // numpadEnter - insert_record(table, 0x00000057, 0x00070059); // numpad1 - insert_record(table, 0x00000058, 0x0007005a); // numpad2 - insert_record(table, 0x00000059, 0x0007005b); // numpad3 - insert_record(table, 0x00000053, 0x0007005c); // numpad4 - insert_record(table, 0x00000054, 0x0007005d); // numpad5 - insert_record(table, 0x00000055, 0x0007005e); // numpad6 - insert_record(table, 0x0000004f, 0x0007005f); // numpad7 - insert_record(table, 0x00000050, 0x00070060); // numpad8 - insert_record(table, 0x00000051, 0x00070061); // numpad9 - insert_record(table, 0x0000005a, 0x00070062); // numpad0 - insert_record(table, 0x0000005b, 0x00070063); // numpadDecimal - insert_record(table, 0x0000005e, 0x00070064); // intlBackslash - insert_record(table, 0x00000087, 0x00070065); // contextMenu - insert_record(table, 0x0000007c, 0x00070066); // power - insert_record(table, 0x0000007d, 0x00070067); // numpadEqual - insert_record(table, 0x000000bf, 0x00070068); // f13 - insert_record(table, 0x000000c0, 0x00070069); // f14 - insert_record(table, 0x000000c1, 0x0007006a); // f15 - insert_record(table, 0x000000c2, 0x0007006b); // f16 - insert_record(table, 0x000000c3, 0x0007006c); // f17 - insert_record(table, 0x000000c4, 0x0007006d); // f18 - insert_record(table, 0x000000c5, 0x0007006e); // f19 - insert_record(table, 0x000000c6, 0x0007006f); // f20 - insert_record(table, 0x000000c7, 0x00070070); // f21 - insert_record(table, 0x000000c8, 0x00070071); // f22 - insert_record(table, 0x000000c9, 0x00070072); // f23 - insert_record(table, 0x000000ca, 0x00070073); // f24 - insert_record(table, 0x0000008e, 0x00070074); // open - insert_record(table, 0x00000092, 0x00070075); // help - insert_record(table, 0x0000008c, 0x00070077); // select - insert_record(table, 0x00000089, 0x00070079); // again - insert_record(table, 0x0000008b, 0x0007007a); // undo - insert_record(table, 0x00000091, 0x0007007b); // cut - insert_record(table, 0x0000008d, 0x0007007c); // copy - insert_record(table, 0x0000008f, 0x0007007d); // paste - insert_record(table, 0x00000090, 0x0007007e); // find - insert_record(table, 0x00000079, 0x0007007f); // audioVolumeMute - insert_record(table, 0x0000007b, 0x00070080); // audioVolumeUp - insert_record(table, 0x0000007a, 0x00070081); // audioVolumeDown - insert_record(table, 0x00000081, 0x00070085); // numpadComma - insert_record(table, 0x00000061, 0x00070087); // intlRo - insert_record(table, 0x00000065, 0x00070088); // kanaMode - insert_record(table, 0x00000084, 0x00070089); // intlYen - insert_record(table, 0x00000064, 0x0007008a); // convert - insert_record(table, 0x00000066, 0x0007008b); // nonConvert - insert_record(table, 0x00000082, 0x00070090); // lang1 - insert_record(table, 0x00000083, 0x00070091); // lang2 - insert_record(table, 0x00000062, 0x00070092); // lang3 - insert_record(table, 0x00000063, 0x00070093); // lang4 - insert_record(table, 0x0000005d, 0x00070094); // lang5 - insert_record(table, 0x000000bb, 0x000700b6); // numpadParenLeft - insert_record(table, 0x000000bc, 0x000700b7); // numpadParenRight - insert_record(table, 0x0000007e, 0x000700d7); // numpadSignChange - insert_record(table, 0x00000025, 0x000700e0); // controlLeft - insert_record(table, 0x00000032, 0x000700e1); // shiftLeft - insert_record(table, 0x00000040, 0x000700e2); // altLeft - insert_record(table, 0x00000085, 0x000700e3); // metaLeft - insert_record(table, 0x00000069, 0x000700e4); // controlRight - insert_record(table, 0x0000003e, 0x000700e5); // shiftRight - insert_record(table, 0x0000006c, 0x000700e6); // altRight - insert_record(table, 0x00000086, 0x000700e7); // metaRight - insert_record(table, 0x0000016e, 0x000c0060); // info - insert_record(table, 0x0000017a, 0x000c0061); // closedCaptionToggle - insert_record(table, 0x000000e9, 0x000c006f); // brightnessUp - insert_record(table, 0x000000e8, 0x000c0070); // brightnessDown - insert_record(table, 0x000001b7, 0x000c0072); // brightnessToggle - insert_record(table, 0x00000258, 0x000c0073); // brightnessMinimum - insert_record(table, 0x00000259, 0x000c0074); // brightnessMaximum - insert_record(table, 0x000000fc, 0x000c0075); // brightnessAuto - insert_record(table, 0x000000ee, 0x000c0079); // kbdIllumUp - insert_record(table, 0x000000ed, 0x000c007a); // kbdIllumDown - insert_record(table, 0x0000019d, 0x000c0083); // mediaLast - insert_record(table, 0x000000b1, 0x000c008c); // launchPhone - insert_record(table, 0x00000172, 0x000c008d); // programGuide - insert_record(table, 0x000000b6, 0x000c0094); // exit - insert_record(table, 0x000001a2, 0x000c009c); // channelUp - insert_record(table, 0x000001a3, 0x000c009d); // channelDown - insert_record(table, 0x000000d7, 0x000c00b0); // mediaPlay - insert_record(table, 0x000000d1, 0x000c00b1); // mediaPause - insert_record(table, 0x000000af, 0x000c00b2); // mediaRecord - insert_record(table, 0x000000d8, 0x000c00b3); // mediaFastForward - insert_record(table, 0x000000b0, 0x000c00b4); // mediaRewind - insert_record(table, 0x000000ab, 0x000c00b5); // mediaTrackNext - insert_record(table, 0x000000ad, 0x000c00b6); // mediaTrackPrevious - insert_record(table, 0x000000ae, 0x000c00b7); // mediaStop - insert_record(table, 0x000000a9, 0x000c00b8); // eject - insert_record(table, 0x000000ac, 0x000c00cd); // mediaPlayPause - insert_record(table, 0x0000024e, 0x000c00cf); // speechInputToggle - insert_record(table, 0x000000d9, 0x000c00e5); // bassBoost - insert_record(table, 0x000000b3, 0x000c0183); // mediaSelect - insert_record(table, 0x000001ad, 0x000c0184); // launchWordProcessor - insert_record(table, 0x000001af, 0x000c0186); // launchSpreadsheet - insert_record(table, 0x000000a3, 0x000c018a); // launchMail - insert_record(table, 0x000001b5, 0x000c018d); // launchContacts - insert_record(table, 0x00000195, 0x000c018e); // launchCalendar - insert_record(table, 0x00000094, 0x000c0192); // launchApp2 - insert_record(table, 0x00000098, 0x000c0194); // launchApp1 - insert_record(table, 0x0000009e, 0x000c0196); // launchInternetBrowser - insert_record(table, 0x000001b9, 0x000c019c); // logOff - insert_record(table, 0x000000a0, 0x000c019e); // lockScreen - insert_record(table, 0x0000024b, 0x000c019f); // launchControlPanel - insert_record(table, 0x0000024c, 0x000c01a2); // selectTask - insert_record(table, 0x000000f3, 0x000c01a7); // launchDocuments - insert_record(table, 0x000001b8, 0x000c01ab); // spellCheck - insert_record(table, 0x0000017e, 0x000c01ae); // launchKeyboardLayout - insert_record(table, 0x0000024d, 0x000c01b1); // launchScreenSaver - insert_record(table, 0x0000024f, 0x000c01cb); // launchAssistant - insert_record(table, 0x00000190, 0x000c01b7); // launchAudioBrowser - insert_record(table, 0x000000bd, 0x000c0201); // newKey - insert_record(table, 0x000000d6, 0x000c0203); // close - insert_record(table, 0x000000f2, 0x000c0207); // save - insert_record(table, 0x000000da, 0x000c0208); // print - insert_record(table, 0x000000e1, 0x000c0221); // browserSearch - insert_record(table, 0x000000b4, 0x000c0223); // browserHome - insert_record(table, 0x000000a6, 0x000c0224); // browserBack - insert_record(table, 0x000000a7, 0x000c0225); // browserForward - insert_record(table, 0x00000088, 0x000c0226); // browserStop - insert_record(table, 0x000000b5, 0x000c0227); // browserRefresh - insert_record(table, 0x000000a4, 0x000c022a); // browserFavorites - insert_record(table, 0x000001aa, 0x000c022d); // zoomIn - insert_record(table, 0x000001ab, 0x000c022e); // zoomOut - insert_record(table, 0x0000017c, 0x000c0232); // zoomToggle - insert_record(table, 0x000000be, 0x000c0279); // redo - insert_record(table, 0x000000f0, 0x000c0289); // mailReply - insert_record(table, 0x000000f1, 0x000c028b); // mailForward - insert_record(table, 0x000000ef, 0x000c028c); // mailSend - insert_record(table, 0x00000250, 0x000c029d); // keyboardLayoutSelect - insert_record(table, 0x00000080, 0x000c029f); // showAllWindows + insert_record(table, 0x00000281, 0x00000017); // privacyScreenToggle + insert_record(table, 0x00000096, 0x00010082); // sleep + insert_record(table, 0x00000097, 0x00010083); // wakeUp + insert_record(table, 0x000000eb, 0x000100b5); // displayToggleIntExt + insert_record(table, 0x00000026, 0x00070004); // keyA + insert_record(table, 0x00000038, 0x00070005); // keyB + insert_record(table, 0x00000036, 0x00070006); // keyC + insert_record(table, 0x00000028, 0x00070007); // keyD + insert_record(table, 0x0000001a, 0x00070008); // keyE + insert_record(table, 0x00000029, 0x00070009); // keyF + insert_record(table, 0x0000002a, 0x0007000a); // keyG + insert_record(table, 0x0000002b, 0x0007000b); // keyH + insert_record(table, 0x0000001f, 0x0007000c); // keyI + insert_record(table, 0x0000002c, 0x0007000d); // keyJ + insert_record(table, 0x0000002d, 0x0007000e); // keyK + insert_record(table, 0x0000002e, 0x0007000f); // keyL + insert_record(table, 0x0000003a, 0x00070010); // keyM + insert_record(table, 0x00000039, 0x00070011); // keyN + insert_record(table, 0x00000020, 0x00070012); // keyO + insert_record(table, 0x00000021, 0x00070013); // keyP + insert_record(table, 0x00000018, 0x00070014); // keyQ + insert_record(table, 0x0000001b, 0x00070015); // keyR + insert_record(table, 0x00000027, 0x00070016); // keyS + insert_record(table, 0x0000001c, 0x00070017); // keyT + insert_record(table, 0x0000001e, 0x00070018); // keyU + insert_record(table, 0x00000037, 0x00070019); // keyV + insert_record(table, 0x00000019, 0x0007001a); // keyW + insert_record(table, 0x00000035, 0x0007001b); // keyX + insert_record(table, 0x0000001d, 0x0007001c); // keyY + insert_record(table, 0x00000034, 0x0007001d); // keyZ + insert_record(table, 0x0000000a, 0x0007001e); // digit1 + insert_record(table, 0x0000000b, 0x0007001f); // digit2 + insert_record(table, 0x0000000c, 0x00070020); // digit3 + insert_record(table, 0x0000000d, 0x00070021); // digit4 + insert_record(table, 0x0000000e, 0x00070022); // digit5 + insert_record(table, 0x0000000f, 0x00070023); // digit6 + insert_record(table, 0x00000010, 0x00070024); // digit7 + insert_record(table, 0x00000011, 0x00070025); // digit8 + insert_record(table, 0x00000012, 0x00070026); // digit9 + insert_record(table, 0x00000013, 0x00070027); // digit0 + insert_record(table, 0x00000024, 0x00070028); // enter + insert_record(table, 0x00000009, 0x00070029); // escape + insert_record(table, 0x00000016, 0x0007002a); // backspace + insert_record(table, 0x00000017, 0x0007002b); // tab + insert_record(table, 0x00000041, 0x0007002c); // space + insert_record(table, 0x00000014, 0x0007002d); // minus + insert_record(table, 0x00000015, 0x0007002e); // equal + insert_record(table, 0x00000022, 0x0007002f); // bracketLeft + insert_record(table, 0x00000023, 0x00070030); // bracketRight + insert_record(table, 0x00000033, 0x00070031); // backslash + insert_record(table, 0x0000002f, 0x00070033); // semicolon + insert_record(table, 0x00000030, 0x00070034); // quote + insert_record(table, 0x00000031, 0x00070035); // backquote + insert_record(table, 0x0000003b, 0x00070036); // comma + insert_record(table, 0x0000003c, 0x00070037); // period + insert_record(table, 0x0000003d, 0x00070038); // slash + insert_record(table, 0x00000042, 0x00070039); // capsLock + insert_record(table, 0x00000043, 0x0007003a); // f1 + insert_record(table, 0x00000044, 0x0007003b); // f2 + insert_record(table, 0x00000045, 0x0007003c); // f3 + insert_record(table, 0x00000046, 0x0007003d); // f4 + insert_record(table, 0x00000047, 0x0007003e); // f5 + insert_record(table, 0x00000048, 0x0007003f); // f6 + insert_record(table, 0x00000049, 0x00070040); // f7 + insert_record(table, 0x0000004a, 0x00070041); // f8 + insert_record(table, 0x0000004b, 0x00070042); // f9 + insert_record(table, 0x0000004c, 0x00070043); // f10 + insert_record(table, 0x0000005f, 0x00070044); // f11 + insert_record(table, 0x00000060, 0x00070045); // f12 + insert_record(table, 0x0000006b, 0x00070046); // printScreen + insert_record(table, 0x0000004e, 0x00070047); // scrollLock + insert_record(table, 0x0000007f, 0x00070048); // pause + insert_record(table, 0x00000076, 0x00070049); // insert + insert_record(table, 0x0000006e, 0x0007004a); // home + insert_record(table, 0x00000070, 0x0007004b); // pageUp + insert_record(table, 0x00000077, 0x0007004c); // delete + insert_record(table, 0x00000073, 0x0007004d); // end + insert_record(table, 0x00000075, 0x0007004e); // pageDown + insert_record(table, 0x00000072, 0x0007004f); // arrowRight + insert_record(table, 0x00000071, 0x00070050); // arrowLeft + insert_record(table, 0x00000074, 0x00070051); // arrowDown + insert_record(table, 0x0000006f, 0x00070052); // arrowUp + insert_record(table, 0x0000004d, 0x00070053); // numLock + insert_record(table, 0x0000006a, 0x00070054); // numpadDivide + insert_record(table, 0x0000003f, 0x00070055); // numpadMultiply + insert_record(table, 0x00000052, 0x00070056); // numpadSubtract + insert_record(table, 0x00000056, 0x00070057); // numpadAdd + insert_record(table, 0x00000068, 0x00070058); // numpadEnter + insert_record(table, 0x00000057, 0x00070059); // numpad1 + insert_record(table, 0x00000058, 0x0007005a); // numpad2 + insert_record(table, 0x00000059, 0x0007005b); // numpad3 + insert_record(table, 0x00000053, 0x0007005c); // numpad4 + insert_record(table, 0x00000054, 0x0007005d); // numpad5 + insert_record(table, 0x00000055, 0x0007005e); // numpad6 + insert_record(table, 0x0000004f, 0x0007005f); // numpad7 + insert_record(table, 0x00000050, 0x00070060); // numpad8 + insert_record(table, 0x00000051, 0x00070061); // numpad9 + insert_record(table, 0x0000005a, 0x00070062); // numpad0 + insert_record(table, 0x0000005b, 0x00070063); // numpadDecimal + insert_record(table, 0x0000005e, 0x00070064); // intlBackslash + insert_record(table, 0x00000087, 0x00070065); // contextMenu + insert_record(table, 0x0000007c, 0x00070066); // power + insert_record(table, 0x0000007d, 0x00070067); // numpadEqual + insert_record(table, 0x000000bf, 0x00070068); // f13 + insert_record(table, 0x000000c0, 0x00070069); // f14 + insert_record(table, 0x000000c1, 0x0007006a); // f15 + insert_record(table, 0x000000c2, 0x0007006b); // f16 + insert_record(table, 0x000000c3, 0x0007006c); // f17 + insert_record(table, 0x000000c4, 0x0007006d); // f18 + insert_record(table, 0x000000c5, 0x0007006e); // f19 + insert_record(table, 0x000000c6, 0x0007006f); // f20 + insert_record(table, 0x000000c7, 0x00070070); // f21 + insert_record(table, 0x000000c8, 0x00070071); // f22 + insert_record(table, 0x000000c9, 0x00070072); // f23 + insert_record(table, 0x000000ca, 0x00070073); // f24 + insert_record(table, 0x0000008e, 0x00070074); // open + insert_record(table, 0x00000092, 0x00070075); // help + insert_record(table, 0x0000008c, 0x00070077); // select + insert_record(table, 0x00000089, 0x00070079); // again + insert_record(table, 0x0000008b, 0x0007007a); // undo + insert_record(table, 0x00000091, 0x0007007b); // cut + insert_record(table, 0x0000008d, 0x0007007c); // copy + insert_record(table, 0x0000008f, 0x0007007d); // paste + insert_record(table, 0x00000090, 0x0007007e); // find + insert_record(table, 0x00000079, 0x0007007f); // audioVolumeMute + insert_record(table, 0x0000007b, 0x00070080); // audioVolumeUp + insert_record(table, 0x0000007a, 0x00070081); // audioVolumeDown + insert_record(table, 0x00000081, 0x00070085); // numpadComma + insert_record(table, 0x00000061, 0x00070087); // intlRo + insert_record(table, 0x00000065, 0x00070088); // kanaMode + insert_record(table, 0x00000084, 0x00070089); // intlYen + insert_record(table, 0x00000064, 0x0007008a); // convert + insert_record(table, 0x00000066, 0x0007008b); // nonConvert + insert_record(table, 0x00000082, 0x00070090); // lang1 + insert_record(table, 0x00000083, 0x00070091); // lang2 + insert_record(table, 0x00000062, 0x00070092); // lang3 + insert_record(table, 0x00000063, 0x00070093); // lang4 + insert_record(table, 0x0000005d, 0x00070094); // lang5 + insert_record(table, 0x000000bb, 0x000700b6); // numpadParenLeft + insert_record(table, 0x000000bc, 0x000700b7); // numpadParenRight + insert_record(table, 0x0000007e, 0x000700d7); // numpadSignChange + insert_record(table, 0x00000025, 0x000700e0); // controlLeft + insert_record(table, 0x00000032, 0x000700e1); // shiftLeft + insert_record(table, 0x00000040, 0x000700e2); // altLeft + insert_record(table, 0x00000085, 0x000700e3); // metaLeft + insert_record(table, 0x00000069, 0x000700e4); // controlRight + insert_record(table, 0x0000003e, 0x000700e5); // shiftRight + insert_record(table, 0x0000006c, 0x000700e6); // altRight + insert_record(table, 0x00000086, 0x000700e7); // metaRight + insert_record(table, 0x0000016e, 0x000c0060); // info + insert_record(table, 0x0000017a, 0x000c0061); // closedCaptionToggle + insert_record(table, 0x000000e9, 0x000c006f); // brightnessUp + insert_record(table, 0x000000e8, 0x000c0070); // brightnessDown + insert_record(table, 0x000001b7, 0x000c0072); // brightnessToggle + insert_record(table, 0x00000258, 0x000c0073); // brightnessMinimum + insert_record(table, 0x00000259, 0x000c0074); // brightnessMaximum + insert_record(table, 0x000000fc, 0x000c0075); // brightnessAuto + insert_record(table, 0x000000ee, 0x000c0079); // kbdIllumUp + insert_record(table, 0x000000ed, 0x000c007a); // kbdIllumDown + insert_record(table, 0x0000019d, 0x000c0083); // mediaLast + insert_record(table, 0x000000b1, 0x000c008c); // launchPhone + insert_record(table, 0x00000172, 0x000c008d); // programGuide + insert_record(table, 0x000000b6, 0x000c0094); // exit + insert_record(table, 0x000001a2, 0x000c009c); // channelUp + insert_record(table, 0x000001a3, 0x000c009d); // channelDown + insert_record(table, 0x000000d7, 0x000c00b0); // mediaPlay + insert_record(table, 0x000000d1, 0x000c00b1); // mediaPause + insert_record(table, 0x000000af, 0x000c00b2); // mediaRecord + insert_record(table, 0x000000d8, 0x000c00b3); // mediaFastForward + insert_record(table, 0x000000b0, 0x000c00b4); // mediaRewind + insert_record(table, 0x000000ab, 0x000c00b5); // mediaTrackNext + insert_record(table, 0x000000ad, 0x000c00b6); // mediaTrackPrevious + insert_record(table, 0x000000ae, 0x000c00b7); // mediaStop + insert_record(table, 0x000000a9, 0x000c00b8); // eject + insert_record(table, 0x000000ac, 0x000c00cd); // mediaPlayPause + insert_record(table, 0x0000024e, 0x000c00cf); // speechInputToggle + insert_record(table, 0x000000d9, 0x000c00e5); // bassBoost + insert_record(table, 0x000000b3, 0x000c0183); // mediaSelect + insert_record(table, 0x000001ad, 0x000c0184); // launchWordProcessor + insert_record(table, 0x000001af, 0x000c0186); // launchSpreadsheet + insert_record(table, 0x000000a3, 0x000c018a); // launchMail + insert_record(table, 0x000001b5, 0x000c018d); // launchContacts + insert_record(table, 0x00000195, 0x000c018e); // launchCalendar + insert_record(table, 0x00000094, 0x000c0192); // launchApp2 + insert_record(table, 0x00000098, 0x000c0194); // launchApp1 + insert_record(table, 0x0000009e, 0x000c0196); // launchInternetBrowser + insert_record(table, 0x000001b9, 0x000c019c); // logOff + insert_record(table, 0x000000a0, 0x000c019e); // lockScreen + insert_record(table, 0x0000024b, 0x000c019f); // launchControlPanel + insert_record(table, 0x0000024c, 0x000c01a2); // selectTask + insert_record(table, 0x000000f3, 0x000c01a7); // launchDocuments + insert_record(table, 0x000001b8, 0x000c01ab); // spellCheck + insert_record(table, 0x0000017e, 0x000c01ae); // launchKeyboardLayout + insert_record(table, 0x0000024d, 0x000c01b1); // launchScreenSaver + insert_record(table, 0x0000024f, 0x000c01cb); // launchAssistant + insert_record(table, 0x00000190, 0x000c01b7); // launchAudioBrowser + insert_record(table, 0x000000bd, 0x000c0201); // newKey + insert_record(table, 0x000000d6, 0x000c0203); // close + insert_record(table, 0x000000f2, 0x000c0207); // save + insert_record(table, 0x000000da, 0x000c0208); // print + insert_record(table, 0x000000e1, 0x000c0221); // browserSearch + insert_record(table, 0x000000b4, 0x000c0223); // browserHome + insert_record(table, 0x000000a6, 0x000c0224); // browserBack + insert_record(table, 0x000000a7, 0x000c0225); // browserForward + insert_record(table, 0x00000088, 0x000c0226); // browserStop + insert_record(table, 0x000000b5, 0x000c0227); // browserRefresh + insert_record(table, 0x000000a4, 0x000c022a); // browserFavorites + insert_record(table, 0x000001aa, 0x000c022d); // zoomIn + insert_record(table, 0x000001ab, 0x000c022e); // zoomOut + insert_record(table, 0x0000017c, 0x000c0232); // zoomToggle + insert_record(table, 0x000000be, 0x000c0279); // redo + insert_record(table, 0x000000f0, 0x000c0289); // mailReply + insert_record(table, 0x000000f1, 0x000c028b); // mailForward + insert_record(table, 0x000000ef, 0x000c028c); // mailSend + insert_record(table, 0x00000250, 0x000c029d); // keyboardLayoutSelect + insert_record(table, 0x00000080, 0x000c029f); // showAllWindows } void initialize_gtk_keyval_to_logical_key(GHashTable* table) { - insert_record(table, 0x0000ff08, 0x00000008); // BackSpace - insert_record(table, 0x0000ff09, 0x00000009); // Tab - insert_record(table, 0x0000ff89, 0x00000009); // KP_Tab - insert_record(table, 0x0000fe20, 0x00000009); // ISO_Left_Tab - insert_record(table, 0x0000ff0d, 0x0000000d); // Return - insert_record(table, 0x0000fe34, 0x0000000d); // ISO_Enter - insert_record(table, 0x0000fd1e, 0x0000000d); // 3270_Enter - insert_record(table, 0x0000ff1b, 0x0000001b); // Escape - insert_record(table, 0x0000ff80, 0x00000020); // KP_Space - insert_record(table, 0x0000ffae, 0x0000002e); // KP_Decimal - insert_record(table, 0x0000ffff, 0x0000007f); // Delete - insert_record(table, 0x0000ffe5, 0x00000104); // Caps_Lock - insert_record(table, 0x0000ffed, 0x00000108); // Hyper_L - insert_record(table, 0x0000ffee, 0x00000108); // Hyper_R - insert_record(table, 0x0000ff7f, 0x0000010a); // Num_Lock - insert_record(table, 0x0000ff14, 0x0000010c); // Scroll_Lock - insert_record(table, 0x0000ffeb, 0x0000010e); // Super_L - insert_record(table, 0x0000ffec, 0x0000010e); // Super_R - insert_record(table, 0x0000ff54, 0x00000301); // Down - insert_record(table, 0x0000ff51, 0x00000302); // Left - insert_record(table, 0x0000ff53, 0x00000303); // Right - insert_record(table, 0x0000ff52, 0x00000304); // Up - insert_record(table, 0x0000ff57, 0x00000305); // End - insert_record(table, 0x0000ff50, 0x00000306); // Home - insert_record(table, 0x0000ff56, 0x00000307); // Page_Down - insert_record(table, 0x0000ff55, 0x00000308); // Page_Up - insert_record(table, 0x0000ff0b, 0x00000401); // Clear - insert_record(table, 0x0000fd15, 0x00000402); // 3270_Copy - insert_record(table, 0x1008ff57, 0x00000402); // Copy - insert_record(table, 0x1008ff58, 0x00000404); // Cut - insert_record(table, 0x0000fd06, 0x00000405); // 3270_EraseEOF - insert_record(table, 0x0000fd1b, 0x00000406); // 3270_ExSelect - insert_record(table, 0x0000ff63, 0x00000407); // Insert - insert_record(table, 0x1008ff6d, 0x00000408); // Paste - insert_record(table, 0x0000ff66, 0x00000409); // Redo - insert_record(table, 0x0000ff65, 0x0000040a); // Undo - insert_record(table, 0x0000fd0e, 0x00000503); // 3270_Attn - insert_record(table, 0x0000ff69, 0x00000504); // Cancel - insert_record(table, 0x0000ff67, 0x00000505); // Menu - insert_record(table, 0x0000ff62, 0x00000506); // Execute - insert_record(table, 0x0000ff68, 0x00000507); // Find - insert_record(table, 0x0000ff6a, 0x00000508); // Help - insert_record(table, 0x0000ff13, 0x00000509); // Pause - insert_record(table, 0x0000ff60, 0x0000050c); // Select - insert_record(table, 0x1008ff8b, 0x0000050d); // ZoomIn - insert_record(table, 0x1008ff8c, 0x0000050e); // ZoomOut - insert_record(table, 0x1008ff03, 0x00000601); // MonBrightnessDown - insert_record(table, 0x1008ff02, 0x00000602); // MonBrightnessUp - insert_record(table, 0x1008ff2c, 0x00000604); // Eject - insert_record(table, 0x1008ff61, 0x00000605); // LogOff - insert_record(table, 0x1008ff2a, 0x00000607); // PowerOff - insert_record(table, 0x0000fd1d, 0x00000608); // 3270_PrintScreen - insert_record(table, 0x1008ff10, 0x0000060a); // Standby - insert_record(table, 0x1008ff2b, 0x0000060b); // WakeUp - insert_record(table, 0x0000ff37, 0x00000703); // Codeinput - insert_record(table, 0x0000fe0c, 0x00000707); // ISO_First_Group - insert_record(table, 0x0000fe0e, 0x00000708); // ISO_Last_Group - insert_record(table, 0x0000fe08, 0x00000709); // ISO_Next_Group - insert_record(table, 0x0000fe0a, 0x0000070a); // ISO_Prev_Group - insert_record(table, 0x0000ff7e, 0x0000070b); // Mode_switch - insert_record(table, 0x0000ff3e, 0x0000070e); // PreviousCandidate - insert_record(table, 0x0000ff3c, 0x00000710); // SingleCandidate - insert_record(table, 0x0000ff31, 0x00000711); // Hangul - insert_record(table, 0x0000ff34, 0x00000712); // Hangul_Hanja - insert_record(table, 0x0000ff2f, 0x00000714); // Eisu_Shift - insert_record(table, 0x0000ff29, 0x00000715); // Hankaku - insert_record(table, 0x0000ff25, 0x00000716); // Hiragana - insert_record(table, 0x0000ff27, 0x00000717); // Hiragana_Katakana - insert_record(table, 0x0000ff7e, 0x00000718); // kana_switch - insert_record(table, 0x0000ff21, 0x00000719); // Kanji - insert_record(table, 0x0000ff26, 0x0000071a); // Katakana - insert_record(table, 0x0000ff24, 0x0000071b); // Romaji - insert_record(table, 0x0000ff28, 0x0000071c); // Zenkaku - insert_record(table, 0x0000ff2a, 0x0000071d); // Zenkaku_Hankaku - insert_record(table, 0x0000ff91, 0x00000801); // KP_F1 - insert_record(table, 0x0000ffbe, 0x00000801); // F1 - insert_record(table, 0x0000ff92, 0x00000802); // KP_F2 - insert_record(table, 0x0000ffbf, 0x00000802); // F2 - insert_record(table, 0x0000ff93, 0x00000803); // KP_F3 - insert_record(table, 0x0000ffc0, 0x00000803); // F3 - insert_record(table, 0x0000ff94, 0x00000804); // KP_F4 - insert_record(table, 0x0000ffc1, 0x00000804); // F4 - insert_record(table, 0x0000ffc2, 0x00000805); // F5 - insert_record(table, 0x0000ffc3, 0x00000806); // F6 - insert_record(table, 0x0000ffc4, 0x00000807); // F7 - insert_record(table, 0x0000ffc5, 0x00000808); // F8 - insert_record(table, 0x0000ffc6, 0x00000809); // F9 - insert_record(table, 0x0000ffc7, 0x0000080a); // F10 - insert_record(table, 0x0000ffc8, 0x0000080b); // F11 - insert_record(table, 0x0000ffc9, 0x0000080c); // F12 - insert_record(table, 0x0000ffca, 0x0000080d); // F13 - insert_record(table, 0x0000ffcb, 0x0000080e); // F14 - insert_record(table, 0x0000ffcc, 0x0000080f); // F15 - insert_record(table, 0x0000ffcd, 0x00000810); // F16 - insert_record(table, 0x0000ffce, 0x00000811); // F17 - insert_record(table, 0x0000ffcf, 0x00000812); // F18 - insert_record(table, 0x0000ffd0, 0x00000813); // F19 - insert_record(table, 0x0000ffd1, 0x00000814); // F20 - insert_record(table, 0x0000ffd2, 0x00000815); // F21 - insert_record(table, 0x0000ffd3, 0x00000816); // F22 - insert_record(table, 0x0000ffd4, 0x00000817); // F23 - insert_record(table, 0x0000ffd5, 0x00000818); // F24 - insert_record(table, 0x1008ff56, 0x00000a01); // Close - insert_record(table, 0x1008ff90, 0x00000a02); // MailForward - insert_record(table, 0x1008ff72, 0x00000a03); // Reply - insert_record(table, 0x1008ff7b, 0x00000a04); // Send - insert_record(table, 0x1008ff15, 0x00000a07); // AudioStop - insert_record(table, 0x1008ff17, 0x00000a08); // AudioNext - insert_record(table, 0x1008ff16, 0x00000a09); // AudioPrev - insert_record(table, 0x1008ff68, 0x00000a0a); // New - insert_record(table, 0x1008ff6b, 0x00000a0b); // Open - insert_record(table, 0x0000ff61, 0x00000a0c); // Print - insert_record(table, 0x1008ff77, 0x00000a0d); // Save - insert_record(table, 0x1008ff7c, 0x00000a0e); // Spell - insert_record(table, 0x1008ff11, 0x00000a0f); // AudioLowerVolume - insert_record(table, 0x1008ff13, 0x00000a10); // AudioRaiseVolume - insert_record(table, 0x1008ff12, 0x00000a11); // AudioMute - insert_record(table, 0x1008ff20, 0x00000b02); // Calendar - insert_record(table, 0x1008ff19, 0x00000b03); // Mail - insert_record(table, 0x1008ff2d, 0x00000b07); // ScreenSaver - insert_record(table, 0x1008ff6e, 0x00000b0d); // Phone - insert_record(table, 0x1008ff26, 0x00000c01); // Back - insert_record(table, 0x1008ff30, 0x00000c02); // Favorites - insert_record(table, 0x1008ff27, 0x00000c03); // Forward - insert_record(table, 0x1008ff18, 0x00000c04); // HomePage - insert_record(table, 0x1008ff29, 0x00000c05); // Refresh - insert_record(table, 0x1008ff1b, 0x00000c06); // Search - insert_record(table, 0x1008ff28, 0x00000c07); // Stop - insert_record(table, 0x1008ff97, 0x00000d2c); // AudioForward - insert_record(table, 0x1008ff31, 0x00000d2e); // AudioPause - insert_record(table, 0x0000fd16, 0x00000d2f); // 3270_Play - insert_record(table, 0x1008ff14, 0x00000d2f); // AudioPlay - insert_record(table, 0x1008ff1c, 0x00000d30); // AudioRecord - insert_record(table, 0x1008ff3e, 0x00000d31); // AudioRewind - insert_record(table, 0x1008ffa7, 0x100000014); // Suspend - insert_record(table, 0x1008ff2f, 0x100010082); // Sleep - insert_record(table, 0x0000ff8d, 0x20000000d); // KP_Enter - insert_record(table, 0x0000ffaa, 0x20000002a); // KP_Multiply - insert_record(table, 0x0000ffab, 0x20000002b); // KP_Add - insert_record(table, 0x0000ffad, 0x20000002d); // KP_Subtract - insert_record(table, 0x0000ff9f, 0x20000002e); // KP_Delete - insert_record(table, 0x0000ffaf, 0x20000002f); // KP_Divide - insert_record(table, 0x0000ff9e, 0x200000030); // KP_Insert - insert_record(table, 0x0000ffb0, 0x200000030); // KP_0 - insert_record(table, 0x0000ff9c, 0x200000031); // KP_End - insert_record(table, 0x0000ffb1, 0x200000031); // KP_1 - insert_record(table, 0x0000ff99, 0x200000032); // KP_Down - insert_record(table, 0x0000ffb2, 0x200000032); // KP_2 - insert_record(table, 0x0000ff9b, 0x200000033); // KP_Page_Down - insert_record(table, 0x0000ffb3, 0x200000033); // KP_3 - insert_record(table, 0x0000ff96, 0x200000034); // KP_Left - insert_record(table, 0x0000ffb4, 0x200000034); // KP_4 - insert_record(table, 0x0000ffb5, 0x200000035); // KP_5 - insert_record(table, 0x0000ff98, 0x200000036); // KP_Right - insert_record(table, 0x0000ffb6, 0x200000036); // KP_6 - insert_record(table, 0x0000ff95, 0x200000037); // KP_Home - insert_record(table, 0x0000ffb7, 0x200000037); // KP_7 - insert_record(table, 0x0000ff97, 0x200000038); // KP_Up - insert_record(table, 0x0000ffb8, 0x200000038); // KP_8 - insert_record(table, 0x0000ff9a, 0x200000039); // KP_Page_Up - insert_record(table, 0x0000ffb9, 0x200000039); // KP_9 - insert_record(table, 0x0000ffbd, 0x20000003d); // KP_Equal - insert_record(table, 0x0000ffe9, 0x300000102); // Alt_L - insert_record(table, 0x0000ffe3, 0x300000105); // Control_L - insert_record(table, 0x0000ffe7, 0x300000109); // Meta_L - insert_record(table, 0x0000ffe1, 0x30000010d); // Shift_L - insert_record(table, 0x0000ffea, 0x400000102); // Alt_R - insert_record(table, 0x0000ffe4, 0x400000105); // Control_R - insert_record(table, 0x0000ffe8, 0x400000109); // Meta_R - insert_record(table, 0x0000ffe2, 0x40000010d); // Shift_R + insert_record(table, 0x0000ff08, 0x00000008); // BackSpace + insert_record(table, 0x0000ff09, 0x00000009); // Tab + insert_record(table, 0x0000ff89, 0x00000009); // KP_Tab + insert_record(table, 0x0000fe20, 0x00000009); // ISO_Left_Tab + insert_record(table, 0x0000ff0d, 0x0000000d); // Return + insert_record(table, 0x0000fe34, 0x0000000d); // ISO_Enter + insert_record(table, 0x0000fd1e, 0x0000000d); // 3270_Enter + insert_record(table, 0x0000ff1b, 0x0000001b); // Escape + insert_record(table, 0x0000ff80, 0x00000020); // KP_Space + insert_record(table, 0x0000ffae, 0x0000002e); // KP_Decimal + insert_record(table, 0x0000ffff, 0x0000007f); // Delete + insert_record(table, 0x0000ffe5, 0x00000104); // Caps_Lock + insert_record(table, 0x0000ffed, 0x00000108); // Hyper_L + insert_record(table, 0x0000ffee, 0x00000108); // Hyper_R + insert_record(table, 0x0000ff7f, 0x0000010a); // Num_Lock + insert_record(table, 0x0000ff14, 0x0000010c); // Scroll_Lock + insert_record(table, 0x0000ffeb, 0x0000010e); // Super_L + insert_record(table, 0x0000ffec, 0x0000010e); // Super_R + insert_record(table, 0x0000ff54, 0x00000301); // Down + insert_record(table, 0x0000ff51, 0x00000302); // Left + insert_record(table, 0x0000ff53, 0x00000303); // Right + insert_record(table, 0x0000ff52, 0x00000304); // Up + insert_record(table, 0x0000ff57, 0x00000305); // End + insert_record(table, 0x0000ff50, 0x00000306); // Home + insert_record(table, 0x0000ff56, 0x00000307); // Page_Down + insert_record(table, 0x0000ff55, 0x00000308); // Page_Up + insert_record(table, 0x0000ff0b, 0x00000401); // Clear + insert_record(table, 0x0000fd15, 0x00000402); // 3270_Copy + insert_record(table, 0x1008ff57, 0x00000402); // Copy + insert_record(table, 0x1008ff58, 0x00000404); // Cut + insert_record(table, 0x0000fd06, 0x00000405); // 3270_EraseEOF + insert_record(table, 0x0000fd1b, 0x00000406); // 3270_ExSelect + insert_record(table, 0x0000ff63, 0x00000407); // Insert + insert_record(table, 0x1008ff6d, 0x00000408); // Paste + insert_record(table, 0x0000ff66, 0x00000409); // Redo + insert_record(table, 0x0000ff65, 0x0000040a); // Undo + insert_record(table, 0x0000fd0e, 0x00000503); // 3270_Attn + insert_record(table, 0x0000ff69, 0x00000504); // Cancel + insert_record(table, 0x0000ff67, 0x00000505); // Menu + insert_record(table, 0x0000ff62, 0x00000506); // Execute + insert_record(table, 0x0000ff68, 0x00000507); // Find + insert_record(table, 0x0000ff6a, 0x00000508); // Help + insert_record(table, 0x0000ff13, 0x00000509); // Pause + insert_record(table, 0x0000ff60, 0x0000050c); // Select + insert_record(table, 0x1008ff8b, 0x0000050d); // ZoomIn + insert_record(table, 0x1008ff8c, 0x0000050e); // ZoomOut + insert_record(table, 0x1008ff03, 0x00000601); // MonBrightnessDown + insert_record(table, 0x1008ff02, 0x00000602); // MonBrightnessUp + insert_record(table, 0x1008ff2c, 0x00000604); // Eject + insert_record(table, 0x1008ff61, 0x00000605); // LogOff + insert_record(table, 0x1008ff2a, 0x00000607); // PowerOff + insert_record(table, 0x0000fd1d, 0x00000608); // 3270_PrintScreen + insert_record(table, 0x1008ff10, 0x0000060a); // Standby + insert_record(table, 0x1008ff2b, 0x0000060b); // WakeUp + insert_record(table, 0x0000ff37, 0x00000703); // Codeinput + insert_record(table, 0x0000fe0c, 0x00000707); // ISO_First_Group + insert_record(table, 0x0000fe0e, 0x00000708); // ISO_Last_Group + insert_record(table, 0x0000fe08, 0x00000709); // ISO_Next_Group + insert_record(table, 0x0000fe0a, 0x0000070a); // ISO_Prev_Group + insert_record(table, 0x0000ff7e, 0x0000070b); // Mode_switch + insert_record(table, 0x0000ff3e, 0x0000070e); // PreviousCandidate + insert_record(table, 0x0000ff3c, 0x00000710); // SingleCandidate + insert_record(table, 0x0000ff31, 0x00000711); // Hangul + insert_record(table, 0x0000ff34, 0x00000712); // Hangul_Hanja + insert_record(table, 0x0000ff2f, 0x00000714); // Eisu_Shift + insert_record(table, 0x0000ff29, 0x00000715); // Hankaku + insert_record(table, 0x0000ff25, 0x00000716); // Hiragana + insert_record(table, 0x0000ff27, 0x00000717); // Hiragana_Katakana + insert_record(table, 0x0000ff7e, 0x00000718); // kana_switch + insert_record(table, 0x0000ff21, 0x00000719); // Kanji + insert_record(table, 0x0000ff26, 0x0000071a); // Katakana + insert_record(table, 0x0000ff24, 0x0000071b); // Romaji + insert_record(table, 0x0000ff28, 0x0000071c); // Zenkaku + insert_record(table, 0x0000ff2a, 0x0000071d); // Zenkaku_Hankaku + insert_record(table, 0x0000ff91, 0x00000801); // KP_F1 + insert_record(table, 0x0000ffbe, 0x00000801); // F1 + insert_record(table, 0x0000ff92, 0x00000802); // KP_F2 + insert_record(table, 0x0000ffbf, 0x00000802); // F2 + insert_record(table, 0x0000ff93, 0x00000803); // KP_F3 + insert_record(table, 0x0000ffc0, 0x00000803); // F3 + insert_record(table, 0x0000ff94, 0x00000804); // KP_F4 + insert_record(table, 0x0000ffc1, 0x00000804); // F4 + insert_record(table, 0x0000ffc2, 0x00000805); // F5 + insert_record(table, 0x0000ffc3, 0x00000806); // F6 + insert_record(table, 0x0000ffc4, 0x00000807); // F7 + insert_record(table, 0x0000ffc5, 0x00000808); // F8 + insert_record(table, 0x0000ffc6, 0x00000809); // F9 + insert_record(table, 0x0000ffc7, 0x0000080a); // F10 + insert_record(table, 0x0000ffc8, 0x0000080b); // F11 + insert_record(table, 0x0000ffc9, 0x0000080c); // F12 + insert_record(table, 0x0000ffca, 0x0000080d); // F13 + insert_record(table, 0x0000ffcb, 0x0000080e); // F14 + insert_record(table, 0x0000ffcc, 0x0000080f); // F15 + insert_record(table, 0x0000ffcd, 0x00000810); // F16 + insert_record(table, 0x0000ffce, 0x00000811); // F17 + insert_record(table, 0x0000ffcf, 0x00000812); // F18 + insert_record(table, 0x0000ffd0, 0x00000813); // F19 + insert_record(table, 0x0000ffd1, 0x00000814); // F20 + insert_record(table, 0x0000ffd2, 0x00000815); // F21 + insert_record(table, 0x0000ffd3, 0x00000816); // F22 + insert_record(table, 0x0000ffd4, 0x00000817); // F23 + insert_record(table, 0x0000ffd5, 0x00000818); // F24 + insert_record(table, 0x1008ff56, 0x00000a01); // Close + insert_record(table, 0x1008ff90, 0x00000a02); // MailForward + insert_record(table, 0x1008ff72, 0x00000a03); // Reply + insert_record(table, 0x1008ff7b, 0x00000a04); // Send + insert_record(table, 0x1008ff15, 0x00000a07); // AudioStop + insert_record(table, 0x1008ff17, 0x00000a08); // AudioNext + insert_record(table, 0x1008ff16, 0x00000a09); // AudioPrev + insert_record(table, 0x1008ff68, 0x00000a0a); // New + insert_record(table, 0x1008ff6b, 0x00000a0b); // Open + insert_record(table, 0x0000ff61, 0x00000a0c); // Print + insert_record(table, 0x1008ff77, 0x00000a0d); // Save + insert_record(table, 0x1008ff7c, 0x00000a0e); // Spell + insert_record(table, 0x1008ff11, 0x00000a0f); // AudioLowerVolume + insert_record(table, 0x1008ff13, 0x00000a10); // AudioRaiseVolume + insert_record(table, 0x1008ff12, 0x00000a11); // AudioMute + insert_record(table, 0x1008ff20, 0x00000b02); // Calendar + insert_record(table, 0x1008ff19, 0x00000b03); // Mail + insert_record(table, 0x1008ff2d, 0x00000b07); // ScreenSaver + insert_record(table, 0x1008ff6e, 0x00000b0d); // Phone + insert_record(table, 0x1008ff26, 0x00000c01); // Back + insert_record(table, 0x1008ff30, 0x00000c02); // Favorites + insert_record(table, 0x1008ff27, 0x00000c03); // Forward + insert_record(table, 0x1008ff18, 0x00000c04); // HomePage + insert_record(table, 0x1008ff29, 0x00000c05); // Refresh + insert_record(table, 0x1008ff1b, 0x00000c06); // Search + insert_record(table, 0x1008ff28, 0x00000c07); // Stop + insert_record(table, 0x1008ff97, 0x00000d2c); // AudioForward + insert_record(table, 0x1008ff31, 0x00000d2e); // AudioPause + insert_record(table, 0x0000fd16, 0x00000d2f); // 3270_Play + insert_record(table, 0x1008ff14, 0x00000d2f); // AudioPlay + insert_record(table, 0x1008ff1c, 0x00000d30); // AudioRecord + insert_record(table, 0x1008ff3e, 0x00000d31); // AudioRewind + insert_record(table, 0x1008ffa7, 0x100000014); // Suspend + insert_record(table, 0x1008ff2f, 0x100010082); // Sleep + insert_record(table, 0x0000ff8d, 0x20000000d); // KP_Enter + insert_record(table, 0x0000ffaa, 0x20000002a); // KP_Multiply + insert_record(table, 0x0000ffab, 0x20000002b); // KP_Add + insert_record(table, 0x0000ffad, 0x20000002d); // KP_Subtract + insert_record(table, 0x0000ff9f, 0x20000002e); // KP_Delete + insert_record(table, 0x0000ffaf, 0x20000002f); // KP_Divide + insert_record(table, 0x0000ff9e, 0x200000030); // KP_Insert + insert_record(table, 0x0000ffb0, 0x200000030); // KP_0 + insert_record(table, 0x0000ff9c, 0x200000031); // KP_End + insert_record(table, 0x0000ffb1, 0x200000031); // KP_1 + insert_record(table, 0x0000ff99, 0x200000032); // KP_Down + insert_record(table, 0x0000ffb2, 0x200000032); // KP_2 + insert_record(table, 0x0000ff9b, 0x200000033); // KP_Page_Down + insert_record(table, 0x0000ffb3, 0x200000033); // KP_3 + insert_record(table, 0x0000ff96, 0x200000034); // KP_Left + insert_record(table, 0x0000ffb4, 0x200000034); // KP_4 + insert_record(table, 0x0000ffb5, 0x200000035); // KP_5 + insert_record(table, 0x0000ff98, 0x200000036); // KP_Right + insert_record(table, 0x0000ffb6, 0x200000036); // KP_6 + insert_record(table, 0x0000ff95, 0x200000037); // KP_Home + insert_record(table, 0x0000ffb7, 0x200000037); // KP_7 + insert_record(table, 0x0000ff97, 0x200000038); // KP_Up + insert_record(table, 0x0000ffb8, 0x200000038); // KP_8 + insert_record(table, 0x0000ff9a, 0x200000039); // KP_Page_Up + insert_record(table, 0x0000ffb9, 0x200000039); // KP_9 + insert_record(table, 0x0000ffbd, 0x20000003d); // KP_Equal + insert_record(table, 0x0000ffe9, 0x300000102); // Alt_L + insert_record(table, 0x0000ffe3, 0x300000105); // Control_L + insert_record(table, 0x0000ffe7, 0x300000109); // Meta_L + insert_record(table, 0x0000ffe1, 0x30000010d); // Shift_L + insert_record(table, 0x0000ffea, 0x400000102); // Alt_R + insert_record(table, 0x0000ffe4, 0x400000105); // Control_R + insert_record(table, 0x0000ffe8, 0x400000109); // Meta_R + insert_record(table, 0x0000ffe2, 0x40000010d); // Shift_R } diff --git a/shell/platform/windows/keyboard_key_embedder_handler.cc b/shell/platform/windows/keyboard_key_embedder_handler.cc index 84ee0a100cd61..ec1c5402ad2bc 100644 --- a/shell/platform/windows/keyboard_key_embedder_handler.cc +++ b/shell/platform/windows/keyboard_key_embedder_handler.cc @@ -39,6 +39,8 @@ constexpr uint64_t kHidPlane = 0x00100000000; constexpr uint64_t kUnicodePlane = 0x00000000000; /** + * The code prefix for keys from Windows which do not have a Unicode + * representation. */ constexpr uint64_t kWindowsKeyIdPlane = 0x00700000000; From 6cc9b08cf6a54f4c689687016710e8dd4ee1434b Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Sat, 10 Apr 2021 15:18:34 -0700 Subject: [PATCH 021/126] Compile test --- .../linux/fl_key_embedder_responder_test.cc | 90 ++++++++----------- 1 file changed, 39 insertions(+), 51 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index 014014208d6ad..d77a425ea9755 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -11,10 +11,16 @@ #include "flutter/shell/platform/linux/fl_engine_private.h" #include "flutter/shell/platform/linux/testing/fl_test.h" -static const char* expected_value = nullptr; static gboolean expected_handled = FALSE; namespace { +constexpr guint16 kKeyCodeKeyA = 0x26u; +// constexpr guint16 kKeyCodeKeyB = 0x38u; + +static GdkEventKey* GDK_EVENT_KEY(gpointer pointer) { + return reinterpret_cast(pointer); +} + G_DECLARE_FINAL_TYPE(FlKeyboardCallRecord, fl_keyboard_call_record, FL, @@ -74,6 +80,32 @@ static FlKeyboardCallRecord* fl_keyboard_call_record_new( return self; } +// A global variable to store new event. It is a global variable so that it can +// be returned by key_event_new, which does not properly release this event. +// It is reused by different key_event_new calls. +GdkEventKey* _g_key_event; + +static GdkEventKey* key_event_new(gboolean is_down, + guint keyval, + guint16 hardware_keycode, + guint state, + gboolean is_modifier) { + if (_g_key_event == nullptr) + _g_key_event = GDK_EVENT_KEY(gdk_event_new(GDK_KEY_PRESS)); + _g_key_event->type = is_down ? GDK_KEY_PRESS : GDK_KEY_RELEASE; + _g_key_event->window = nullptr; + _g_key_event->send_event = FALSE; + _g_key_event->time = 12345; + _g_key_event->state = state; + _g_key_event->keyval = keyval; + _g_key_event->length = 0; + _g_key_event->string = nullptr; + _g_key_event->hardware_keycode = hardware_keycode; + _g_key_event->group = 0; + _g_key_event->is_modifier = is_modifier ? 1 : 0; + return _g_key_event; +} + static void responder_callback(bool handled, gpointer user_data) { EXPECT_EQ(handled, expected_handled); g_main_loop_quit(static_cast(user_data)); @@ -81,7 +113,7 @@ static void responder_callback(bool handled, gpointer user_data) { // Test sending a letter "A"; TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { - g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); + // g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); g_autoptr(GPtrArray) call_records = g_ptr_array_new_with_free_func(g_object_unref); @@ -101,56 +133,12 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { g_autoptr(FlKeyResponder) responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); - char string[] = "A"; - GdkEventKey key_event = GdkEventKey{ - GDK_KEY_PRESS, // event type - nullptr, // window (not needed) - FALSE, // event was sent explicitly - 12345, // time - 0x0, // modifier state - GDK_KEY_A, // key code - 1, // length of string representation - reinterpret_cast(&string[0]), // string representation - 0x04, // scan code - 0, // keyboard group - 0, // is a modifier - }; - // printf("Test 1 %s\n", expected_value);fflush(stdout); - fl_key_responder_handle_event(responder, &key_event, responder_callback, - loop); - // printf("Test 2 %s\n", expected_value);fflush(stdout); - expected_value = - "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, keyCode: 65, " - "modifiers: 0, unicodeScalarValues: 65}"; - expected_handled = FALSE; - - // Blocks here until echo_response_cb is called. - g_main_loop_run(loop); - - key_event = GdkEventKey{ - GDK_KEY_RELEASE, // event type - nullptr, // window (not needed) - FALSE, // event was sent explicitly - 23456, // time - 0x0, // modifier state - GDK_KEY_A, // key code - 1, // length of string representation - reinterpret_cast(&string[0]), // string representation - 0x04, // scan code - 0, // keyboard group - 0, // is a modifier - }; - - fl_key_responder_handle_event(responder, &key_event, responder_callback, - loop); - expected_value = - "{type: keyup, keymap: linux, scanCode: 4, toolkit: gtk, keyCode: 65, " - "modifiers: 0, unicodeScalarValues: 65}"; - expected_handled = FALSE; - - // Blocks here until echo_response_cb is called. - g_main_loop_run(loop); + fl_key_responder_handle_event(responder, + key_event_new(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false), + responder_callback, nullptr); + + EXPECT_EQ(call_records->len, 1u); } } // namespace From a5bef693eab94e1944af3826f1966b351069c50d Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 12 Apr 2021 01:11:33 -0700 Subject: [PATCH 022/126] Rename --- .../linux/fl_key_channel_responder.cc | 48 +++++++++---------- .../linux/fl_key_embedder_responder.cc | 48 +++++++++---------- .../linux/fl_key_embedder_responder_test.cc | 38 +++++++-------- 3 files changed, 67 insertions(+), 67 deletions(-) diff --git a/shell/platform/linux/fl_key_channel_responder.cc b/shell/platform/linux/fl_key_channel_responder.cc index e9274c46afb96..11acb93e8cf4b 100644 --- a/shell/platform/linux/fl_key_channel_responder.cc +++ b/shell/platform/linux/fl_key_channel_responder.cc @@ -55,13 +55,13 @@ static void fl_key_channel_responder_iface_init( } // Declare and define a private class to hold response data from the framework. -G_DECLARE_FINAL_TYPE(FlKeyEventResponseData, - fl_key_event_response_data, +G_DECLARE_FINAL_TYPE(FlKeyChannelUserData, + fl_key_channel_user_data, FL, - KEY_EVENT_RESPONSE_DATA, + KEY_CHANNEL_USER_DATA, GObject); -struct _FlKeyEventResponseData { +struct _FlKeyChannelUserData { GObject parent_instance; FlKeyChannelResponder* responder; @@ -69,13 +69,13 @@ struct _FlKeyEventResponseData { gpointer user_data; }; -// Definition for FlKeyEventResponseData private class. -G_DEFINE_TYPE(FlKeyEventResponseData, fl_key_event_response_data, G_TYPE_OBJECT) +// Definition for FlKeyChannelUserData private class. +G_DEFINE_TYPE(FlKeyChannelUserData, fl_key_channel_user_data, G_TYPE_OBJECT) -// Dispose method for FlKeyEventResponseData private class. -static void fl_key_event_response_data_dispose(GObject* object) { - g_return_if_fail(FL_IS_KEY_EVENT_RESPONSE_DATA(object)); - FlKeyEventResponseData* self = FL_KEY_EVENT_RESPONSE_DATA(object); +// Dispose method for FlKeyChannelUserData private class. +static void fl_key_channel_user_data_dispose(GObject* object) { + g_return_if_fail(FL_IS_KEY_CHANNEL_USER_DATA(object)); + FlKeyChannelUserData* self = FL_KEY_CHANNEL_USER_DATA(object); if (self->responder != nullptr) { g_object_remove_weak_pointer( G_OBJECT(self->responder), @@ -84,24 +84,24 @@ static void fl_key_event_response_data_dispose(GObject* object) { } } -// Class initialization method for FlKeyEventResponseData private class. -static void fl_key_event_response_data_class_init( - FlKeyEventResponseDataClass* klass) { - G_OBJECT_CLASS(klass)->dispose = fl_key_event_response_data_dispose; +// Class initialization method for FlKeyChannelUserData private class. +static void fl_key_channel_user_data_class_init( + FlKeyChannelUserDataClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_key_channel_user_data_dispose; } -// Instance initialization method for FlKeyEventResponseData private class. -static void fl_key_event_response_data_init(FlKeyEventResponseData* self) {} +// Instance initialization method for FlKeyChannelUserData private class. +static void fl_key_channel_user_data_init(FlKeyChannelUserData* self) {} -// Creates a new FlKeyEventResponseData private class with a responder that +// Creates a new FlKeyChannelUserData private class with a responder that // created the request, a unique ID for tracking, and optional user data. Will // keep a weak pointer to the responder. -static FlKeyEventResponseData* fl_key_event_response_data_new( +static FlKeyChannelUserData* fl_key_channel_user_data_new( FlKeyChannelResponder* responder, FlKeyResponderAsyncCallback callback, gpointer user_data) { - FlKeyEventResponseData* self = FL_KEY_EVENT_RESPONSE_DATA( - g_object_new(fl_key_event_response_data_get_type(), nullptr)); + FlKeyChannelUserData* self = FL_KEY_CHANNEL_USER_DATA( + g_object_new(fl_key_channel_user_data_get_type(), nullptr)); self->responder = responder; // Add a weak pointer so we can know if the key event responder disappeared @@ -118,8 +118,8 @@ static FlKeyEventResponseData* fl_key_event_response_data_new( static void handle_response(GObject* object, GAsyncResult* result, gpointer user_data) { - g_autoptr(FlKeyEventResponseData) data = - FL_KEY_EVENT_RESPONSE_DATA(user_data); + g_autoptr(FlKeyChannelUserData) data = + FL_KEY_CHANNEL_USER_DATA(user_data); // Will also return if the weak pointer has been destroyed. if (data->responder == nullptr) { @@ -274,8 +274,8 @@ static void fl_key_channel_responder_handle_event( fl_value_new_int(unicodeScalarValues)); } - FlKeyEventResponseData* data = - fl_key_event_response_data_new(self, callback, user_data); + FlKeyChannelUserData* data = + fl_key_channel_user_data_new(self, callback, user_data); // Send the message off to the framework for handling (or not). fl_basic_message_channel_send(self->channel, message, nullptr, handle_response, data); diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index 618759933a666..f96047679d9e7 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -23,13 +23,13 @@ constexpr uint64_t kLinuxKeyIdPlane = 0x00600000000; constexpr uint64_t kMicrosecondsPerMillisecond = 1000; // Declare and define a private class to hold response data from the framework. -G_DECLARE_FINAL_TYPE(FlKeyEventResponseData, - fl_key_event_response_data, +G_DECLARE_FINAL_TYPE(FlKeyEmbedderUserData, + fl_key_embedder_user_data, FL, - KEY_EVENT_RESPONSE_DATA, + KEY_EMBEDDER_USER_DATA, GObject); -struct _FlKeyEventResponseData { +struct _FlKeyEmbedderUserData { GObject parent_instance; FlKeyEmbedderResponder* responder; @@ -37,13 +37,13 @@ struct _FlKeyEventResponseData { gpointer user_data; }; -// Definition for FlKeyEventResponseData private class. -G_DEFINE_TYPE(FlKeyEventResponseData, fl_key_event_response_data, G_TYPE_OBJECT) +// Definition for FlKeyEmbedderUserData private class. +G_DEFINE_TYPE(FlKeyEmbedderUserData, fl_key_embedder_user_data, G_TYPE_OBJECT) -// Dispose method for FlKeyEventResponseData private class. -static void fl_key_event_response_data_dispose(GObject* object) { - g_return_if_fail(FL_IS_KEY_EVENT_RESPONSE_DATA(object)); - FlKeyEventResponseData* self = FL_KEY_EVENT_RESPONSE_DATA(object); +// Dispose method for FlKeyEmbedderUserData private class. +static void fl_key_embedder_user_data_dispose(GObject* object) { + g_return_if_fail(FL_IS_KEY_EMBEDDER_USER_DATA(object)); + FlKeyEmbedderUserData* self = FL_KEY_EMBEDDER_USER_DATA(object); if (self->responder != nullptr) { g_object_remove_weak_pointer( G_OBJECT(self->responder), @@ -52,24 +52,24 @@ static void fl_key_event_response_data_dispose(GObject* object) { } } -// Class initialization method for FlKeyEventResponseData private class. -static void fl_key_event_response_data_class_init( - FlKeyEventResponseDataClass* klass) { - G_OBJECT_CLASS(klass)->dispose = fl_key_event_response_data_dispose; +// Class initialization method for FlKeyEmbedderUserData private class. +static void fl_key_embedder_user_data_class_init( + FlKeyEmbedderUserDataClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_key_embedder_user_data_dispose; } -// Instance initialization method for FlKeyEventResponseData private class. -static void fl_key_event_response_data_init(FlKeyEventResponseData* self) {} +// Instance initialization method for FlKeyEmbedderUserData private class. +static void fl_key_embedder_user_data_init(FlKeyEmbedderUserData* self) {} -// Creates a new FlKeyEventResponseData private class with a responder that +// Creates a new FlKeyEmbedderUserData private class with a responder that // created the request, a unique ID for tracking, and optional user data. Will // keep a weak pointer to the responder. -static FlKeyEventResponseData* fl_key_event_response_data_new( +static FlKeyEmbedderUserData* fl_key_embedder_user_data_new( FlKeyEmbedderResponder* responder, FlKeyResponderAsyncCallback callback, gpointer user_data) { - FlKeyEventResponseData* self = FL_KEY_EVENT_RESPONSE_DATA( - g_object_new(fl_key_event_response_data_get_type(), nullptr)); + FlKeyEmbedderUserData* self = FL_KEY_EMBEDDER_USER_DATA( + g_object_new(fl_key_embedder_user_data_get_type(), nullptr)); self->responder = responder; // Add a weak pointer so we can know if the key event responder disappeared @@ -238,8 +238,8 @@ static uint64_t pressed_logical_for_physical(GHashTable* pressing_records, // Handles a response from the framework to a key event sent to the framework // earlier. static void handle_response(bool handled, gpointer user_data) { - g_autoptr(FlKeyEventResponseData) data = - FL_KEY_EVENT_RESPONSE_DATA(user_data); + g_autoptr(FlKeyEmbedderUserData) data = + FL_KEY_EMBEDDER_USER_DATA(user_data); // Return if the weak pointer has been destroyed. if (data->responder == nullptr) { @@ -313,8 +313,8 @@ static void fl_key_embedder_responder_handle_event( out_event.logical = logical_key; } - FlKeyEventResponseData* response_data = - fl_key_event_response_data_new(self, callback, user_data); + FlKeyEmbedderUserData* response_data = + fl_key_embedder_user_data_new(self, callback, user_data); fl_engine_send_key_event(self->engine, &out_event, handle_response, response_data); diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index d77a425ea9755..e87ec384f55ec 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -21,13 +21,13 @@ static GdkEventKey* GDK_EVENT_KEY(gpointer pointer) { return reinterpret_cast(pointer); } -G_DECLARE_FINAL_TYPE(FlKeyboardCallRecord, - fl_keyboard_call_record, +G_DECLARE_FINAL_TYPE(FlKeyEmbedderCallRecord, + fl_key_embedder_call_record, FL, - KEYBOARD_CALL_RECORD, + KEY_EMBEDDER_CALL_RECORD, GObject); -struct _FlKeyboardCallRecord { +struct _FlKeyEmbedderCallRecord { GObject parent_instance; FlutterKeyEvent* event; @@ -35,36 +35,36 @@ struct _FlKeyboardCallRecord { gpointer user_data; }; -G_DEFINE_TYPE(FlKeyboardCallRecord, fl_keyboard_call_record, G_TYPE_OBJECT) +G_DEFINE_TYPE(FlKeyEmbedderCallRecord, fl_key_embedder_call_record, G_TYPE_OBJECT) -static void fl_keyboard_call_record_init(FlKeyboardCallRecord* self) {} +static void fl_key_embedder_call_record_init(FlKeyEmbedderCallRecord* self) {} -// Dispose method for FlKeyboardCallRecord. -static void fl_keyboard_call_record_dispose(GObject* object) { - g_return_if_fail(FL_IS_KEYBOARD_CALL_RECORD(object)); +// Dispose method for FlKeyEmbedderCallRecord. +static void fl_key_embedder_call_record_dispose(GObject* object) { + g_return_if_fail(FL_IS_KEY_EMBEDDER_CALL_RECORD(object)); - FlKeyboardCallRecord* self = FL_KEYBOARD_CALL_RECORD(object); + FlKeyEmbedderCallRecord* self = FL_KEY_EMBEDDER_CALL_RECORD(object); if (self->event != nullptr) { g_free(const_cast(self->event->character)); g_free(self->event); } - G_OBJECT_CLASS(fl_keyboard_call_record_parent_class)->dispose(object); + G_OBJECT_CLASS(fl_key_embedder_call_record_parent_class)->dispose(object); } -// Class Initialization method for FlKeyboardCallRecord class. -static void fl_keyboard_call_record_class_init( - FlKeyboardCallRecordClass* klass) { - G_OBJECT_CLASS(klass)->dispose = fl_keyboard_call_record_dispose; +// Class Initialization method for FlKeyEmbedderCallRecord class. +static void fl_key_embedder_call_record_class_init( + FlKeyEmbedderCallRecordClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_key_embedder_call_record_dispose; } -static FlKeyboardCallRecord* fl_keyboard_call_record_new( +static FlKeyEmbedderCallRecord* fl_key_embedder_call_record_new( const FlutterKeyEvent* event, FlutterKeyEventCallback callback, gpointer user_data) { g_return_val_if_fail(event != nullptr, nullptr); - FlKeyboardCallRecord* self = FL_KEYBOARD_CALL_RECORD( - g_object_new(fl_keyboard_call_record_get_type(), nullptr)); + FlKeyEmbedderCallRecord* self = FL_KEY_EMBEDDER_CALL_RECORD( + g_object_new(fl_key_embedder_call_record_get_type(), nullptr)); FlutterKeyEvent* clone_event = g_new(FlutterKeyEvent, 1); *clone_event = *event; @@ -124,7 +124,7 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { SendKeyEvent, ([&call_records](auto engine, const FlutterKeyEvent* event, FlutterKeyEventCallback callback, void* user_data) -> FlutterEngineResult { - g_ptr_array_add(call_records, fl_keyboard_call_record_new( + g_ptr_array_add(call_records, fl_key_embedder_call_record_new( event, callback, user_data)); return kSuccess; From 4cff9aeb4b11c298c43e1078dd0c87fd5fa3d98d Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 12 Apr 2021 03:37:23 -0700 Subject: [PATCH 023/126] Barely running --- .../linux/fl_key_channel_responder.cc | 3 +- .../linux/fl_key_embedder_responder.cc | 3 +- .../linux/fl_key_embedder_responder_test.cc | 68 ++++++++++--------- shell/platform/linux/testing/mock_engine.cc | 9 +++ 4 files changed, 48 insertions(+), 35 deletions(-) diff --git a/shell/platform/linux/fl_key_channel_responder.cc b/shell/platform/linux/fl_key_channel_responder.cc index 11acb93e8cf4b..1b2c123fa766e 100644 --- a/shell/platform/linux/fl_key_channel_responder.cc +++ b/shell/platform/linux/fl_key_channel_responder.cc @@ -118,8 +118,7 @@ static FlKeyChannelUserData* fl_key_channel_user_data_new( static void handle_response(GObject* object, GAsyncResult* result, gpointer user_data) { - g_autoptr(FlKeyChannelUserData) data = - FL_KEY_CHANNEL_USER_DATA(user_data); + g_autoptr(FlKeyChannelUserData) data = FL_KEY_CHANNEL_USER_DATA(user_data); // Will also return if the weak pointer has been destroyed. if (data->responder == nullptr) { diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index f96047679d9e7..95ee16697c83a 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -238,8 +238,7 @@ static uint64_t pressed_logical_for_physical(GHashTable* pressing_records, // Handles a response from the framework to a key event sent to the framework // earlier. static void handle_response(bool handled, gpointer user_data) { - g_autoptr(FlKeyEmbedderUserData) data = - FL_KEY_EMBEDDER_USER_DATA(user_data); + g_autoptr(FlKeyEmbedderUserData) data = FL_KEY_EMBEDDER_USER_DATA(user_data); // Return if the weak pointer has been destroyed. if (data->responder == nullptr) { diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index e87ec384f55ec..1b13f54a7ad4c 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -13,14 +13,9 @@ static gboolean expected_handled = FALSE; -namespace { constexpr guint16 kKeyCodeKeyA = 0x26u; // constexpr guint16 kKeyCodeKeyB = 0x38u; -static GdkEventKey* GDK_EVENT_KEY(gpointer pointer) { - return reinterpret_cast(pointer); -} - G_DECLARE_FINAL_TYPE(FlKeyEmbedderCallRecord, fl_key_embedder_call_record, FL, @@ -35,7 +30,9 @@ struct _FlKeyEmbedderCallRecord { gpointer user_data; }; -G_DEFINE_TYPE(FlKeyEmbedderCallRecord, fl_key_embedder_call_record, G_TYPE_OBJECT) +G_DEFINE_TYPE(FlKeyEmbedderCallRecord, + fl_key_embedder_call_record, + G_TYPE_OBJECT) static void fl_key_embedder_call_record_init(FlKeyEmbedderCallRecord* self) {} @@ -80,30 +77,29 @@ static FlKeyEmbedderCallRecord* fl_key_embedder_call_record_new( return self; } +namespace { // A global variable to store new event. It is a global variable so that it can -// be returned by key_event_new, which does not properly release this event. -// It is reused by different key_event_new calls. -GdkEventKey* _g_key_event; +// be returned by key_event_new for easy use. +GdkEventKey _g_key_event; +} // namespace static GdkEventKey* key_event_new(gboolean is_down, guint keyval, guint16 hardware_keycode, guint state, gboolean is_modifier) { - if (_g_key_event == nullptr) - _g_key_event = GDK_EVENT_KEY(gdk_event_new(GDK_KEY_PRESS)); - _g_key_event->type = is_down ? GDK_KEY_PRESS : GDK_KEY_RELEASE; - _g_key_event->window = nullptr; - _g_key_event->send_event = FALSE; - _g_key_event->time = 12345; - _g_key_event->state = state; - _g_key_event->keyval = keyval; - _g_key_event->length = 0; - _g_key_event->string = nullptr; - _g_key_event->hardware_keycode = hardware_keycode; - _g_key_event->group = 0; - _g_key_event->is_modifier = is_modifier ? 1 : 0; - return _g_key_event; + _g_key_event.type = is_down ? GDK_KEY_PRESS : GDK_KEY_RELEASE; + _g_key_event.window = nullptr; + _g_key_event.send_event = FALSE; + _g_key_event.time = 12345; + _g_key_event.state = state; + _g_key_event.keyval = keyval; + _g_key_event.length = 0; + _g_key_event.string = nullptr; + _g_key_event.hardware_keycode = hardware_keycode; + _g_key_event.group = 0; + _g_key_event.is_modifier = is_modifier ? 1 : 0; + return &_g_key_event; } static void responder_callback(bool handled, gpointer user_data) { @@ -111,6 +107,16 @@ static void responder_callback(bool handled, gpointer user_data) { g_main_loop_quit(static_cast(user_data)); } +TEST(FlKeyEmbedderResponderTest, NeedThisToWork) { + g_autoptr(FlEngine) engine = make_mock_engine(); + FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); + + embedder_api->DispatchSemanticsAction = MOCK_ENGINE_PROC( + DispatchSemanticsAction, + ([](auto engine, uint64_t id, FlutterSemanticsAction action, + const uint8_t* data, size_t data_length) { return kSuccess; })); +} + // Test sending a letter "A"; TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { // g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); @@ -121,12 +127,14 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); embedder_api->SendKeyEvent = MOCK_ENGINE_PROC( - SendKeyEvent, ([&call_records](auto engine, const FlutterKeyEvent* event, - FlutterKeyEventCallback callback, - void* user_data) -> FlutterEngineResult { + SendKeyEvent, + ([&call_records](auto engine, const FlutterKeyEvent* event, + FlutterKeyEventCallback callback, void* user_data) { + // printf("Callback: before add %d\n", len); g_ptr_array_add(call_records, fl_key_embedder_call_record_new( event, callback, user_data)); + // printf("Callback: before return\n"); return kSuccess; })); @@ -134,11 +142,9 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); // printf("Test 1 %s\n", expected_value);fflush(stdout); - fl_key_responder_handle_event(responder, - key_event_new(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false), - responder_callback, nullptr); + fl_key_responder_handle_event( + responder, key_event_new(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false), + responder_callback, nullptr); EXPECT_EQ(call_records->len, 1u); } - -} // namespace diff --git a/shell/platform/linux/testing/mock_engine.cc b/shell/platform/linux/testing/mock_engine.cc index 516adae3c3345..fc748b69c128b 100644 --- a/shell/platform/linux/testing/mock_engine.cc +++ b/shell/platform/linux/testing/mock_engine.cc @@ -226,6 +226,14 @@ FlutterEngineResult FlutterEngineSendPointerEvent( return kSuccess; } +FlutterEngineResult FlutterEngineSendKeyEvent(FLUTTER_API_SYMBOL(FlutterEngine) + engine, + const FlutterKeyEvent* event, + FlutterKeyEventCallback callback, + void* user_data) { + return kSuccess; +} + FLUTTER_EXPORT FlutterEngineResult FlutterEngineSendPlatformMessage( FLUTTER_API_SYMBOL(FlutterEngine) engine, @@ -481,6 +489,7 @@ FlutterEngineResult FlutterEngineGetProcAddresses( table->RunInitialized = &FlutterEngineRunInitialized; table->SendWindowMetricsEvent = &FlutterEngineSendWindowMetricsEvent; table->SendPointerEvent = &FlutterEngineSendPointerEvent; + table->SendKeyEvent = &FlutterEngineSendKeyEvent; table->SendPlatformMessage = &FlutterEngineSendPlatformMessage; table->PlatformMessageCreateResponseHandle = &FlutterPlatformMessageCreateResponseHandle; From 7c0c2cac5665b157b942ecdccd84be4201922221 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 12 Apr 2021 15:18:06 -0700 Subject: [PATCH 024/126] Down event --- .../linux/fl_key_embedder_responder_test.cc | 88 ++++++++++++------- 1 file changed, 56 insertions(+), 32 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index 1b13f54a7ad4c..21e193d6e6413 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -13,9 +13,25 @@ static gboolean expected_handled = FALSE; +namespace { constexpr guint16 kKeyCodeKeyA = 0x26u; // constexpr guint16 kKeyCodeKeyB = 0x38u; +constexpr uint64_t kPhysicalKeyA = 0x00070004; +// constexpr uint64_t kPhysicalControlLeft = 0x000700e0; +// constexpr uint64_t kPhysicalControlRight = 0x000700e4; +// constexpr uint64_t kPhysicalShiftLeft = 0x000700e1; +// constexpr uint64_t kPhysicalShiftRight = 0x000700e5; +// constexpr uint64_t kPhysicalKeyNumLock = 0x00070053; + +constexpr uint64_t kLogicalKeyA = 0x00000061; +// constexpr uint64_t kLogicalControlLeft = 0x00300000105; +// constexpr uint64_t kLogicalControlRight = 0x00400000105; +// constexpr uint64_t kLogicalShiftLeft = 0x0030000010d; +// constexpr uint64_t kLogicalShiftRight = 0x0040000010d; +// constexpr uint64_t kLogicalKeyNumLock = 0x0000000010a; +} // namespace + G_DECLARE_FINAL_TYPE(FlKeyEmbedderCallRecord, fl_key_embedder_call_record, FL, @@ -71,6 +87,7 @@ static FlKeyEmbedderCallRecord* fl_key_embedder_call_record_new( strcpy(clone_character, event->character); clone_event->character = clone_character; } + self->event = clone_event; self->callback = callback; self->user_data = user_data; @@ -83,7 +100,8 @@ namespace { GdkEventKey _g_key_event; } // namespace -static GdkEventKey* key_event_new(gboolean is_down, +static GdkEventKey* key_event_new(guint32 time_in_milliseconds, + gboolean is_down, guint keyval, guint16 hardware_keycode, guint state, @@ -91,7 +109,7 @@ static GdkEventKey* key_event_new(gboolean is_down, _g_key_event.type = is_down ? GDK_KEY_PRESS : GDK_KEY_RELEASE; _g_key_event.window = nullptr; _g_key_event.send_event = FALSE; - _g_key_event.time = 12345; + _g_key_event.time = time_in_milliseconds; _g_key_event.state = state; _g_key_event.keyval = keyval; _g_key_event.length = 0; @@ -107,44 +125,50 @@ static void responder_callback(bool handled, gpointer user_data) { g_main_loop_quit(static_cast(user_data)); } -TEST(FlKeyEmbedderResponderTest, NeedThisToWork) { - g_autoptr(FlEngine) engine = make_mock_engine(); - FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); - - embedder_api->DispatchSemanticsAction = MOCK_ENGINE_PROC( - DispatchSemanticsAction, - ([](auto engine, uint64_t id, FlutterSemanticsAction action, - const uint8_t* data, size_t data_length) { return kSuccess; })); +namespace { +GPtrArray* g_call_records; } -// Test sending a letter "A"; -TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { - // g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); - g_autoptr(GPtrArray) call_records = - g_ptr_array_new_with_free_func(g_object_unref); - - g_autoptr(FlEngine) engine = make_mock_engine(); +static FlEngine* make_mock_engine_with_records() { + FlEngine* engine = make_mock_engine(); FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); + embedder_api->SendKeyEvent = [](auto engine, const FlutterKeyEvent* event, + FlutterKeyEventCallback callback, + void* user_data) { + g_ptr_array_add(g_call_records, fl_key_embedder_call_record_new( + event, callback, user_data)); - embedder_api->SendKeyEvent = MOCK_ENGINE_PROC( - SendKeyEvent, - ([&call_records](auto engine, const FlutterKeyEvent* event, - FlutterKeyEventCallback callback, void* user_data) { - // printf("Callback: before add %d\n", len); - g_ptr_array_add(call_records, fl_key_embedder_call_record_new( - event, callback, user_data)); + return kSuccess; + }; - // printf("Callback: before return\n"); - return kSuccess; - })); + return engine; +} +// Test sending a letter "A"; +TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { + EXPECT_EQ(g_call_records, nullptr); + g_call_records = g_ptr_array_new_with_free_func(g_object_unref); + g_autoptr(FlEngine) engine = make_mock_engine_with_records(); g_autoptr(FlKeyResponder) responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); + int user_data = 123; // Arbitrary user data - // printf("Test 1 %s\n", expected_value);fflush(stdout); - fl_key_responder_handle_event( - responder, key_event_new(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false), - responder_callback, nullptr); + FlKeyEmbedderCallRecord* record; - EXPECT_EQ(call_records->len, 1u); + fl_key_responder_handle_event( + responder, + key_event_new(12345, true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false), + responder_callback, &user_data); + + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->struct_size, sizeof(FlutterKeyEvent)); + EXPECT_EQ(record->event->timestamp, 12345000); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->physical, kPhysicalKeyA); + EXPECT_EQ(record->event->logical, kLogicalKeyA); + EXPECT_STREQ(record->event->character, "a"); + EXPECT_EQ(record->event->synthesized, false); + + g_clear_object(&g_call_records); } From 537dcf6a60dc4055403238ab3069438ac5ac4f70 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 12 Apr 2021 15:38:07 -0700 Subject: [PATCH 025/126] Up event --- .../linux/fl_key_embedder_responder_test.cc | 55 ++++++++++++++++--- 1 file changed, 46 insertions(+), 9 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index 21e193d6e6413..e6f07c5fbf1f7 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -11,20 +11,20 @@ #include "flutter/shell/platform/linux/fl_engine_private.h" #include "flutter/shell/platform/linux/testing/fl_test.h" -static gboolean expected_handled = FALSE; - namespace { constexpr guint16 kKeyCodeKeyA = 0x26u; // constexpr guint16 kKeyCodeKeyB = 0x38u; constexpr uint64_t kPhysicalKeyA = 0x00070004; +// constexpr uint64_t kPhysicalKeyQ = 0x00070014; // constexpr uint64_t kPhysicalControlLeft = 0x000700e0; // constexpr uint64_t kPhysicalControlRight = 0x000700e4; // constexpr uint64_t kPhysicalShiftLeft = 0x000700e1; // constexpr uint64_t kPhysicalShiftRight = 0x000700e5; // constexpr uint64_t kPhysicalKeyNumLock = 0x00070053; -constexpr uint64_t kLogicalKeyA = 0x00000061; +// constexpr uint64_t kLogicalKeyA = 0x00000061; +constexpr uint64_t kLogicalKeyQ = 0x00000071; // constexpr uint64_t kLogicalControlLeft = 0x00300000105; // constexpr uint64_t kLogicalControlRight = 0x00400000105; // constexpr uint64_t kLogicalShiftLeft = 0x0030000010d; @@ -32,6 +32,10 @@ constexpr uint64_t kLogicalKeyA = 0x00000061; // constexpr uint64_t kLogicalKeyNumLock = 0x0000000010a; } // namespace +static void g_ptr_array_clear(GPtrArray* array) { + g_ptr_array_remove_range(array, 0, array->len); +} + G_DECLARE_FINAL_TYPE(FlKeyEmbedderCallRecord, fl_key_embedder_call_record, FL, @@ -120,9 +124,17 @@ static GdkEventKey* key_event_new(guint32 time_in_milliseconds, return &_g_key_event; } +static gboolean g_expected_handled; +static gpointer g_expected_user_data; + static void responder_callback(bool handled, gpointer user_data) { - EXPECT_EQ(handled, expected_handled); - g_main_loop_quit(static_cast(user_data)); + EXPECT_EQ(handled, g_expected_handled); +} + +static void invoke_record_callback_and_verify(FlKeyEmbedderCallRecord* record, bool expected_handled, void* expected_user_data) { + g_expected_handled = expected_handled; + g_expected_user_data = expected_user_data; + record->callback(expected_handled, record->user_data); } namespace { @@ -144,7 +156,7 @@ static FlEngine* make_mock_engine_with_records() { return engine; } -// Test sending a letter "A"; +// On an AZERTY keyboard, press key Q (physically key A), hold, and release. TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); @@ -155,9 +167,10 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { FlKeyEmbedderCallRecord* record; + // Key down fl_key_responder_handle_event( responder, - key_event_new(12345, true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false), + key_event_new(12345, true, GDK_KEY_q, kKeyCodeKeyA, 0x10, false), responder_callback, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -166,9 +179,33 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { EXPECT_EQ(record->event->timestamp, 12345000); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); EXPECT_EQ(record->event->physical, kPhysicalKeyA); - EXPECT_EQ(record->event->logical, kLogicalKeyA); - EXPECT_STREQ(record->event->character, "a"); + EXPECT_EQ(record->event->logical, kLogicalKeyQ); + EXPECT_STREQ(record->event->character, "q"); EXPECT_EQ(record->event->synthesized, false); + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + // Key repeat seems not to exist for GDK + + // Key up + fl_key_responder_handle_event( + responder, + key_event_new(12346, false, GDK_KEY_q, kKeyCodeKeyA, 0x10, false), + responder_callback, &user_data); + + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->struct_size, sizeof(FlutterKeyEvent)); + EXPECT_EQ(record->event->timestamp, 12346000); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); + EXPECT_EQ(record->event->physical, kPhysicalKeyA); + EXPECT_EQ(record->event->logical, kLogicalKeyQ); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, FALSE, &user_data); + g_ptr_array_clear(g_call_records); + g_clear_object(&g_call_records); } From 04644bd5ab0c50a574b12547d700b9ea59018615 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 12 Apr 2021 17:50:32 -0700 Subject: [PATCH 026/126] Update key mapping --- .../linux/fl_key_embedder_responder_test.cc | 144 +++++++++- shell/platform/linux/key_mapping.cc | 270 +++++++++--------- 2 files changed, 270 insertions(+), 144 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index e6f07c5fbf1f7..58a7c9b81828d 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -13,6 +13,7 @@ namespace { constexpr guint16 kKeyCodeKeyA = 0x26u; +constexpr guint16 kKeyCodeShiftRight = 0x3eu; // constexpr guint16 kKeyCodeKeyB = 0x38u; constexpr uint64_t kPhysicalKeyA = 0x00070004; @@ -20,15 +21,15 @@ constexpr uint64_t kPhysicalKeyA = 0x00070004; // constexpr uint64_t kPhysicalControlLeft = 0x000700e0; // constexpr uint64_t kPhysicalControlRight = 0x000700e4; // constexpr uint64_t kPhysicalShiftLeft = 0x000700e1; -// constexpr uint64_t kPhysicalShiftRight = 0x000700e5; +constexpr uint64_t kPhysicalShiftRight = 0x000700e5; // constexpr uint64_t kPhysicalKeyNumLock = 0x00070053; -// constexpr uint64_t kLogicalKeyA = 0x00000061; +constexpr uint64_t kLogicalKeyA = 0x00000061; constexpr uint64_t kLogicalKeyQ = 0x00000071; // constexpr uint64_t kLogicalControlLeft = 0x00300000105; // constexpr uint64_t kLogicalControlRight = 0x00400000105; // constexpr uint64_t kLogicalShiftLeft = 0x0030000010d; -// constexpr uint64_t kLogicalShiftRight = 0x0040000010d; +constexpr uint64_t kLogicalShiftRight = 0x0040000010d; // constexpr uint64_t kLogicalKeyNumLock = 0x0000000010a; } // namespace @@ -131,7 +132,9 @@ static void responder_callback(bool handled, gpointer user_data) { EXPECT_EQ(handled, g_expected_handled); } -static void invoke_record_callback_and_verify(FlKeyEmbedderCallRecord* record, bool expected_handled, void* expected_user_data) { +static void invoke_record_callback_and_verify(FlKeyEmbedderCallRecord* record, + bool expected_handled, + void* expected_user_data) { g_expected_handled = expected_handled; g_expected_user_data = expected_user_data; record->callback(expected_handled, record->user_data); @@ -156,7 +159,7 @@ static FlEngine* make_mock_engine_with_records() { return engine; } -// On an AZERTY keyboard, press key Q (physically key A), hold, and release. +// Basic key presses TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); @@ -167,10 +170,11 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { FlKeyEmbedderCallRecord* record; + // On a QWERTY keyboard, press key Q (physically key A), and release. // Key down fl_key_responder_handle_event( responder, - key_event_new(12345, true, GDK_KEY_q, kKeyCodeKeyA, 0x10, false), + key_event_new(12345, true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false), responder_callback, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -179,19 +183,19 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { EXPECT_EQ(record->event->timestamp, 12345000); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); EXPECT_EQ(record->event->physical, kPhysicalKeyA); - EXPECT_EQ(record->event->logical, kLogicalKeyQ); - EXPECT_STREQ(record->event->character, "q"); + EXPECT_EQ(record->event->logical, kLogicalKeyA); + EXPECT_STREQ(record->event->character, "a"); EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); g_ptr_array_clear(g_call_records); - // Key repeat seems not to exist for GDK + // Skip testing key repeats, which is not present on GDK. // Key up fl_key_responder_handle_event( responder, - key_event_new(12346, false, GDK_KEY_q, kKeyCodeKeyA, 0x10, false), + key_event_new(12346, false, GDK_KEY_a, kKeyCodeKeyA, 0x10, false), responder_callback, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -200,6 +204,45 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { EXPECT_EQ(record->event->timestamp, 12346000); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); EXPECT_EQ(record->event->physical, kPhysicalKeyA); + EXPECT_EQ(record->event->logical, kLogicalKeyA); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, FALSE, &user_data); + g_ptr_array_clear(g_call_records); + + // On an AZERTY keyboard, press key Q (physically key A), and release. + // Key down + fl_key_responder_handle_event( + responder, + key_event_new(12347, true, GDK_KEY_q, kKeyCodeKeyA, 0x10, false), + responder_callback, &user_data); + + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->struct_size, sizeof(FlutterKeyEvent)); + EXPECT_EQ(record->event->timestamp, 12347000); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->physical, kPhysicalKeyA); + EXPECT_EQ(record->event->logical, kLogicalKeyQ); + EXPECT_STREQ(record->event->character, "q"); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + // Key up + fl_key_responder_handle_event( + responder, + key_event_new(12348, false, GDK_KEY_q, kKeyCodeKeyA, 0x10, false), + responder_callback, &user_data); + + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->struct_size, sizeof(FlutterKeyEvent)); + EXPECT_EQ(record->event->timestamp, 12348000); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); + EXPECT_EQ(record->event->physical, kPhysicalKeyA); EXPECT_EQ(record->event->logical, kLogicalKeyQ); EXPECT_STREQ(record->event->character, nullptr); EXPECT_EQ(record->event->synthesized, false); @@ -209,3 +252,84 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { g_clear_object(&g_call_records); } + +// Press Shift, key A, then release Shift, key A. +TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { + EXPECT_EQ(g_call_records, nullptr); + g_call_records = g_ptr_array_new_with_free_func(g_object_unref); + g_autoptr(FlEngine) engine = make_mock_engine_with_records(); + g_autoptr(FlKeyResponder) responder = + FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); + int user_data = 123; // Arbitrary user data + + FlKeyEmbedderCallRecord* record; + + // Press shift right + fl_key_responder_handle_event( + responder, + key_event_new(101, true, GDK_KEY_Shift_R, kKeyCodeShiftRight, 0x10, true), + responder_callback, &user_data); + + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->physical, kPhysicalShiftRight); + EXPECT_EQ(record->event->logical, kLogicalShiftRight); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + // Press key A + fl_key_responder_handle_event( + responder, key_event_new(102, true, GDK_KEY_A, kKeyCodeKeyA, 0x11, false), + responder_callback, &user_data); + + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->physical, kPhysicalKeyA); + EXPECT_EQ(record->event->logical, kLogicalKeyA); + EXPECT_STREQ(record->event->character, "A"); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + // Release shift right + fl_key_responder_handle_event(responder, + key_event_new(103, false, GDK_KEY_Shift_R, + kKeyCodeShiftRight, 0x11, true), + responder_callback, &user_data); + + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); + EXPECT_EQ(record->event->physical, kPhysicalShiftRight); + EXPECT_EQ(record->event->logical, kLogicalShiftRight); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + // Release key A + fl_key_responder_handle_event( + responder, + key_event_new(104, false, GDK_KEY_A, kKeyCodeKeyA, 0x10, false), + responder_callback, &user_data); + + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->physical, kPhysicalKeyA); + EXPECT_EQ(record->event->logical, kLogicalKeyA); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + g_clear_object(&g_call_records); +} diff --git a/shell/platform/linux/key_mapping.cc b/shell/platform/linux/key_mapping.cc index 3e26d486a39f6..914370dfc901f 100644 --- a/shell/platform/linux/key_mapping.cc +++ b/shell/platform/linux/key_mapping.cc @@ -241,142 +241,143 @@ void initialize_xkb_to_physical_key(GHashTable* table) { } void initialize_gtk_keyval_to_logical_key(GHashTable* table) { - insert_record(table, 0x0000ff08, 0x00000008); // BackSpace - insert_record(table, 0x0000ff09, 0x00000009); // Tab - insert_record(table, 0x0000ff89, 0x00000009); // KP_Tab - insert_record(table, 0x0000fe20, 0x00000009); // ISO_Left_Tab - insert_record(table, 0x0000ff0d, 0x0000000d); // Return - insert_record(table, 0x0000fe34, 0x0000000d); // ISO_Enter - insert_record(table, 0x0000fd1e, 0x0000000d); // 3270_Enter - insert_record(table, 0x0000ff1b, 0x0000001b); // Escape - insert_record(table, 0x0000ff80, 0x00000020); // KP_Space - insert_record(table, 0x0000ffae, 0x0000002e); // KP_Decimal - insert_record(table, 0x0000ffff, 0x0000007f); // Delete - insert_record(table, 0x0000ffe5, 0x00000104); // Caps_Lock - insert_record(table, 0x0000ffed, 0x00000108); // Hyper_L - insert_record(table, 0x0000ffee, 0x00000108); // Hyper_R - insert_record(table, 0x0000ff7f, 0x0000010a); // Num_Lock - insert_record(table, 0x0000ff14, 0x0000010c); // Scroll_Lock - insert_record(table, 0x0000ffeb, 0x0000010e); // Super_L - insert_record(table, 0x0000ffec, 0x0000010e); // Super_R - insert_record(table, 0x0000ff54, 0x00000301); // Down - insert_record(table, 0x0000ff51, 0x00000302); // Left - insert_record(table, 0x0000ff53, 0x00000303); // Right - insert_record(table, 0x0000ff52, 0x00000304); // Up - insert_record(table, 0x0000ff57, 0x00000305); // End - insert_record(table, 0x0000ff50, 0x00000306); // Home - insert_record(table, 0x0000ff56, 0x00000307); // Page_Down - insert_record(table, 0x0000ff55, 0x00000308); // Page_Up - insert_record(table, 0x0000ff0b, 0x00000401); // Clear - insert_record(table, 0x0000fd15, 0x00000402); // 3270_Copy - insert_record(table, 0x1008ff57, 0x00000402); // Copy - insert_record(table, 0x1008ff58, 0x00000404); // Cut - insert_record(table, 0x0000fd06, 0x00000405); // 3270_EraseEOF - insert_record(table, 0x0000fd1b, 0x00000406); // 3270_ExSelect - insert_record(table, 0x0000ff63, 0x00000407); // Insert - insert_record(table, 0x1008ff6d, 0x00000408); // Paste - insert_record(table, 0x0000ff66, 0x00000409); // Redo - insert_record(table, 0x0000ff65, 0x0000040a); // Undo - insert_record(table, 0x0000fd0e, 0x00000503); // 3270_Attn - insert_record(table, 0x0000ff69, 0x00000504); // Cancel - insert_record(table, 0x0000ff67, 0x00000505); // Menu - insert_record(table, 0x0000ff62, 0x00000506); // Execute - insert_record(table, 0x0000ff68, 0x00000507); // Find - insert_record(table, 0x0000ff6a, 0x00000508); // Help - insert_record(table, 0x0000ff13, 0x00000509); // Pause - insert_record(table, 0x0000ff60, 0x0000050c); // Select - insert_record(table, 0x1008ff8b, 0x0000050d); // ZoomIn - insert_record(table, 0x1008ff8c, 0x0000050e); // ZoomOut - insert_record(table, 0x1008ff03, 0x00000601); // MonBrightnessDown - insert_record(table, 0x1008ff02, 0x00000602); // MonBrightnessUp - insert_record(table, 0x1008ff2c, 0x00000604); // Eject - insert_record(table, 0x1008ff61, 0x00000605); // LogOff - insert_record(table, 0x1008ff2a, 0x00000607); // PowerOff - insert_record(table, 0x0000fd1d, 0x00000608); // 3270_PrintScreen - insert_record(table, 0x1008ff10, 0x0000060a); // Standby - insert_record(table, 0x1008ff2b, 0x0000060b); // WakeUp - insert_record(table, 0x0000ff37, 0x00000703); // Codeinput - insert_record(table, 0x0000fe0c, 0x00000707); // ISO_First_Group - insert_record(table, 0x0000fe0e, 0x00000708); // ISO_Last_Group - insert_record(table, 0x0000fe08, 0x00000709); // ISO_Next_Group - insert_record(table, 0x0000fe0a, 0x0000070a); // ISO_Prev_Group - insert_record(table, 0x0000ff7e, 0x0000070b); // Mode_switch - insert_record(table, 0x0000ff3e, 0x0000070e); // PreviousCandidate - insert_record(table, 0x0000ff3c, 0x00000710); // SingleCandidate - insert_record(table, 0x0000ff31, 0x00000711); // Hangul - insert_record(table, 0x0000ff34, 0x00000712); // Hangul_Hanja - insert_record(table, 0x0000ff2f, 0x00000714); // Eisu_Shift - insert_record(table, 0x0000ff29, 0x00000715); // Hankaku - insert_record(table, 0x0000ff25, 0x00000716); // Hiragana - insert_record(table, 0x0000ff27, 0x00000717); // Hiragana_Katakana - insert_record(table, 0x0000ff7e, 0x00000718); // kana_switch - insert_record(table, 0x0000ff21, 0x00000719); // Kanji - insert_record(table, 0x0000ff26, 0x0000071a); // Katakana - insert_record(table, 0x0000ff24, 0x0000071b); // Romaji - insert_record(table, 0x0000ff28, 0x0000071c); // Zenkaku - insert_record(table, 0x0000ff2a, 0x0000071d); // Zenkaku_Hankaku - insert_record(table, 0x0000ff91, 0x00000801); // KP_F1 - insert_record(table, 0x0000ffbe, 0x00000801); // F1 - insert_record(table, 0x0000ff92, 0x00000802); // KP_F2 - insert_record(table, 0x0000ffbf, 0x00000802); // F2 - insert_record(table, 0x0000ff93, 0x00000803); // KP_F3 - insert_record(table, 0x0000ffc0, 0x00000803); // F3 - insert_record(table, 0x0000ff94, 0x00000804); // KP_F4 - insert_record(table, 0x0000ffc1, 0x00000804); // F4 - insert_record(table, 0x0000ffc2, 0x00000805); // F5 - insert_record(table, 0x0000ffc3, 0x00000806); // F6 - insert_record(table, 0x0000ffc4, 0x00000807); // F7 - insert_record(table, 0x0000ffc5, 0x00000808); // F8 - insert_record(table, 0x0000ffc6, 0x00000809); // F9 - insert_record(table, 0x0000ffc7, 0x0000080a); // F10 - insert_record(table, 0x0000ffc8, 0x0000080b); // F11 - insert_record(table, 0x0000ffc9, 0x0000080c); // F12 - insert_record(table, 0x0000ffca, 0x0000080d); // F13 - insert_record(table, 0x0000ffcb, 0x0000080e); // F14 - insert_record(table, 0x0000ffcc, 0x0000080f); // F15 - insert_record(table, 0x0000ffcd, 0x00000810); // F16 - insert_record(table, 0x0000ffce, 0x00000811); // F17 - insert_record(table, 0x0000ffcf, 0x00000812); // F18 - insert_record(table, 0x0000ffd0, 0x00000813); // F19 - insert_record(table, 0x0000ffd1, 0x00000814); // F20 - insert_record(table, 0x0000ffd2, 0x00000815); // F21 - insert_record(table, 0x0000ffd3, 0x00000816); // F22 - insert_record(table, 0x0000ffd4, 0x00000817); // F23 - insert_record(table, 0x0000ffd5, 0x00000818); // F24 - insert_record(table, 0x1008ff56, 0x00000a01); // Close - insert_record(table, 0x1008ff90, 0x00000a02); // MailForward - insert_record(table, 0x1008ff72, 0x00000a03); // Reply - insert_record(table, 0x1008ff7b, 0x00000a04); // Send - insert_record(table, 0x1008ff15, 0x00000a07); // AudioStop - insert_record(table, 0x1008ff17, 0x00000a08); // AudioNext - insert_record(table, 0x1008ff16, 0x00000a09); // AudioPrev - insert_record(table, 0x1008ff68, 0x00000a0a); // New - insert_record(table, 0x1008ff6b, 0x00000a0b); // Open - insert_record(table, 0x0000ff61, 0x00000a0c); // Print - insert_record(table, 0x1008ff77, 0x00000a0d); // Save - insert_record(table, 0x1008ff7c, 0x00000a0e); // Spell - insert_record(table, 0x1008ff11, 0x00000a0f); // AudioLowerVolume - insert_record(table, 0x1008ff13, 0x00000a10); // AudioRaiseVolume - insert_record(table, 0x1008ff12, 0x00000a11); // AudioMute - insert_record(table, 0x1008ff20, 0x00000b02); // Calendar - insert_record(table, 0x1008ff19, 0x00000b03); // Mail - insert_record(table, 0x1008ff2d, 0x00000b07); // ScreenSaver - insert_record(table, 0x1008ff6e, 0x00000b0d); // Phone - insert_record(table, 0x1008ff26, 0x00000c01); // Back - insert_record(table, 0x1008ff30, 0x00000c02); // Favorites - insert_record(table, 0x1008ff27, 0x00000c03); // Forward - insert_record(table, 0x1008ff18, 0x00000c04); // HomePage - insert_record(table, 0x1008ff29, 0x00000c05); // Refresh - insert_record(table, 0x1008ff1b, 0x00000c06); // Search - insert_record(table, 0x1008ff28, 0x00000c07); // Stop - insert_record(table, 0x1008ff97, 0x00000d2c); // AudioForward - insert_record(table, 0x1008ff31, 0x00000d2e); // AudioPause - insert_record(table, 0x0000fd16, 0x00000d2f); // 3270_Play - insert_record(table, 0x1008ff14, 0x00000d2f); // AudioPlay - insert_record(table, 0x1008ff1c, 0x00000d30); // AudioRecord - insert_record(table, 0x1008ff3e, 0x00000d31); // AudioRewind + insert_record(table, 0x0000ff08, 0x000000008); // BackSpace + insert_record(table, 0x0000ff09, 0x000000009); // Tab + insert_record(table, 0x0000ff89, 0x000000009); // KP_Tab + insert_record(table, 0x0000fe20, 0x000000009); // ISO_Left_Tab + insert_record(table, 0x0000ff0d, 0x00000000d); // Return + insert_record(table, 0x0000fe34, 0x00000000d); // ISO_Enter + insert_record(table, 0x0000fd1e, 0x00000000d); // 3270_Enter + insert_record(table, 0x0000ff1b, 0x00000001b); // Escape + insert_record(table, 0x0000ff80, 0x000000020); // KP_Space + insert_record(table, 0x0000ffae, 0x00000002e); // KP_Decimal + insert_record(table, 0x0000ffff, 0x00000007f); // Delete + insert_record(table, 0x0000ffe5, 0x000000104); // Caps_Lock + insert_record(table, 0x0000ffed, 0x000000108); // Hyper_L + insert_record(table, 0x0000ffee, 0x000000108); // Hyper_R + insert_record(table, 0x0000ff7f, 0x00000010a); // Num_Lock + insert_record(table, 0x0000ff14, 0x00000010c); // Scroll_Lock + insert_record(table, 0x0000ffeb, 0x00000010e); // Super_L + insert_record(table, 0x0000ffec, 0x00000010e); // Super_R + insert_record(table, 0x0000ff54, 0x000000301); // Down + insert_record(table, 0x0000ff51, 0x000000302); // Left + insert_record(table, 0x0000ff53, 0x000000303); // Right + insert_record(table, 0x0000ff52, 0x000000304); // Up + insert_record(table, 0x0000ff57, 0x000000305); // End + insert_record(table, 0x0000ff50, 0x000000306); // Home + insert_record(table, 0x0000ff56, 0x000000307); // Page_Down + insert_record(table, 0x0000ff55, 0x000000308); // Page_Up + insert_record(table, 0x0000ff0b, 0x000000401); // Clear + insert_record(table, 0x0000fd15, 0x000000402); // 3270_Copy + insert_record(table, 0x1008ff57, 0x000000402); // Copy + insert_record(table, 0x1008ff58, 0x000000404); // Cut + insert_record(table, 0x0000fd06, 0x000000405); // 3270_EraseEOF + insert_record(table, 0x0000fd1b, 0x000000406); // 3270_ExSelect + insert_record(table, 0x0000ff63, 0x000000407); // Insert + insert_record(table, 0x1008ff6d, 0x000000408); // Paste + insert_record(table, 0x0000ff66, 0x000000409); // Redo + insert_record(table, 0x0000ff65, 0x00000040a); // Undo + insert_record(table, 0x0000fd0e, 0x000000503); // 3270_Attn + insert_record(table, 0x0000ff69, 0x000000504); // Cancel + insert_record(table, 0x0000ff67, 0x000000505); // Menu + insert_record(table, 0x0000ff62, 0x000000506); // Execute + insert_record(table, 0x0000ff68, 0x000000507); // Find + insert_record(table, 0x0000ff6a, 0x000000508); // Help + insert_record(table, 0x0000ff13, 0x000000509); // Pause + insert_record(table, 0x0000ff60, 0x00000050c); // Select + insert_record(table, 0x1008ff8b, 0x00000050d); // ZoomIn + insert_record(table, 0x1008ff8c, 0x00000050e); // ZoomOut + insert_record(table, 0x1008ff03, 0x000000601); // MonBrightnessDown + insert_record(table, 0x1008ff02, 0x000000602); // MonBrightnessUp + insert_record(table, 0x1008ff2c, 0x000000604); // Eject + insert_record(table, 0x1008ff61, 0x000000605); // LogOff + insert_record(table, 0x1008ff2a, 0x000000607); // PowerOff + insert_record(table, 0x0000fd1d, 0x000000608); // 3270_PrintScreen + insert_record(table, 0x1008ff10, 0x00000060a); // Standby + insert_record(table, 0x1008ff2b, 0x00000060b); // WakeUp + insert_record(table, 0x0000ff37, 0x000000703); // Codeinput + insert_record(table, 0x0000fe0c, 0x000000707); // ISO_First_Group + insert_record(table, 0x0000fe0e, 0x000000708); // ISO_Last_Group + insert_record(table, 0x0000fe08, 0x000000709); // ISO_Next_Group + insert_record(table, 0x0000fe0a, 0x00000070a); // ISO_Prev_Group + insert_record(table, 0x0000ff7e, 0x00000070b); // Mode_switch + insert_record(table, 0x0000ff3e, 0x00000070e); // PreviousCandidate + insert_record(table, 0x0000ff3c, 0x000000710); // SingleCandidate + insert_record(table, 0x0000ff31, 0x000000711); // Hangul + insert_record(table, 0x0000ff34, 0x000000712); // Hangul_Hanja + insert_record(table, 0x0000ff2f, 0x000000714); // Eisu_Shift + insert_record(table, 0x0000ff29, 0x000000715); // Hankaku + insert_record(table, 0x0000ff25, 0x000000716); // Hiragana + insert_record(table, 0x0000ff27, 0x000000717); // Hiragana_Katakana + insert_record(table, 0x0000ff7e, 0x000000718); // kana_switch + insert_record(table, 0x0000ff21, 0x000000719); // Kanji + insert_record(table, 0x0000ff26, 0x00000071a); // Katakana + insert_record(table, 0x0000ff24, 0x00000071b); // Romaji + insert_record(table, 0x0000ff28, 0x00000071c); // Zenkaku + insert_record(table, 0x0000ff2a, 0x00000071d); // Zenkaku_Hankaku + insert_record(table, 0x0000ff91, 0x000000801); // KP_F1 + insert_record(table, 0x0000ffbe, 0x000000801); // F1 + insert_record(table, 0x0000ff92, 0x000000802); // KP_F2 + insert_record(table, 0x0000ffbf, 0x000000802); // F2 + insert_record(table, 0x0000ff93, 0x000000803); // KP_F3 + insert_record(table, 0x0000ffc0, 0x000000803); // F3 + insert_record(table, 0x0000ff94, 0x000000804); // KP_F4 + insert_record(table, 0x0000ffc1, 0x000000804); // F4 + insert_record(table, 0x0000ffc2, 0x000000805); // F5 + insert_record(table, 0x0000ffc3, 0x000000806); // F6 + insert_record(table, 0x0000ffc4, 0x000000807); // F7 + insert_record(table, 0x0000ffc5, 0x000000808); // F8 + insert_record(table, 0x0000ffc6, 0x000000809); // F9 + insert_record(table, 0x0000ffc7, 0x00000080a); // F10 + insert_record(table, 0x0000ffc8, 0x00000080b); // F11 + insert_record(table, 0x0000ffc9, 0x00000080c); // F12 + insert_record(table, 0x0000ffca, 0x00000080d); // F13 + insert_record(table, 0x0000ffcb, 0x00000080e); // F14 + insert_record(table, 0x0000ffcc, 0x00000080f); // F15 + insert_record(table, 0x0000ffcd, 0x000000810); // F16 + insert_record(table, 0x0000ffce, 0x000000811); // F17 + insert_record(table, 0x0000ffcf, 0x000000812); // F18 + insert_record(table, 0x0000ffd0, 0x000000813); // F19 + insert_record(table, 0x0000ffd1, 0x000000814); // F20 + insert_record(table, 0x0000ffd2, 0x000000815); // F21 + insert_record(table, 0x0000ffd3, 0x000000816); // F22 + insert_record(table, 0x0000ffd4, 0x000000817); // F23 + insert_record(table, 0x0000ffd5, 0x000000818); // F24 + insert_record(table, 0x1008ff56, 0x000000a01); // Close + insert_record(table, 0x1008ff90, 0x000000a02); // MailForward + insert_record(table, 0x1008ff72, 0x000000a03); // Reply + insert_record(table, 0x1008ff7b, 0x000000a04); // Send + insert_record(table, 0x1008ff15, 0x000000a07); // AudioStop + insert_record(table, 0x1008ff17, 0x000000a08); // AudioNext + insert_record(table, 0x1008ff16, 0x000000a09); // AudioPrev + insert_record(table, 0x1008ff68, 0x000000a0a); // New + insert_record(table, 0x1008ff6b, 0x000000a0b); // Open + insert_record(table, 0x0000ff61, 0x000000a0c); // Print + insert_record(table, 0x1008ff77, 0x000000a0d); // Save + insert_record(table, 0x1008ff7c, 0x000000a0e); // Spell + insert_record(table, 0x1008ff11, 0x000000a0f); // AudioLowerVolume + insert_record(table, 0x1008ff13, 0x000000a10); // AudioRaiseVolume + insert_record(table, 0x1008ff12, 0x000000a11); // AudioMute + insert_record(table, 0x1008ff20, 0x000000b02); // Calendar + insert_record(table, 0x1008ff19, 0x000000b03); // Mail + insert_record(table, 0x1008ff2d, 0x000000b07); // ScreenSaver + insert_record(table, 0x1008ff6e, 0x000000b0d); // Phone + insert_record(table, 0x1008ff26, 0x000000c01); // Back + insert_record(table, 0x1008ff30, 0x000000c02); // Favorites + insert_record(table, 0x1008ff27, 0x000000c03); // Forward + insert_record(table, 0x1008ff18, 0x000000c04); // HomePage + insert_record(table, 0x1008ff29, 0x000000c05); // Refresh + insert_record(table, 0x1008ff1b, 0x000000c06); // Search + insert_record(table, 0x1008ff28, 0x000000c07); // Stop + insert_record(table, 0x1008ff97, 0x000000d2c); // AudioForward + insert_record(table, 0x1008ff31, 0x000000d2e); // AudioPause + insert_record(table, 0x0000fd16, 0x000000d2f); // 3270_Play + insert_record(table, 0x1008ff14, 0x000000d2f); // AudioPlay + insert_record(table, 0x1008ff1c, 0x000000d30); // AudioRecord + insert_record(table, 0x1008ff3e, 0x000000d31); // AudioRewind insert_record(table, 0x1008ffa7, 0x100000014); // Suspend insert_record(table, 0x1008ff2f, 0x100010082); // Sleep + insert_record(table, 0x000000a5, 0x100070089); // yen insert_record(table, 0x0000ff8d, 0x20000000d); // KP_Enter insert_record(table, 0x0000ffaa, 0x20000002a); // KP_Multiply insert_record(table, 0x0000ffab, 0x20000002b); // KP_Add @@ -408,6 +409,7 @@ void initialize_gtk_keyval_to_logical_key(GHashTable* table) { insert_record(table, 0x0000ffe7, 0x300000109); // Meta_L insert_record(table, 0x0000ffe1, 0x30000010d); // Shift_L insert_record(table, 0x0000ffea, 0x400000102); // Alt_R + insert_record(table, 0x0000fe03, 0x400000102); // ISO_Level3_Shift insert_record(table, 0x0000ffe4, 0x400000105); // Control_R insert_record(table, 0x0000ffe8, 0x400000109); // Meta_R insert_record(table, 0x0000ffe2, 0x40000010d); // Shift_R From dcc12ca25be7d22be9b20d712612bc791cbe49aa Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 12 Apr 2021 19:04:37 -0700 Subject: [PATCH 027/126] Shift and letter keys --- .../linux/fl_key_embedder_responder.cc | 62 +++++++++++-------- .../linux/fl_key_embedder_responder_test.cc | 38 ++++++++---- shell/platform/linux/key_mapping.cc | 6 +- shell/platform/linux/key_mapping.h | 9 +++ 4 files changed, 74 insertions(+), 41 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index 95ee16697c83a..e2615a3b7c771 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -174,27 +174,52 @@ FlKeyEmbedderResponder* fl_key_embedder_responder_new(FlEngine* engine) { return self; } +static uint64_t lookup_hash_table(GHashTable* table, uint64_t key) { + return gpointer_to_uint64( + g_hash_table_lookup(table, uint64_to_gpointer(key))); +} + static uint64_t event_to_physical_key(const GdkEventKey* event, GHashTable* table) { - gpointer record = - g_hash_table_lookup(table, GUINT_TO_POINTER(event->hardware_keycode)); - if (record != nullptr) { - return GPOINTER_TO_UINT(record); + uint64_t record = lookup_hash_table(table, event->hardware_keycode); + if (record != 0) { + return record; } // Auto-generate key return kAutogeneratedMask | kLinuxKeyIdPlane | event->hardware_keycode; } +static uint64_t to_lower(uint64_t n) { + constexpr uint64_t lower_a = 0x61; + constexpr uint64_t upper_a = 0x41; + constexpr uint64_t upper_z = 0x5a; + + constexpr uint64_t lower_a_grave = 0xe0; + constexpr uint64_t upper_a_grave = 0xc0; + constexpr uint64_t upper_thorn = 0xde; + constexpr uint64_t division = 0xf7; + + if (n >= upper_a && n <= upper_z) { + return n - upper_a + lower_a; + } + + if (n >= upper_a_grave && n <= upper_thorn && n != division) { + return n - upper_a_grave + lower_a_grave; + } + + return n; +} + static uint64_t event_to_logical_key(const GdkEventKey* event, GHashTable* table) { guint keyval = event->keyval; - gpointer record = g_hash_table_lookup(table, GUINT_TO_POINTER(keyval)); - if (record != nullptr) { - return GPOINTER_TO_UINT(record); + uint64_t record = lookup_hash_table(table, keyval); + if (record != 0) { + return record; } - // ASCII // TODO + // EASCII range if (keyval < 256) { - return keyval; + return to_lower(keyval); } // Auto-generate key return kAutogeneratedMask | kLinuxKeyIdPlane | keyval; @@ -218,23 +243,6 @@ static char* event_to_character(const GdkEventKey* event) { return result; } -static uint64_t gpointerToUint64(gpointer pointer) { - return pointer == nullptr ? 0 : reinterpret_cast(pointer); -} - -static gpointer uint64ToGpointer(uint64_t number) { - return reinterpret_cast(number); -} - -// Return the logical key corresponding to the physical key. -// -// Returns 0 if not found. -static uint64_t pressed_logical_for_physical(GHashTable* pressing_records, - uint64_t physical) { - return gpointerToUint64( - g_hash_table_lookup(pressing_records, uint64ToGpointer(physical))); -} - // Handles a response from the framework to a key event sent to the framework // earlier. static void handle_response(bool handled, gpointer user_data) { @@ -275,7 +283,7 @@ static void fl_key_embedder_responder_handle_event( bool is_physical_down = event->type == GDK_KEY_PRESS; uint64_t last_logical_record = - pressed_logical_for_physical(self->pressing_records, physical_key); + lookup_hash_table(self->pressing_records, physical_key); uint64_t next_logical_record = is_physical_down ? last_logical_record : 0; char* character_to_free = nullptr; diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index 58a7c9b81828d..57819b318fd3e 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -12,6 +12,12 @@ #include "flutter/shell/platform/linux/testing/fl_test.h" namespace { +constexpr gboolean kRelease = FALSE; +constexpr gboolean kPress = TRUE; + +constexpr gboolean kIsModifier = TRUE; +constexpr gboolean kIsNotModifier = FALSE; + constexpr guint16 kKeyCodeKeyA = 0x26u; constexpr guint16 kKeyCodeShiftRight = 0x3eu; // constexpr guint16 kKeyCodeKeyB = 0x38u; @@ -174,7 +180,8 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { // Key down fl_key_responder_handle_event( responder, - key_event_new(12345, true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false), + key_event_new(12345, kPress, GDK_KEY_a, kKeyCodeKeyA, 0x10, + kIsNotModifier), responder_callback, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -195,7 +202,8 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { // Key up fl_key_responder_handle_event( responder, - key_event_new(12346, false, GDK_KEY_a, kKeyCodeKeyA, 0x10, false), + key_event_new(12346, kRelease, GDK_KEY_a, kKeyCodeKeyA, 0x10, + kIsNotModifier), responder_callback, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -215,7 +223,8 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { // Key down fl_key_responder_handle_event( responder, - key_event_new(12347, true, GDK_KEY_q, kKeyCodeKeyA, 0x10, false), + key_event_new(12347, kPress, GDK_KEY_q, kKeyCodeKeyA, 0x10, + kIsNotModifier), responder_callback, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -234,7 +243,8 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { // Key up fl_key_responder_handle_event( responder, - key_event_new(12348, false, GDK_KEY_q, kKeyCodeKeyA, 0x10, false), + key_event_new(12348, kRelease, GDK_KEY_q, kKeyCodeKeyA, 0x10, + kIsNotModifier), responder_callback, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -267,7 +277,8 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { // Press shift right fl_key_responder_handle_event( responder, - key_event_new(101, true, GDK_KEY_Shift_R, kKeyCodeShiftRight, 0x10, true), + key_event_new(101, kPress, GDK_KEY_Shift_R, kKeyCodeShiftRight, 0x10, + kIsModifier), responder_callback, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -283,7 +294,8 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { // Press key A fl_key_responder_handle_event( - responder, key_event_new(102, true, GDK_KEY_A, kKeyCodeKeyA, 0x11, false), + responder, + key_event_new(102, kPress, GDK_KEY_A, kKeyCodeKeyA, 0x11, kIsNotModifier), responder_callback, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -298,10 +310,11 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { g_ptr_array_clear(g_call_records); // Release shift right - fl_key_responder_handle_event(responder, - key_event_new(103, false, GDK_KEY_Shift_R, - kKeyCodeShiftRight, 0x11, true), - responder_callback, &user_data); + fl_key_responder_handle_event( + responder, + key_event_new(103, kRelease, GDK_KEY_Shift_R, kKeyCodeShiftRight, 0x11, + kIsModifier), + responder_callback, &user_data); EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); @@ -317,12 +330,13 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { // Release key A fl_key_responder_handle_event( responder, - key_event_new(104, false, GDK_KEY_A, kKeyCodeKeyA, 0x10, false), + key_event_new(104, kRelease, GDK_KEY_A, kKeyCodeKeyA, 0x10, + kIsNotModifier), responder_callback, &user_data); EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); - EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); EXPECT_EQ(record->event->physical, kPhysicalKeyA); EXPECT_EQ(record->event->logical, kLogicalKeyA); EXPECT_STREQ(record->event->character, nullptr); diff --git a/shell/platform/linux/key_mapping.cc b/shell/platform/linux/key_mapping.cc index 914370dfc901f..946b749369df0 100644 --- a/shell/platform/linux/key_mapping.cc +++ b/shell/platform/linux/key_mapping.cc @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "key_mapping.h" + #include #include @@ -17,8 +19,8 @@ // // Returns whether the newly added value was already in the hash table or not. static bool insert_record(GHashTable* table, guint64 xkb, guint64 fl_key) { - return g_hash_table_insert(table, GUINT_TO_POINTER(xkb), - GUINT_TO_POINTER(fl_key)); + return g_hash_table_insert(table, uint64_to_gpointer(xkb), + uint64_to_gpointer(fl_key)); } void initialize_xkb_to_physical_key(GHashTable* table) { diff --git a/shell/platform/linux/key_mapping.h b/shell/platform/linux/key_mapping.h index f4cda7b1bc2d7..2062971203625 100644 --- a/shell/platform/linux/key_mapping.h +++ b/shell/platform/linux/key_mapping.h @@ -6,6 +6,15 @@ #define KEYBOARD_MAP_H_ #include +#include + +inline uint64_t gpointer_to_uint64(gpointer pointer) { + return pointer == nullptr ? 0 : reinterpret_cast(pointer); +} + +inline gpointer uint64_to_gpointer(uint64_t number) { + return reinterpret_cast(number); +} // Initialize a hashtable that maps XKB specific key code values to // Flutter's physical key code values. From ccbecac2f84a5043b6d3ce3f30ad2af106aafe42 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 13 Apr 2021 03:01:46 -0700 Subject: [PATCH 028/126] Test for numpad key --- .../linux/fl_key_embedder_responder.cc | 2 +- .../linux/fl_key_embedder_responder_test.cc | 98 ++++++++++++++++++- 2 files changed, 97 insertions(+), 3 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index e2615a3b7c771..3fab9367af199 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -297,7 +297,7 @@ static void fl_key_embedder_responder_handle_event( out_event.type = kFlutterKeyEventTypeDown; out_event.timestamp = event_to_timestamp(event); out_event.physical = physical_key; - out_event.logical = physical_key; + out_event.logical = logical_key; out_event.character = character_to_free; out_event.synthesized = false; diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index 57819b318fd3e..262587a122b71 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -20,6 +20,8 @@ constexpr gboolean kIsNotModifier = FALSE; constexpr guint16 kKeyCodeKeyA = 0x26u; constexpr guint16 kKeyCodeShiftRight = 0x3eu; +constexpr guint16 kKeyCodeNumpad1 = 0x57u; +constexpr guint16 kKeyCodeNumLock = 0x4du; // constexpr guint16 kKeyCodeKeyB = 0x38u; constexpr uint64_t kPhysicalKeyA = 0x00070004; @@ -28,7 +30,8 @@ constexpr uint64_t kPhysicalKeyA = 0x00070004; // constexpr uint64_t kPhysicalControlRight = 0x000700e4; // constexpr uint64_t kPhysicalShiftLeft = 0x000700e1; constexpr uint64_t kPhysicalShiftRight = 0x000700e5; -// constexpr uint64_t kPhysicalKeyNumLock = 0x00070053; +constexpr uint64_t kPhysicalKeyNumpad1 = 0x00070059; +constexpr uint64_t kPhysicalKeyNumLock = 0x00070053; constexpr uint64_t kLogicalKeyA = 0x00000061; constexpr uint64_t kLogicalKeyQ = 0x00000071; @@ -36,7 +39,8 @@ constexpr uint64_t kLogicalKeyQ = 0x00000071; // constexpr uint64_t kLogicalControlRight = 0x00400000105; // constexpr uint64_t kLogicalShiftLeft = 0x0030000010d; constexpr uint64_t kLogicalShiftRight = 0x0040000010d; -// constexpr uint64_t kLogicalKeyNumLock = 0x0000000010a; +constexpr uint64_t kLogicalKeyNumpad1 = 0x00200000031; +constexpr uint64_t kLogicalKeyNumLock = 0x0000000010a; } // namespace static void g_ptr_array_clear(GPtrArray* array) { @@ -347,3 +351,93 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { g_clear_object(&g_call_records); } + + +// Press Numpad 1, tap NumLock, then release Numpad 1. +// +// This is special because the keyval for the numpad key will change +// before and after the NumLock tap, which should not alter the +// resulting logical key. +TEST(FlKeyEmbedderResponderTest, TapNumLockDuringNumpadKeyTap) { + EXPECT_EQ(g_call_records, nullptr); + g_call_records = g_ptr_array_new_with_free_func(g_object_unref); + g_autoptr(FlEngine) engine = make_mock_engine_with_records(); + g_autoptr(FlKeyResponder) responder = + FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); + int user_data = 123; // Arbitrary user data + + FlKeyEmbedderCallRecord* record; + + // Press Numpad 1 + fl_key_responder_handle_event( + responder, + key_event_new(101, kPress, GDK_KEY_KP_1, kKeyCodeNumpad1, 0x10, + kIsNotModifier), + responder_callback, &user_data); + + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->physical, kPhysicalKeyNumpad1); + EXPECT_EQ(record->event->logical, kLogicalKeyNumpad1); + EXPECT_STREQ(record->event->character, "1"); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + // Press NumLock + fl_key_responder_handle_event( + responder, + key_event_new(102, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock, 0x10, kIsNotModifier), + responder_callback, &user_data); + + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); + EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + // Release shift right + fl_key_responder_handle_event( + responder, + key_event_new(103, kRelease, GDK_KEY_Num_Lock, kKeyCodeNumLock, 0x10, + kIsModifier), + responder_callback, &user_data); + + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); + EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); + EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + // Release key A + fl_key_responder_handle_event( + responder, + key_event_new(104, kRelease, GDK_KEY_KP_End, kKeyCodeNumpad1, 0x10, + kIsNotModifier), + responder_callback, &user_data); + + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); + EXPECT_EQ(record->event->physical, kPhysicalKeyNumpad1); + EXPECT_EQ(record->event->logical, kLogicalKeyNumpad1); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + g_clear_object(&g_call_records); +} From 7cbb69cefedc23b56f24d133c7b4f9c333bc72f4 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 13 Apr 2021 22:54:55 -0700 Subject: [PATCH 029/126] Add embedder responder to manager --- .../linux/fl_key_embedder_responder.cc | 52 +++++++++++-------- .../linux/fl_key_embedder_responder_test.cc | 24 ++++----- shell/platform/linux/fl_keyboard_manager.cc | 22 -------- shell/platform/linux/fl_view.cc | 17 ++---- shell/platform/linux/key_mapping.cc | 40 ++++++++++++++ shell/platform/linux/key_mapping.h | 2 + 6 files changed, 89 insertions(+), 68 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index 3fab9367af199..d306a007e7636 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -12,6 +12,7 @@ #include "flutter/shell/platform/linux/key_mapping.h" namespace { + const uint64_t kAutogeneratedMask = 0x10000000000; /** @@ -100,7 +101,7 @@ struct _FlKeyEmbedderResponder { // A static map from GTK keyval to Flutter's logical key code GHashTable* keyval_to_logical_key; - gchar* character_to_free; + GHashTable* modifier_bit_to_physical_keys; }; static void fl_key_embedder_responder_iface_init( @@ -131,9 +132,6 @@ static void fl_key_embedder_responder_dispose(GObject* object) { g_clear_pointer(&self->pressing_records, g_hash_table_unref); g_clear_pointer(&self->xkb_to_physical_key, g_hash_table_unref); g_clear_pointer(&self->keyval_to_logical_key, g_hash_table_unref); - if (self->character_to_free != nullptr) { - g_free(self->character_to_free); - } G_OBJECT_CLASS(fl_key_embedder_responder_parent_class)->dispose(object); } @@ -169,7 +167,6 @@ FlKeyEmbedderResponder* fl_key_embedder_responder_new(FlEngine* engine) { initialize_xkb_to_physical_key(self->xkb_to_physical_key); self->keyval_to_logical_key = g_hash_table_new(g_direct_hash, g_direct_equal); initialize_gtk_keyval_to_logical_key(self->keyval_to_logical_key); - self->character_to_free = nullptr; return self; } @@ -261,21 +258,32 @@ static void handle_response(bool handled, gpointer user_data) { data->callback(handled, data->user_data); } +static void synchronize_pressed_states_foreach(FlKeyEmbedderResponder* self) { + +} + +static int _text_idx = 0; + // Sends a key event to the framework. static void fl_key_embedder_responder_handle_event( FlKeyResponder* responder, GdkEventKey* event, FlKeyResponderAsyncCallback callback, gpointer user_data) { - FlKeyEmbedderResponder* self = FL_KEY_EMBEDDER_RESPONDER(responder); + + _text_idx += 1; + printf( + "#%7s keyval 0x%x keycode 0x%x state 0x%x ismod %d snd %d grp %d " + "time %d [%d]\n", + event->type == GDK_KEY_PRESS ? "PRESS" : "RELEASE", + event->keyval, event->hardware_keycode, event->state, event->is_modifier, + event->send_event, event->group, event->time, _text_idx); + fflush(stdout); + g_return_if_fail(event != nullptr); g_return_if_fail(callback != nullptr); + FlKeyEmbedderResponder* self = FL_KEY_EMBEDDER_RESPONDER(responder); - printf("===START=== state %d\n", event->state); - if (self->character_to_free != nullptr) { - g_free(self->character_to_free); - self->character_to_free = nullptr; - } uint64_t physical_key = event_to_physical_key(event, self->xkb_to_physical_key); uint64_t logical_key = @@ -286,34 +294,36 @@ static void fl_key_embedder_responder_handle_event( lookup_hash_table(self->pressing_records, physical_key); uint64_t next_logical_record = is_physical_down ? last_logical_record : 0; - char* character_to_free = nullptr; - printf("last %lu next %lu down %d type %d\n", last_logical_record, next_logical_record, is_physical_down, event->type); fflush(stdout); + synchronize_pressed_states_foreach(self); + FlutterKeyEvent out_event; out_event.struct_size = sizeof(out_event); out_event.type = kFlutterKeyEventTypeDown; out_event.timestamp = event_to_timestamp(event); out_event.physical = physical_key; out_event.logical = logical_key; - out_event.character = character_to_free; + out_event.character = nullptr; out_event.synthesized = false; + g_autofree char* character_to_free = nullptr; if (is_physical_down) { - character_to_free = event_to_character(event); // Might be null - out_event.character = character_to_free; - if (last_logical_record) { - // GTK doesn't report repeat events separatedly, therefore we can't - // distinguish a repeat event from a down event after a missed up event. - out_event.type = kFlutterKeyEventTypeRepeat; - out_event.logical = last_logical_record; + // A key has been pressed that has the exact physical key as a currently + // pressed one, usually indicating multiple keyboards are pressing keys + // with the same physical key, or the up event was lost during a loss of + // focus. The down event is ignored. + callback(true, user_data); + return; } else { out_event.type = kFlutterKeyEventTypeDown; out_event.logical = logical_key; } + character_to_free = event_to_character(event); // Might be null + out_event.character = character_to_free; } else { // is_physical_down false out_event.character = nullptr; out_event.type = kFlutterKeyEventTypeUp; diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index 262587a122b71..26bcf03112adc 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -184,7 +184,7 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { // Key down fl_key_responder_handle_event( responder, - key_event_new(12345, kPress, GDK_KEY_a, kKeyCodeKeyA, 0x10, + key_event_new(12345, kPress, GDK_KEY_a, kKeyCodeKeyA, 0, kIsNotModifier), responder_callback, &user_data); @@ -206,7 +206,7 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { // Key up fl_key_responder_handle_event( responder, - key_event_new(12346, kRelease, GDK_KEY_a, kKeyCodeKeyA, 0x10, + key_event_new(12346, kRelease, GDK_KEY_a, kKeyCodeKeyA, 0, kIsNotModifier), responder_callback, &user_data); @@ -227,7 +227,7 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { // Key down fl_key_responder_handle_event( responder, - key_event_new(12347, kPress, GDK_KEY_q, kKeyCodeKeyA, 0x10, + key_event_new(12347, kPress, GDK_KEY_q, kKeyCodeKeyA, 0, kIsNotModifier), responder_callback, &user_data); @@ -247,7 +247,7 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { // Key up fl_key_responder_handle_event( responder, - key_event_new(12348, kRelease, GDK_KEY_q, kKeyCodeKeyA, 0x10, + key_event_new(12348, kRelease, GDK_KEY_q, kKeyCodeKeyA, 0, kIsNotModifier), responder_callback, &user_data); @@ -281,7 +281,7 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { // Press shift right fl_key_responder_handle_event( responder, - key_event_new(101, kPress, GDK_KEY_Shift_R, kKeyCodeShiftRight, 0x10, + key_event_new(101, kPress, GDK_KEY_Shift_R, kKeyCodeShiftRight, 0, kIsModifier), responder_callback, &user_data); @@ -299,7 +299,7 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { // Press key A fl_key_responder_handle_event( responder, - key_event_new(102, kPress, GDK_KEY_A, kKeyCodeKeyA, 0x11, kIsNotModifier), + key_event_new(102, kPress, GDK_KEY_A, kKeyCodeKeyA, 0x1, kIsNotModifier), responder_callback, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -334,7 +334,7 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { // Release key A fl_key_responder_handle_event( responder, - key_event_new(104, kRelease, GDK_KEY_A, kKeyCodeKeyA, 0x10, + key_event_new(104, kRelease, GDK_KEY_A, kKeyCodeKeyA, 0, kIsNotModifier), responder_callback, &user_data); @@ -352,7 +352,6 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { g_clear_object(&g_call_records); } - // Press Numpad 1, tap NumLock, then release Numpad 1. // // This is special because the keyval for the numpad key will change @@ -389,7 +388,8 @@ TEST(FlKeyEmbedderResponderTest, TapNumLockDuringNumpadKeyTap) { // Press NumLock fl_key_responder_handle_event( responder, - key_event_new(102, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock, 0x10, kIsNotModifier), + key_event_new(102, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock, 0x10, + kIsNotModifier), responder_callback, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -403,7 +403,7 @@ TEST(FlKeyEmbedderResponderTest, TapNumLockDuringNumpadKeyTap) { invoke_record_callback_and_verify(record, TRUE, &user_data); g_ptr_array_clear(g_call_records); - // Release shift right + // Release NumLock fl_key_responder_handle_event( responder, key_event_new(103, kRelease, GDK_KEY_Num_Lock, kKeyCodeNumLock, 0x10, @@ -421,10 +421,10 @@ TEST(FlKeyEmbedderResponderTest, TapNumLockDuringNumpadKeyTap) { invoke_record_callback_and_verify(record, TRUE, &user_data); g_ptr_array_clear(g_call_records); - // Release key A + // Release numpad 1 fl_key_responder_handle_event( responder, - key_event_new(104, kRelease, GDK_KEY_KP_End, kKeyCodeNumpad1, 0x10, + key_event_new(104, kRelease, GDK_KEY_KP_End, kKeyCodeNumpad1, 0, kIsNotModifier), responder_callback, &user_data); diff --git a/shell/platform/linux/fl_keyboard_manager.cc b/shell/platform/linux/fl_keyboard_manager.cc index a6a0fff4beffb..1b495000af3a7 100644 --- a/shell/platform/linux/fl_keyboard_manager.cc +++ b/shell/platform/linux/fl_keyboard_manager.cc @@ -133,29 +133,22 @@ static uint64_t fl_keyboard_manager_get_event_hash(GdkEventKey* event) { FlKeyboardPendingEvent* fl_keyboard_pending_event_new(GdkEventKey* event, uint64_t sequence_id, size_t to_reply) { - printf("new pending 1\n"); FlKeyboardPendingEvent* self = FL_KEYBOARD_PENDING_EVENT( g_object_new(fl_keyboard_pending_event_get_type(), nullptr)); - printf("new pending 2\n"); FL_KEYBOARD_PENDING_EVENT(self); - printf("new 1\n"); // Copy the event to preserve refcounts for referenced values (mainly the // window). GdkEventKey* event_copy = reinterpret_cast( gdk_event_copy(reinterpret_cast(event))); - printf("new 1.5\n"); FlKeyboardPendingEvent* self2 = FL_KEYBOARD_PENDING_EVENT(self); - printf("new 2\n"); self->event = event_copy; self->sequence_id = sequence_id; self->unreplied = to_reply; self->any_handled = false; self->hash = fl_keyboard_manager_get_event_hash(event); - printf("new 3\n"); // FlKeyboardPendingEvent* self2 = FL_KEYBOARD_PENDING_EVENT(self); - printf("new 4\n"); return self2; } @@ -246,7 +239,6 @@ static void responder_handle_event_callback(bool handled, g_return_if_fail(FL_IS_KEYBOARD_MANAGER_USER_DATA(user_data_ptr)); FlKeyboardManagerUserData* user_data = FL_KEYBOARD_MANAGER_USER_DATA(user_data_ptr); - printf("callback 2\n"); FlKeyboardManager* self = user_data->manager; guint result_index = -1; @@ -254,22 +246,18 @@ static void responder_handle_event_callback(bool handled, self->pending_responds, &user_data->sequence_id, compare_pending_by_sequence_id, &result_index); g_return_if_fail(found); - printf("callback 3\n"); FlKeyboardPendingEvent* pending = FL_KEYBOARD_PENDING_EVENT( g_ptr_array_index(self->pending_responds, result_index)); - printf("callback 4 unrep %zu\n", pending->unreplied); g_return_if_fail(pending != nullptr); g_return_if_fail(pending->unreplied > 0); pending->unreplied -= 1; pending->any_handled = pending->any_handled || handled; // All responders have replied. if (pending->unreplied == 0) { - printf("callback 5\n"); g_object_unref(user_data_ptr); g_ptr_array_remove_index_fast(self->pending_responds, result_index); bool should_redispatch = false; if (!pending->any_handled) { - printf("callback 6\n"); // If no responders have handled, send it to text plugin. if (self->text_input_plugin == nullptr || !fl_text_input_plugin_filter_keypress(self->text_input_plugin, @@ -279,15 +267,12 @@ static void responder_handle_event_callback(bool handled, } } if (should_redispatch) { - printf("callback 7\n"); g_ptr_array_add(self->pending_redispatches, pending); self->redispatch_callback(reinterpret_cast(pending->event)); } else { - printf("callback 8\n"); g_object_unref(pending); } } - printf("callback ret\n"); } FlKeyboardManager* fl_keyboard_manager_new( @@ -319,7 +304,6 @@ void fl_keyboard_manager_add_responder(FlKeyboardManager* self, g_return_if_fail(responder != nullptr); g_ptr_array_add(self->responder_list, responder); - printf("after add len %u\n", self->responder_list->len); } static void dispatch_pending_to_responder(gpointer responder_data, @@ -339,19 +323,14 @@ gboolean fl_keyboard_manager_handle_event(FlKeyboardManager* self, g_return_val_if_fail(event != nullptr, FALSE); uint64_t incoming_hash = fl_keyboard_manager_get_event_hash(event); - printf("Handle 1\n"); if (fl_keyboard_manager_remove_redispatched(self, incoming_hash)) { - printf("Handle ret\n"); return FALSE; } - printf("Handle 2 len %u\n", self->responder_list->len); FlKeyboardPendingEvent* pending = fl_keyboard_pending_event_new( event, ++self->last_sequence_id, self->responder_list->len); - printf("Handle 2.5\n"); g_ptr_array_add(self->pending_responds, pending); - printf("Handle 3\n"); FlKeyboardManagerUserData* user_data = fl_keyboard_manager_user_data_new(self, pending->sequence_id); DispatchPendingToResponderForeachData data{ @@ -360,7 +339,6 @@ gboolean fl_keyboard_manager_handle_event(FlKeyboardManager* self, }; g_ptr_array_foreach(self->responder_list, dispatch_pending_to_responder, &data); - printf("Handle 4\n"); return TRUE; } diff --git a/shell/platform/linux/fl_view.cc b/shell/platform/linux/fl_view.cc index 72131e1b8d7d3..adafa75a857a8 100644 --- a/shell/platform/linux/fl_view.cc +++ b/shell/platform/linux/fl_view.cc @@ -11,6 +11,7 @@ #include "flutter/shell/platform/linux/fl_accessibility_plugin.h" #include "flutter/shell/platform/linux/fl_engine_private.h" #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/fl_keyboard_manager.h" #include "flutter/shell/platform/linux/fl_mouse_cursor_plugin.h" #include "flutter/shell/platform/linux/fl_platform_plugin.h" @@ -185,6 +186,9 @@ static void fl_view_constructed(GObject* object) { fl_keyboard_manager_add_responder( self->keyboard_manager, FL_KEY_RESPONDER(fl_key_channel_responder_new(messenger))); + fl_keyboard_manager_add_responder( + self->keyboard_manager, + FL_KEY_RESPONDER(fl_key_embedder_responder_new(self->engine))); self->mouse_cursor_plugin = fl_mouse_cursor_plugin_new(messenger, self); self->platform_plugin = fl_platform_plugin_new(messenger); @@ -501,12 +505,6 @@ static gboolean event_box_motion_notify_event(GtkWidget* widget, static gboolean fl_view_key_press_event(GtkWidget* widget, GdkEventKey* event) { FlView* self = FL_VIEW(widget); - printf( - "#PRESS keyval 0x%x keycode 0x%x state 0x%x ismod %d snd %d grp %d " - "time %d\n", - event->keyval, event->hardware_keycode, event->state, event->is_modifier, - event->send_event, event->group, event->time); - fflush(stdout); return fl_keyboard_manager_handle_event(self->keyboard_manager, event); } @@ -514,13 +512,6 @@ static gboolean fl_view_key_press_event(GtkWidget* widget, GdkEventKey* event) { static gboolean fl_view_key_release_event(GtkWidget* widget, GdkEventKey* event) { FlView* self = FL_VIEW(widget); - - printf( - "#RELEASE keyval 0x%x keycode 0x%x state 0x%x ismod %d snd %d grp %d " - "time %d\n", - event->keyval, event->hardware_keycode, event->state, event->is_modifier, - event->send_event, event->group, event->time); - fflush(stdout); return fl_keyboard_manager_handle_event(self->keyboard_manager, event); } diff --git a/shell/platform/linux/key_mapping.cc b/shell/platform/linux/key_mapping.cc index 946b749369df0..c3b384eaab627 100644 --- a/shell/platform/linux/key_mapping.cc +++ b/shell/platform/linux/key_mapping.cc @@ -416,3 +416,43 @@ void initialize_gtk_keyval_to_logical_key(GHashTable* table) { insert_record(table, 0x0000ffe8, 0x400000109); // Meta_R insert_record(table, 0x0000ffe2, 0x40000010d); // Shift_R } + +void initialize_modifier_bit_to_physical_keys(GHashTable* table) { + GArray* array; + + array = g_array_new(TRUE, FALSE, sizeof(uint64_t)); + g_hash_table_insert(table, uint64_to_gpointer(GDK_SHIFT_MASK), array); + g_array_set_size(array, 2); + int data_shift[] = { + 0x000700e1, // ShiftLeft + 0x000700e5, // ShiftRight + }; + g_array_append_vals(array, data_shift, 2); + + array = g_array_new(TRUE, FALSE, sizeof(uint64_t)); + g_hash_table_insert(table, uint64_to_gpointer(GDK_CONTROL_MASK), array); + g_array_set_size(array, 2); + int data_control[] = { + 0x000700e0, // ControlLeft + 0x000700e4, // ControlRight + }; + g_array_append_vals(array, data_control, 2); + + array = g_array_new(TRUE, FALSE, sizeof(uint64_t)); + g_hash_table_insert(table, uint64_to_gpointer(GDK_MOD1_MASK), array); + g_array_set_size(array, 2); + int data_mod1[] = { + 0x000700e2, // AltLeft + 0x000700e6, // AltRight + }; + g_array_append_vals(array, data_mod1, 2); + + array = g_array_new(TRUE, FALSE, sizeof(uint64_t)); + g_hash_table_insert(table, uint64_to_gpointer(GDK_MOD4_MASK), array); + g_array_set_size(array, 2); + int data_mod4[] = { + 0x000700e3, // MetaLeft + 0x000700e7, // MetaRight + }; + g_array_append_vals(array, data_mod4, 2); +} diff --git a/shell/platform/linux/key_mapping.h b/shell/platform/linux/key_mapping.h index 2062971203625..a8589d9962a77 100644 --- a/shell/platform/linux/key_mapping.h +++ b/shell/platform/linux/key_mapping.h @@ -24,4 +24,6 @@ void initialize_xkb_to_physical_key(GHashTable* table); // Flutter's logical key code values. void initialize_gtk_keyval_to_logical_key(GHashTable* table); +void initialize_modifier_bit_to_physical_keys(GHashTable* table); + #endif // KEYBOARD_MAP_H_ From 5dac16123aa5cf7447c139e4c40d9e5ee211169e Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Wed, 14 Apr 2021 02:15:31 -0700 Subject: [PATCH 030/126] synthesize pressing state --- shell/platform/linux/BUILD.gn | 1 + .../linux/fl_key_embedder_responder.cc | 121 +++++++++++++++--- .../linux/fl_key_embedder_responder_private.h | 21 +++ .../linux/fl_key_embedder_responder_test.cc | 27 ++-- shell/platform/linux/key_mapping.cc | 92 ++++++++----- shell/platform/linux/key_mapping.h | 4 +- 6 files changed, 198 insertions(+), 68 deletions(-) create mode 100644 shell/platform/linux/fl_key_embedder_responder_private.h diff --git a/shell/platform/linux/BUILD.gn b/shell/platform/linux/BUILD.gn index 0e406df1e7e44..315a08693e5f6 100644 --- a/shell/platform/linux/BUILD.gn +++ b/shell/platform/linux/BUILD.gn @@ -78,6 +78,7 @@ source_set("flutter_linux_sources") { "fl_key_responder.h", "fl_key_channel_responder.h", "fl_key_embedder_responder.h", + "fl_key_embedder_responder_private.h", "fl_method_call_private.h", "fl_method_channel_private.h", "fl_method_codec_private.h", diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index d306a007e7636..5ce996654463b 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -9,6 +9,7 @@ #include "flutter/shell/platform/embedder/embedder.h" #include "flutter/shell/platform/linux/fl_engine_private.h" +#include "flutter/shell/platform/linux/fl_key_embedder_responder_private.h" #include "flutter/shell/platform/linux/key_mapping.h" namespace { @@ -145,6 +146,10 @@ static void fl_key_embedder_responder_class_init( // Initializes an FlKeyEmbedderResponder instance. static void fl_key_embedder_responder_init(FlKeyEmbedderResponder* self) {} +static void garray_free_notify(gpointer array) { + g_free(array); +} + // Creates a new FlKeyEmbedderResponder instance, with a messenger used to send // messages to the framework, an FlTextInputPlugin used to handle key events // that the framework doesn't handle. Mainly for testing purposes, it also takes @@ -167,6 +172,9 @@ FlKeyEmbedderResponder* fl_key_embedder_responder_new(FlEngine* engine) { initialize_xkb_to_physical_key(self->xkb_to_physical_key); self->keyval_to_logical_key = g_hash_table_new(g_direct_hash, g_direct_equal); initialize_gtk_keyval_to_logical_key(self->keyval_to_logical_key); + self->modifier_bit_to_physical_keys = g_hash_table_new_full( + g_direct_hash, g_direct_equal, NULL, garray_free_notify); + // initialize_modifier_bit_to_physical_keys(self->modifier_bit_to_physical_keys); return self; } @@ -258,8 +266,69 @@ static void handle_response(bool handled, gpointer user_data) { data->callback(handled, data->user_data); } -static void synchronize_pressed_states_foreach(FlKeyEmbedderResponder* self) { +static void synthesize_simple_event(FlKeyEmbedderResponder* self, + FlutterKeyEventType type, + uint64_t physical, + uint64_t logical, + double timestamp) { + FlutterKeyEvent out_event; + out_event.struct_size = sizeof(out_event); + out_event.timestamp = timestamp; + out_event.type = type; + out_event.physical = physical; + out_event.logical = logical; + out_event.character = nullptr; + out_event.synthesized = true; + fl_engine_send_key_event(self->engine, &out_event, nullptr, nullptr); +} +namespace { +typedef struct { + FlKeyEmbedderResponder* self; + guint state; + double timestamp; +} SyncPressedStatesForeachData; +} // namespace + +static void synchronize_pressed_states_foreach(gpointer key, + gpointer value, + gpointer user_data) { + SyncPressedStatesForeachData* foreach_data = + reinterpret_cast(user_data); + FlKeyEmbedderCheckedKey* checked_key = + reinterpret_cast(value); + + guint modifier_bit = GPOINTER_TO_INT(key); + FlKeyEmbedderResponder* self = foreach_data->self; + uint64_t* physical_keys = checked_key->physical_keys; + + bool pressed_by_state = foreach_data->state & modifier_bit; + bool pressed_by_record = false; + + for (guint physical_key_idx = 0; physical_key_idx < checked_key->length; + physical_key_idx++) { + uint64_t physical_key = physical_keys[physical_key_idx]; + uint64_t logical_key = + lookup_hash_table(self->pressing_records, physical_key); + if (logical_key != 0) { + pressed_by_record = true; + if (!pressed_by_state) { + synthesize_simple_event(self, kFlutterKeyEventTypeUp, physical_key, + logical_key, foreach_data->timestamp); + g_hash_table_remove(self->pressing_records, + uint64_to_gpointer(physical_key)); + } + } + } + if (pressed_by_state && !pressed_by_record) { + uint64_t physical_key = physical_keys[0]; + uint64_t logical_key = checked_key->first_logical_key; + synthesize_simple_event(self, kFlutterKeyEventTypeDown, physical_key, + logical_key, foreach_data->timestamp); + g_hash_table_insert(self->pressing_records, + uint64_to_gpointer(physical_key), + uint64_to_gpointer(logical_key)); + } } static int _text_idx = 0; @@ -270,13 +339,12 @@ static void fl_key_embedder_responder_handle_event( GdkEventKey* event, FlKeyResponderAsyncCallback callback, gpointer user_data) { - _text_idx += 1; printf( "#%7s keyval 0x%x keycode 0x%x state 0x%x ismod %d snd %d grp %d " "time %d [%d]\n", - event->type == GDK_KEY_PRESS ? "PRESS" : "RELEASE", - event->keyval, event->hardware_keycode, event->state, event->is_modifier, + event->type == GDK_KEY_PRESS ? "PRESS" : "RELEASE", event->keyval, + event->hardware_keycode, event->state, event->is_modifier, event->send_event, event->group, event->time, _text_idx); fflush(stdout); @@ -288,22 +356,36 @@ static void fl_key_embedder_responder_handle_event( event_to_physical_key(event, self->xkb_to_physical_key); uint64_t logical_key = event_to_logical_key(event, self->keyval_to_logical_key); + double timestamp = event_to_timestamp(event); bool is_physical_down = event->type == GDK_KEY_PRESS; uint64_t last_logical_record = lookup_hash_table(self->pressing_records, physical_key); - uint64_t next_logical_record = is_physical_down ? last_logical_record : 0; - printf("last %lu next %lu down %d type %d\n", last_logical_record, - next_logical_record, is_physical_down, event->type); - fflush(stdout); + // printf("last %lu next %lu down %d type %d\n", last_logical_record, + // next_logical_record, is_physical_down, event->type); + // fflush(stdout); + + if (is_physical_down) { + g_hash_table_insert(self->pressing_records, + uint64_to_gpointer(physical_key), + uint64_to_gpointer(logical_key)); + } else { + g_hash_table_remove(self->pressing_records, + uint64_to_gpointer(physical_key)); + } - synchronize_pressed_states_foreach(self); + SyncPressedStatesForeachData sync_pressed_state_data; + sync_pressed_state_data.self = self; + sync_pressed_state_data.state = event->state; + sync_pressed_state_data.timestamp = timestamp; + g_hash_table_foreach(self->modifier_bit_to_physical_keys, + synchronize_pressed_states_foreach, + &sync_pressed_state_data); FlutterKeyEvent out_event; out_event.struct_size = sizeof(out_event); - out_event.type = kFlutterKeyEventTypeDown; - out_event.timestamp = event_to_timestamp(event); + out_event.timestamp = timestamp; out_event.physical = physical_key; out_event.logical = logical_key; out_event.character = nullptr; @@ -320,14 +402,19 @@ static void fl_key_embedder_responder_handle_event( return; } else { out_event.type = kFlutterKeyEventTypeDown; - out_event.logical = logical_key; + character_to_free = event_to_character(event); // Might be null + out_event.character = character_to_free; } - character_to_free = event_to_character(event); // Might be null - out_event.character = character_to_free; } else { // is_physical_down false - out_event.character = nullptr; - out_event.type = kFlutterKeyEventTypeUp; - out_event.logical = logical_key; + if (!last_logical_record) { + // The physical key has been released before. It might indicate a missed + // event due to loss of focus, or multiple keyboards pressed keys with the + // same physical key. Ignore the up event. + callback(true, user_data); + return; + } else { + out_event.type = kFlutterKeyEventTypeUp; + } } FlKeyEmbedderUserData* response_data = diff --git a/shell/platform/linux/fl_key_embedder_responder_private.h b/shell/platform/linux/fl_key_embedder_responder_private.h new file mode 100644 index 0000000000000..808649268b996 --- /dev/null +++ b/shell/platform/linux/fl_key_embedder_responder_private.h @@ -0,0 +1,21 @@ +// 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_KEY_EMBEDDER_RESPONDER_PRIVATE_H_ +#define FLUTTER_SHELL_PLATFORM_LINUX_FL_KEY_EMBEDDER_RESPONDER_PRIVATE_H_ + +#include + +#include "flutter/shell/platform/linux/fl_key_responder.h" +#include "flutter/shell/platform/linux/fl_keyboard_manager.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_value.h" + +typedef struct { + size_t length; + uint64_t* physical_keys; + uint64_t first_logical_key; +} FlKeyEmbedderCheckedKey; + +#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_KEY_EMBEDDER_RESPONDER_PRIVATE_H_ diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index 26bcf03112adc..69d96ef8dc2b2 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -184,8 +184,7 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { // Key down fl_key_responder_handle_event( responder, - key_event_new(12345, kPress, GDK_KEY_a, kKeyCodeKeyA, 0, - kIsNotModifier), + key_event_new(12345, kPress, GDK_KEY_a, kKeyCodeKeyA, 0, kIsNotModifier), responder_callback, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -204,11 +203,10 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { // Skip testing key repeats, which is not present on GDK. // Key up - fl_key_responder_handle_event( - responder, - key_event_new(12346, kRelease, GDK_KEY_a, kKeyCodeKeyA, 0, - kIsNotModifier), - responder_callback, &user_data); + fl_key_responder_handle_event(responder, + key_event_new(12346, kRelease, GDK_KEY_a, + kKeyCodeKeyA, 0, kIsNotModifier), + responder_callback, &user_data); EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); @@ -227,8 +225,7 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { // Key down fl_key_responder_handle_event( responder, - key_event_new(12347, kPress, GDK_KEY_q, kKeyCodeKeyA, 0, - kIsNotModifier), + key_event_new(12347, kPress, GDK_KEY_q, kKeyCodeKeyA, 0, kIsNotModifier), responder_callback, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -245,11 +242,10 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { g_ptr_array_clear(g_call_records); // Key up - fl_key_responder_handle_event( - responder, - key_event_new(12348, kRelease, GDK_KEY_q, kKeyCodeKeyA, 0, - kIsNotModifier), - responder_callback, &user_data); + fl_key_responder_handle_event(responder, + key_event_new(12348, kRelease, GDK_KEY_q, + kKeyCodeKeyA, 0, kIsNotModifier), + responder_callback, &user_data); EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); @@ -334,8 +330,7 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { // Release key A fl_key_responder_handle_event( responder, - key_event_new(104, kRelease, GDK_KEY_A, kKeyCodeKeyA, 0, - kIsNotModifier), + key_event_new(104, kRelease, GDK_KEY_A, kKeyCodeKeyA, 0, kIsNotModifier), responder_callback, &user_data); EXPECT_EQ(g_call_records->len, 1u); diff --git a/shell/platform/linux/key_mapping.cc b/shell/platform/linux/key_mapping.cc index c3b384eaab627..0ca865489f111 100644 --- a/shell/platform/linux/key_mapping.cc +++ b/shell/platform/linux/key_mapping.cc @@ -7,6 +7,8 @@ #include #include +#include "flutter/shell/platform/linux/fl_key_embedder_responder_private.h" + // DO NOT EDIT -- DO NOT EDIT -- DO NOT EDIT // This file is generated by // flutter/flutter@dev/tools/gen_keycodes/bin/gen_keycodes.dart and should not @@ -417,42 +419,64 @@ void initialize_gtk_keyval_to_logical_key(GHashTable* table) { insert_record(table, 0x0000ffe2, 0x40000010d); // Shift_R } -void initialize_modifier_bit_to_physical_keys(GHashTable* table) { - GArray* array; +void initialize_modifier_bit_to_checked_keys(GHashTable* table) { + FlKeyEmbedderCheckedKey* data; + uint64_t* physical_keys; + + data = g_new(FlKeyEmbedderCheckedKey, 1); + g_hash_table_insert(table, GUINT_TO_POINTER(GDK_SHIFT_MASK), data); + data->length = 2; + data->first_logical_key = 0x30000010d; // shiftLeft + physical_keys = g_new(uint64_t, 2); + data->physical_keys = physical_keys; + *(physical_keys++) = 0x000700e1; // ShiftLeft + *(physical_keys++) = 0x000700e5; // ShiftRight + + data = g_new(FlKeyEmbedderCheckedKey, 1); + g_hash_table_insert(table, GUINT_TO_POINTER(GDK_CONTROL_MASK), data); + data->length = 2; + data->first_logical_key = 0x300000105; // controlLeft + physical_keys = g_new(uint64_t, 2); + data->physical_keys = physical_keys; + *(physical_keys++) = 0x000700e0; // ControlLeft + *(physical_keys++) = 0x000700e4; // ControlRight - array = g_array_new(TRUE, FALSE, sizeof(uint64_t)); - g_hash_table_insert(table, uint64_to_gpointer(GDK_SHIFT_MASK), array); - g_array_set_size(array, 2); - int data_shift[] = { - 0x000700e1, // ShiftLeft - 0x000700e5, // ShiftRight - }; - g_array_append_vals(array, data_shift, 2); + data = g_new(FlKeyEmbedderCheckedKey, 1); + g_hash_table_insert(table, GUINT_TO_POINTER(GDK_MOD1_MASK), data); + data->length = 2; + data->first_logical_key = 0x300000102; // altLeft + physical_keys = g_new(uint64_t, 2); + data->physical_keys = physical_keys; + *(physical_keys++) = 0x000700e2; // AltLeft + *(physical_keys++) = 0x000700e6; // AltRight + + data = g_new(FlKeyEmbedderCheckedKey, 1); + g_hash_table_insert(table, GUINT_TO_POINTER(GDK_MOD4_MASK), data); + data->length = 2; + data->first_logical_key = 0x300000109; // metaLeft + physical_keys = g_new(uint64_t, 2); + data->physical_keys = physical_keys; + *(physical_keys++) = 0x000700e3; // MetaLeft + *(physical_keys++) = 0x000700e7; // MetaRight +} - array = g_array_new(TRUE, FALSE, sizeof(uint64_t)); - g_hash_table_insert(table, uint64_to_gpointer(GDK_CONTROL_MASK), array); - g_array_set_size(array, 2); - int data_control[] = { - 0x000700e0, // ControlLeft - 0x000700e4, // ControlRight - }; - g_array_append_vals(array, data_control, 2); +void initialize_mode_bit_to_checked_keys(GHashTable* table) { + FlKeyEmbedderCheckedKey* data; + uint64_t* physical_keys; - array = g_array_new(TRUE, FALSE, sizeof(uint64_t)); - g_hash_table_insert(table, uint64_to_gpointer(GDK_MOD1_MASK), array); - g_array_set_size(array, 2); - int data_mod1[] = { - 0x000700e2, // AltLeft - 0x000700e6, // AltRight - }; - g_array_append_vals(array, data_mod1, 2); + data = g_new(FlKeyEmbedderCheckedKey, 1); + g_hash_table_insert(table, GUINT_TO_POINTER(GDK_LOCK_MASK), data); + data->length = 1; + data->first_logical_key = 0x000000104; // capsLock + physical_keys = g_new(uint64_t, 1); + data->physical_keys = physical_keys; + *(physical_keys++) = 0x00070039; // CapsLock - array = g_array_new(TRUE, FALSE, sizeof(uint64_t)); - g_hash_table_insert(table, uint64_to_gpointer(GDK_MOD4_MASK), array); - g_array_set_size(array, 2); - int data_mod4[] = { - 0x000700e3, // MetaLeft - 0x000700e7, // MetaRight - }; - g_array_append_vals(array, data_mod4, 2); + data = g_new(FlKeyEmbedderCheckedKey, 1); + g_hash_table_insert(table, GUINT_TO_POINTER(GDK_MOD2_MASK), data); + data->length = 1; + data->first_logical_key = 0x00000010a; // numLock + physical_keys = g_new(uint64_t, 1); + data->physical_keys = physical_keys; + *(physical_keys++) = 0x00070053; // NumLock } diff --git a/shell/platform/linux/key_mapping.h b/shell/platform/linux/key_mapping.h index a8589d9962a77..a4e466fb7dd9e 100644 --- a/shell/platform/linux/key_mapping.h +++ b/shell/platform/linux/key_mapping.h @@ -24,6 +24,8 @@ void initialize_xkb_to_physical_key(GHashTable* table); // Flutter's logical key code values. void initialize_gtk_keyval_to_logical_key(GHashTable* table); -void initialize_modifier_bit_to_physical_keys(GHashTable* table); +void initialize_modifier_bit_to_checked_keys(GHashTable* table); + +void initialize_mode_bit_to_checked_keys(GHashTable* table); #endif // KEYBOARD_MAP_H_ From 321d077e62e2df998801ac35a6bb54fd080f9acb Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Wed, 14 Apr 2021 02:40:56 -0700 Subject: [PATCH 031/126] Add test for duplicate events --- .../linux/fl_key_embedder_responder_test.cc | 68 ++++++++++++++++++- ...keyboard_key_embedder_handler_unittests.cc | 2 +- 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index 69d96ef8dc2b2..8fb55abcd09cd 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -19,10 +19,10 @@ constexpr gboolean kIsModifier = TRUE; constexpr gboolean kIsNotModifier = FALSE; constexpr guint16 kKeyCodeKeyA = 0x26u; +// constexpr guint16 kKeyCodeKeyB = 0x38u; constexpr guint16 kKeyCodeShiftRight = 0x3eu; constexpr guint16 kKeyCodeNumpad1 = 0x57u; constexpr guint16 kKeyCodeNumLock = 0x4du; -// constexpr guint16 kKeyCodeKeyB = 0x38u; constexpr uint64_t kPhysicalKeyA = 0x00070004; // constexpr uint64_t kPhysicalKeyQ = 0x00070014; @@ -436,3 +436,69 @@ TEST(FlKeyEmbedderResponderTest, TapNumLockDuringNumpadKeyTap) { g_clear_object(&g_call_records); } + +TEST(FlKeyEmbedderResponderTest, IgnoreDuplicateDownEvent) { + EXPECT_EQ(g_call_records, nullptr); + g_call_records = g_ptr_array_new_with_free_func(g_object_unref); + g_autoptr(FlEngine) engine = make_mock_engine_with_records(); + g_autoptr(FlKeyResponder) responder = + FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); + int user_data = 123; // Arbitrary user data + + FlKeyEmbedderCallRecord* record; + + // Press KeyA + fl_key_responder_handle_event( + responder, + key_event_new(101, kPress, GDK_KEY_a, kKeyCodeKeyA, 0, + kIsNotModifier), + responder_callback, &user_data); + + EXPECT_EQ(g_call_records->len, 1u); + + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + // Press KeyA again (with different logical key, not necessarily but for + // coverage). + fl_key_responder_handle_event( + responder, + key_event_new(102, kPress, GDK_KEY_q, kKeyCodeKeyA, 0, + kIsNotModifier), + responder_callback, &user_data); + + EXPECT_EQ(g_call_records->len, 0u); + + // Release KeyA + fl_key_responder_handle_event( + responder, + key_event_new(103, kRelease, GDK_KEY_q, kKeyCodeKeyA, 0, + kIsNotModifier), + responder_callback, &user_data); + + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + g_clear_object(&g_call_records); +} + +TEST(FlKeyEmbedderResponderTest, IgnoreAbruptUpEvent) { + EXPECT_EQ(g_call_records, nullptr); + g_call_records = g_ptr_array_new_with_free_func(g_object_unref); + g_autoptr(FlEngine) engine = make_mock_engine_with_records(); + g_autoptr(FlKeyResponder) responder = + FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); + int user_data = 123; // Arbitrary user data + + // Release KeyA before it was even pressed. + fl_key_responder_handle_event( + responder, + key_event_new(103, kRelease, GDK_KEY_q, kKeyCodeKeyA, 0, + kIsNotModifier), + responder_callback, &user_data); + + EXPECT_EQ(g_call_records->len, 0u); +} diff --git a/shell/platform/windows/keyboard_key_embedder_handler_unittests.cc b/shell/platform/windows/keyboard_key_embedder_handler_unittests.cc index e992d5d91c200..7fdcaece37994 100644 --- a/shell/platform/windows/keyboard_key_embedder_handler_unittests.cc +++ b/shell/platform/windows/keyboard_key_embedder_handler_unittests.cc @@ -480,7 +480,7 @@ TEST(KeyboardKeyEmbedderHandlerTest, ModifierKeysByVirtualKey) { results.clear(); } -TEST(KeyboardKeyEmbedderHandlerTest, AbruptRepeatIsConvertedtoDown) { +TEST(KeyboardKeyEmbedderHandlerTest, AbruptRepeatIsConvertedToDown) { TestKeystate key_state; std::vector results; TestFlutterKeyEvent* event; From 21e9a98c2cb42eba019f5bb00dbd92aa2f42fed8 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Wed, 14 Apr 2021 04:04:06 -0700 Subject: [PATCH 032/126] Sync state test 1 --- .../linux/fl_key_embedder_responder.cc | 72 +++++++++----- .../linux/fl_key_embedder_responder_test.cc | 94 ++++++++++++++++--- 2 files changed, 129 insertions(+), 37 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index 5ce996654463b..696b978d8109a 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -133,6 +133,7 @@ static void fl_key_embedder_responder_dispose(GObject* object) { g_clear_pointer(&self->pressing_records, g_hash_table_unref); g_clear_pointer(&self->xkb_to_physical_key, g_hash_table_unref); g_clear_pointer(&self->keyval_to_logical_key, g_hash_table_unref); + g_clear_pointer(&self->modifier_bit_to_physical_keys, g_hash_table_unref); G_OBJECT_CLASS(fl_key_embedder_responder_parent_class)->dispose(object); } @@ -146,8 +147,11 @@ static void fl_key_embedder_responder_class_init( // Initializes an FlKeyEmbedderResponder instance. static void fl_key_embedder_responder_init(FlKeyEmbedderResponder* self) {} -static void garray_free_notify(gpointer array) { - g_free(array); +static void checked_key_free_notify(gpointer pointer) { + FlKeyEmbedderCheckedKey* checked_key = + reinterpret_cast(pointer); + g_free(checked_key->physical_keys); + g_free(checked_key); } // Creates a new FlKeyEmbedderResponder instance, with a messenger used to send @@ -173,8 +177,8 @@ FlKeyEmbedderResponder* fl_key_embedder_responder_new(FlEngine* engine) { self->keyval_to_logical_key = g_hash_table_new(g_direct_hash, g_direct_equal); initialize_gtk_keyval_to_logical_key(self->keyval_to_logical_key); self->modifier_bit_to_physical_keys = g_hash_table_new_full( - g_direct_hash, g_direct_equal, NULL, garray_free_notify); - // initialize_modifier_bit_to_physical_keys(self->modifier_bit_to_physical_keys); + g_direct_hash, g_direct_equal, NULL, checked_key_free_notify); + initialize_modifier_bit_to_checked_keys(self->modifier_bit_to_physical_keys); return self; } @@ -286,23 +290,25 @@ namespace { typedef struct { FlKeyEmbedderResponder* self; guint state; + uint64_t current_physical_key; double timestamp; -} SyncPressedStatesForeachData; +} SyncPressedStatesLoopContext; } // namespace -static void synchronize_pressed_states_foreach(gpointer key, - gpointer value, - gpointer user_data) { - SyncPressedStatesForeachData* foreach_data = - reinterpret_cast(user_data); +static void synchronize_pressed_states_loop_body(gpointer key, + gpointer value, + gpointer user_data) { + SyncPressedStatesLoopContext* context = + reinterpret_cast(user_data); FlKeyEmbedderCheckedKey* checked_key = reinterpret_cast(value); guint modifier_bit = GPOINTER_TO_INT(key); - FlKeyEmbedderResponder* self = foreach_data->self; + FlKeyEmbedderResponder* self = context->self; uint64_t* physical_keys = checked_key->physical_keys; + printf("Syn: 1 state %x bit %x curPhy %lx\n", context->state, modifier_bit, context->current_physical_key); - bool pressed_by_state = foreach_data->state & modifier_bit; + bool pressed_by_state = context->state & modifier_bit; bool pressed_by_record = false; for (guint physical_key_idx = 0; physical_key_idx < checked_key->length; @@ -310,11 +316,21 @@ static void synchronize_pressed_states_foreach(gpointer key, uint64_t physical_key = physical_keys[physical_key_idx]; uint64_t logical_key = lookup_hash_table(self->pressing_records, physical_key); - if (logical_key != 0) { + // If this event is the down event of the key, then the state will be + // flipped but haven't reflected on the state. Flip it manually here. + bool adjusted_this_key_pressed = + (logical_key != 0) ^ + (physical_key == context->current_physical_key); + + printf("Syn: 2 phy %lx record %lx adju %d\n", physical_key, logical_key, adjusted_this_key_pressed); + if (adjusted_this_key_pressed) { pressed_by_record = true; if (!pressed_by_state) { + printf("Syn: 3 SYN: phy %lx log %lx currPh %lx\n", physical_key, + logical_key, context->current_physical_key); + g_return_if_fail(physical_key != context->current_physical_key); synthesize_simple_event(self, kFlutterKeyEventTypeUp, physical_key, - logical_key, foreach_data->timestamp); + logical_key, context->timestamp); g_hash_table_remove(self->pressing_records, uint64_to_gpointer(physical_key)); } @@ -322,9 +338,11 @@ static void synchronize_pressed_states_foreach(gpointer key, } if (pressed_by_state && !pressed_by_record) { uint64_t physical_key = physical_keys[0]; + g_return_if_fail(physical_key != context->current_physical_key); uint64_t logical_key = checked_key->first_logical_key; + printf("Syn: 4 SYN: phy %lx log %lx\n", physical_key, logical_key); synthesize_simple_event(self, kFlutterKeyEventTypeDown, physical_key, - logical_key, foreach_data->timestamp); + logical_key, context->timestamp); g_hash_table_insert(self->pressing_records, uint64_to_gpointer(physical_key), uint64_to_gpointer(logical_key)); @@ -357,16 +375,16 @@ static void fl_key_embedder_responder_handle_event( uint64_t logical_key = event_to_logical_key(event, self->keyval_to_logical_key); double timestamp = event_to_timestamp(event); - bool is_physical_down = event->type == GDK_KEY_PRESS; + bool is_down_event = event->type == GDK_KEY_PRESS; uint64_t last_logical_record = lookup_hash_table(self->pressing_records, physical_key); // printf("last %lu next %lu down %d type %d\n", last_logical_record, - // next_logical_record, is_physical_down, event->type); + // next_logical_record, is_down_event, event->type); // fflush(stdout); - if (is_physical_down) { + if (is_down_event) { g_hash_table_insert(self->pressing_records, uint64_to_gpointer(physical_key), uint64_to_gpointer(logical_key)); @@ -375,13 +393,15 @@ static void fl_key_embedder_responder_handle_event( uint64_to_gpointer(physical_key)); } - SyncPressedStatesForeachData sync_pressed_state_data; - sync_pressed_state_data.self = self; - sync_pressed_state_data.state = event->state; - sync_pressed_state_data.timestamp = timestamp; + // printf("Before foreach\n"); + SyncPressedStatesLoopContext sync_pressed_state_context; + sync_pressed_state_context.self = self; + sync_pressed_state_context.state = event->state; + sync_pressed_state_context.timestamp = timestamp; + sync_pressed_state_context.current_physical_key = physical_key; g_hash_table_foreach(self->modifier_bit_to_physical_keys, - synchronize_pressed_states_foreach, - &sync_pressed_state_data); + synchronize_pressed_states_loop_body, + &sync_pressed_state_context); FlutterKeyEvent out_event; out_event.struct_size = sizeof(out_event); @@ -392,7 +412,7 @@ static void fl_key_embedder_responder_handle_event( out_event.synthesized = false; g_autofree char* character_to_free = nullptr; - if (is_physical_down) { + if (is_down_event) { if (last_logical_record) { // A key has been pressed that has the exact physical key as a currently // pressed one, usually indicating multiple keyboards are pressing keys @@ -405,7 +425,7 @@ static void fl_key_embedder_responder_handle_event( character_to_free = event_to_character(event); // Might be null out_event.character = character_to_free; } - } else { // is_physical_down false + } else { // is_down_event false if (!last_logical_record) { // The physical key has been released before. It might indicate a missed // event due to loss of focus, or multiple keyboards pressed keys with the diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index 8fb55abcd09cd..65b0461000e29 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -26,7 +26,7 @@ constexpr guint16 kKeyCodeNumLock = 0x4du; constexpr uint64_t kPhysicalKeyA = 0x00070004; // constexpr uint64_t kPhysicalKeyQ = 0x00070014; -// constexpr uint64_t kPhysicalControlLeft = 0x000700e0; +constexpr uint64_t kPhysicalControlLeft = 0x000700e0; // constexpr uint64_t kPhysicalControlRight = 0x000700e4; // constexpr uint64_t kPhysicalShiftLeft = 0x000700e1; constexpr uint64_t kPhysicalShiftRight = 0x000700e5; @@ -35,7 +35,7 @@ constexpr uint64_t kPhysicalKeyNumLock = 0x00070053; constexpr uint64_t kLogicalKeyA = 0x00000061; constexpr uint64_t kLogicalKeyQ = 0x00000071; -// constexpr uint64_t kLogicalControlLeft = 0x00300000105; +constexpr uint64_t kLogicalControlLeft = 0x00300000105; // constexpr uint64_t kLogicalControlRight = 0x00400000105; // constexpr uint64_t kLogicalShiftLeft = 0x0030000010d; constexpr uint64_t kLogicalShiftRight = 0x0040000010d; @@ -312,7 +312,7 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { // Release shift right fl_key_responder_handle_event( responder, - key_event_new(103, kRelease, GDK_KEY_Shift_R, kKeyCodeShiftRight, 0x11, + key_event_new(103, kRelease, GDK_KEY_Shift_R, kKeyCodeShiftRight, 0x1, kIsModifier), responder_callback, &user_data); @@ -450,8 +450,7 @@ TEST(FlKeyEmbedderResponderTest, IgnoreDuplicateDownEvent) { // Press KeyA fl_key_responder_handle_event( responder, - key_event_new(101, kPress, GDK_KEY_a, kKeyCodeKeyA, 0, - kIsNotModifier), + key_event_new(101, kPress, GDK_KEY_a, kKeyCodeKeyA, 0, kIsNotModifier), responder_callback, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -464,8 +463,7 @@ TEST(FlKeyEmbedderResponderTest, IgnoreDuplicateDownEvent) { // coverage). fl_key_responder_handle_event( responder, - key_event_new(102, kPress, GDK_KEY_q, kKeyCodeKeyA, 0, - kIsNotModifier), + key_event_new(102, kPress, GDK_KEY_q, kKeyCodeKeyA, 0, kIsNotModifier), responder_callback, &user_data); EXPECT_EQ(g_call_records->len, 0u); @@ -473,8 +471,7 @@ TEST(FlKeyEmbedderResponderTest, IgnoreDuplicateDownEvent) { // Release KeyA fl_key_responder_handle_event( responder, - key_event_new(103, kRelease, GDK_KEY_q, kKeyCodeKeyA, 0, - kIsNotModifier), + key_event_new(103, kRelease, GDK_KEY_q, kKeyCodeKeyA, 0, kIsNotModifier), responder_callback, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -496,9 +493,84 @@ TEST(FlKeyEmbedderResponderTest, IgnoreAbruptUpEvent) { // Release KeyA before it was even pressed. fl_key_responder_handle_event( responder, - key_event_new(103, kRelease, GDK_KEY_q, kKeyCodeKeyA, 0, - kIsNotModifier), + key_event_new(103, kRelease, GDK_KEY_q, kKeyCodeKeyA, 0, kIsNotModifier), responder_callback, &user_data); EXPECT_EQ(g_call_records->len, 0u); + + g_clear_object(&g_call_records); +} + +// Press Shift, key A, then release Shift, key A. +TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingState) { + EXPECT_EQ(g_call_records, nullptr); + g_call_records = g_ptr_array_new_with_free_func(g_object_unref); + g_autoptr(FlEngine) engine = make_mock_engine_with_records(); + g_autoptr(FlKeyResponder) responder = + FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); + int user_data = 123; // Arbitrary user data + + FlKeyEmbedderCallRecord* record; + + // A key down of control left is missed. + guint state = GDK_CONTROL_MASK; + + // Send a normal event + fl_key_responder_handle_event( + responder, + key_event_new(101, kPress, GDK_KEY_a, kKeyCodeKeyA, state, + kIsNotModifier), + responder_callback, &user_data); + + EXPECT_EQ(g_call_records->len, 2u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->timestamp, 101000); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->physical, kPhysicalControlLeft); + EXPECT_EQ(record->event->logical, kLogicalControlLeft); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, true); + + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 1)); + EXPECT_EQ(record->event->timestamp, 101000); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->physical, kPhysicalKeyA); + EXPECT_EQ(record->event->logical, kLogicalKeyA); + EXPECT_STREQ(record->event->character, "a"); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + // A key up of control right is missed. + state = 0; + + // Release key A + fl_key_responder_handle_event( + responder, + key_event_new(102, kRelease, GDK_KEY_A, kKeyCodeKeyA, state, + kIsNotModifier), + responder_callback, &user_data); + + EXPECT_EQ(g_call_records->len, 2u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->timestamp, 102000); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); + EXPECT_EQ(record->event->physical, kPhysicalControlLeft); + EXPECT_EQ(record->event->logical, kLogicalControlLeft); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, true); + + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 1)); + EXPECT_EQ(record->event->timestamp, 102000); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); + EXPECT_EQ(record->event->physical, kPhysicalKeyA); + EXPECT_EQ(record->event->logical, kLogicalKeyA); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + g_clear_object(&g_call_records); } From 886d43bb6346db23877af46d3680affe67164b03 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Thu, 15 Apr 2021 03:30:51 -0700 Subject: [PATCH 033/126] Syn lock mode --- .../linux/fl_key_embedder_responder.cc | 235 +++++++++++++++--- .../linux/fl_key_embedder_responder_test.cc | 8 +- shell/platform/linux/key_mapping.cc | 14 +- shell/platform/linux/key_mapping.h | 2 +- 4 files changed, 215 insertions(+), 44 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index 696b978d8109a..d5370ef4ce544 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -96,13 +96,19 @@ struct _FlKeyEmbedderResponder { // Both keys and values are directly stored uint64s. GHashTable* pressing_records; + guint lock_mode_records; + // A static map from XKB to Flutter's physical key code GHashTable* xkb_to_physical_key; // A static map from GTK keyval to Flutter's logical key code GHashTable* keyval_to_logical_key; - GHashTable* modifier_bit_to_physical_keys; + GHashTable* modifier_bit_to_checked_keys; + + GHashTable* lock_mode_bit_to_checked_keys; + + GHashTable* physical_key_to_lock_mode_bit; }; static void fl_key_embedder_responder_iface_init( @@ -133,7 +139,8 @@ static void fl_key_embedder_responder_dispose(GObject* object) { g_clear_pointer(&self->pressing_records, g_hash_table_unref); g_clear_pointer(&self->xkb_to_physical_key, g_hash_table_unref); g_clear_pointer(&self->keyval_to_logical_key, g_hash_table_unref); - g_clear_pointer(&self->modifier_bit_to_physical_keys, g_hash_table_unref); + g_clear_pointer(&self->modifier_bit_to_checked_keys, g_hash_table_unref); + g_clear_pointer(&self->lock_mode_bit_to_checked_keys, g_hash_table_unref); G_OBJECT_CLASS(fl_key_embedder_responder_parent_class)->dispose(object); } @@ -154,6 +161,16 @@ static void checked_key_free_notify(gpointer pointer) { g_free(checked_key); } +static void initialize_physical_key_to_lock_mode_bit_loop_body(gpointer lock_mode_bit, + gpointer value, + gpointer user_data) { + FlKeyEmbedderCheckedKey* checked_key = + reinterpret_cast(value); + GHashTable* table = reinterpret_cast(user_data); + g_hash_table_insert(table, uint64_to_gpointer(checked_key->physical_keys[0]), + GUINT_TO_POINTER(lock_mode_bit)); +} + // Creates a new FlKeyEmbedderResponder instance, with a messenger used to send // messages to the framework, an FlTextInputPlugin used to handle key events // that the framework doesn't handle. Mainly for testing purposes, it also takes @@ -172,13 +189,26 @@ FlKeyEmbedderResponder* fl_key_embedder_responder_new(FlEngine* engine) { reinterpret_cast(&(self->engine))); self->pressing_records = g_hash_table_new(g_direct_hash, g_direct_equal); + self->lock_mode_records = 0; + self->xkb_to_physical_key = g_hash_table_new(g_direct_hash, g_direct_equal); initialize_xkb_to_physical_key(self->xkb_to_physical_key); + self->keyval_to_logical_key = g_hash_table_new(g_direct_hash, g_direct_equal); initialize_gtk_keyval_to_logical_key(self->keyval_to_logical_key); - self->modifier_bit_to_physical_keys = g_hash_table_new_full( + + self->modifier_bit_to_checked_keys = g_hash_table_new_full( + g_direct_hash, g_direct_equal, NULL, checked_key_free_notify); + initialize_modifier_bit_to_checked_keys(self->modifier_bit_to_checked_keys); + + self->lock_mode_bit_to_checked_keys = g_hash_table_new_full( g_direct_hash, g_direct_equal, NULL, checked_key_free_notify); - initialize_modifier_bit_to_checked_keys(self->modifier_bit_to_physical_keys); + initialize_lock_mode_bit_to_checked_keys(self->lock_mode_bit_to_checked_keys); + + self->physical_key_to_lock_mode_bit = g_hash_table_new(g_direct_hash, g_direct_equal); + g_hash_table_foreach(self->lock_mode_bit_to_checked_keys, + initialize_physical_key_to_lock_mode_bit_loop_body, + self->physical_key_to_lock_mode_bit); return self; } @@ -290,7 +320,8 @@ namespace { typedef struct { FlKeyEmbedderResponder* self; guint state; - uint64_t current_physical_key; + uint64_t event_physical_key; + bool is_down; double timestamp; } SyncPressedStatesLoopContext; } // namespace @@ -303,34 +334,34 @@ static void synchronize_pressed_states_loop_body(gpointer key, FlKeyEmbedderCheckedKey* checked_key = reinterpret_cast(value); - guint modifier_bit = GPOINTER_TO_INT(key); + const guint modifier_bit = GPOINTER_TO_INT(key); FlKeyEmbedderResponder* self = context->self; - uint64_t* physical_keys = checked_key->physical_keys; - printf("Syn: 1 state %x bit %x curPhy %lx\n", context->state, modifier_bit, context->current_physical_key); + const uint64_t* physical_keys = checked_key->physical_keys; + // printf("Syn: 1 state %x bit %x curPhy %lx\n", context->state, modifier_bit, context->event_physical_key); - bool pressed_by_state = context->state & modifier_bit; + const bool pressed_by_state = (context->state & modifier_bit) != 0; bool pressed_by_record = false; for (guint physical_key_idx = 0; physical_key_idx < checked_key->length; physical_key_idx++) { - uint64_t physical_key = physical_keys[physical_key_idx]; - uint64_t logical_key = + const uint64_t physical_key = physical_keys[physical_key_idx]; + const uint64_t pressed_logical_key = lookup_hash_table(self->pressing_records, physical_key); - // If this event is the down event of the key, then the state will be - // flipped but haven't reflected on the state. Flip it manually here. - bool adjusted_this_key_pressed = - (logical_key != 0) ^ - (physical_key == context->current_physical_key); + // If this event is an event of the key, then the state will be flipped but + // haven't reflected on the state. Flip it manually here. + const bool adjusted_this_key_pressed = + (pressed_logical_key != 0) ^ + (physical_key == context->event_physical_key); - printf("Syn: 2 phy %lx record %lx adju %d\n", physical_key, logical_key, adjusted_this_key_pressed); + // printf("Syn: 2 phy %lx record %lx adju %d\n", physical_key, pressed_logical_key, adjusted_this_key_pressed); if (adjusted_this_key_pressed) { pressed_by_record = true; if (!pressed_by_state) { - printf("Syn: 3 SYN: phy %lx log %lx currPh %lx\n", physical_key, - logical_key, context->current_physical_key); - g_return_if_fail(physical_key != context->current_physical_key); + // printf("Syn: 3 SYN: phy %lx log %lx currPh %lx\n", physical_key, + // pressed_logical_key, context->event_physical_key); + g_return_if_fail(physical_key != context->event_physical_key); synthesize_simple_event(self, kFlutterKeyEventTypeUp, physical_key, - logical_key, context->timestamp); + pressed_logical_key, context->timestamp); g_hash_table_remove(self->pressing_records, uint64_to_gpointer(physical_key)); } @@ -338,9 +369,9 @@ static void synchronize_pressed_states_loop_body(gpointer key, } if (pressed_by_state && !pressed_by_record) { uint64_t physical_key = physical_keys[0]; - g_return_if_fail(physical_key != context->current_physical_key); + g_return_if_fail(physical_key != context->event_physical_key); uint64_t logical_key = checked_key->first_logical_key; - printf("Syn: 4 SYN: phy %lx log %lx\n", physical_key, logical_key); + // printf("Syn: 4 SYN: phy %lx log %lx\n", physical_key, logical_key); synthesize_simple_event(self, kFlutterKeyEventTypeDown, physical_key, logical_key, context->timestamp); g_hash_table_insert(self->pressing_records, @@ -349,6 +380,139 @@ static void synchronize_pressed_states_loop_body(gpointer key, } } +// Find the stage # before the event (of the 4 stages as documented in +// `synchronize_lock_mode_states_loop_body`) by the current record. +static int find_stage_by_record(bool is_down, bool is_enabled) { + constexpr int stage_by_record_index[] = { + 0, // isDown: 0, isEnabled: 0 + 2, // 0 1 + 3, // 1 0 + 1 // 1 1 + }; + return stage_by_record_index[(is_down << 1) + is_enabled]; +} + +// Find the stage # before the event (of the 4 stages as documented in +// `synchronize_lock_mode_states_loop_body`) by the event. +static int find_stage_by_event(bool is_down, bool is_enabled) { + constexpr int stage_by_record_index[] = { + 3, // isDown: 0, isEnabled: 0 + 1, // 0 1 + 0, // 1 0 + 2 // 1 1 + }; + return stage_by_record_index[(is_down << 1) + is_enabled]; +} + +// Find the first stage # greater than `start` that is equivalent to `target` in +// a cycle of 4. +// +// That is, if `target` is less than `start`, return target + 4. +static int cycle_stage_to_after(int target, int start) { + g_return_val_if_fail(target >= -4 && target < 4, target); + g_return_val_if_fail(start >= 0 && start < 4, target); + constexpr int kNumStages = 4; + return target >= start ? target : target + kNumStages; +} + +static int find_closest_next_stage(int start, int option1, int option2) { + const int adjusted_option1 = cycle_stage_to_after(option1, start); + const int adjusted_option2 = cycle_stage_to_after(option2, start); + return adjusted_option1 < adjusted_option2 ? adjusted_option1 : adjusted_option2; +} + +static void possibly_update_lock_mode_bit(FlKeyEmbedderResponder* self, + uint64_t physical_key, bool is_down) { + if (!is_down) { + return; + } + guint mode_bit = GPOINTER_TO_UINT(g_hash_table_lookup(self->physical_key_to_lock_mode_bit, uint64_to_gpointer(physical_key))); + if (mode_bit != 0) { + self->lock_mode_records ^= mode_bit; + } +} + +static void synchronize_lock_mode_states_loop_body(gpointer key, + gpointer value, + gpointer user_data) { + SyncPressedStatesLoopContext* context = + reinterpret_cast(user_data); + FlKeyEmbedderCheckedKey* checked_key = + reinterpret_cast(value); + + guint modifier_bit = GPOINTER_TO_INT(key); + FlKeyEmbedderResponder* self = context->self; + + const bool is_down_event = context->is_down; + + const uint64_t logical_key = checked_key->first_logical_key; + const uint64_t physical_key = checked_key->physical_keys[0]; + // printf("Syn: 1 state %x bit %x curPhy %lx\n", context->state, modifier_bit, context->event_physical_key); + + // A lock mode key can be at any of a 4-stage cycle: + // + // Up,Disabled -> Down,Enabled -> Up,Enabled -> Down,Disabled -> + // [0] [1] [2] [3] + // EventType: Down Up Down Up + // State: 0 1 1 0 + // + // If the incoming event is the target key, then we know exactly which stage + // the true state is at. + // + // Otherwise, since we only know "state", we can tell if the true stage is + // either 0/3 or 1/2. Choose the shorter one. + + const uint64_t pressed_logical_key = + lookup_hash_table(self->pressing_records, physical_key); + // For simplicity, we're not considering remapped lock keys until we meet such cases. + g_return_if_fail(pressed_logical_key == 0 || pressed_logical_key == logical_key); + const bool pressed_by_record = pressed_logical_key != 0; + const bool enabled_by_record = (self->lock_mode_records & modifier_bit) != 0; + const int stage_by_record = find_stage_by_record(pressed_by_record, enabled_by_record); + + const bool event_is_target_key = physical_key == context->event_physical_key; + printf("SynLock: evtIsTarget %d ph %lx evPh %lx\n", event_is_target_key, physical_key, context->event_physical_key); + const bool enabled_by_state = (context->state & modifier_bit) != 0; + const int stage_by_event = event_is_target_key ? + find_stage_by_event(is_down_event, enabled_by_state) : + find_closest_next_stage( + stage_by_record, + find_stage_by_record(true, enabled_by_state), + find_stage_by_record(false, enabled_by_state)); + + // If the event is for the target key, then the last stage transition should be + // handled by the main event logic instead of synthesization. + const int destination_stage = stage_by_event; + + printf("SynLock: stage by recrd %d\n", stage_by_record); + printf("SynLock: stage by event %d\n", stage_by_event); + printf("SynLock: stage by dest %d\n", destination_stage); + g_return_if_fail(stage_by_record <= destination_stage); + if (stage_by_record == destination_stage) { + return; + } + for (int current_stage = stage_by_record; current_stage < destination_stage; current_stage += 1) { + if (current_stage == 9) { + return; + } + printf("SynLock: syn for stage %d\n", current_stage); + + const int standard_current_stage = current_stage >= 4 ? current_stage - 4 : current_stage; + const bool is_down_event = standard_current_stage == 0 || standard_current_stage == 2; + FlutterKeyEventType type = is_down_event ? kFlutterKeyEventTypeDown : kFlutterKeyEventTypeUp; + if (is_down_event) { + g_hash_table_insert(self->pressing_records, + uint64_to_gpointer(physical_key), + uint64_to_gpointer(logical_key)); + } else { + g_hash_table_remove(self->pressing_records, + uint64_to_gpointer(physical_key)); + } + possibly_update_lock_mode_bit(self, physical_key, is_down_event); + synthesize_simple_event(self, type, physical_key, logical_key, context->timestamp); + } +} + static int _text_idx = 0; // Sends a key event to the framework. @@ -357,18 +521,18 @@ static void fl_key_embedder_responder_handle_event( GdkEventKey* event, FlKeyResponderAsyncCallback callback, gpointer user_data) { + FlKeyEmbedderResponder* self = FL_KEY_EMBEDDER_RESPONDER(responder); _text_idx += 1; printf( "#%7s keyval 0x%x keycode 0x%x state 0x%x ismod %d snd %d grp %d " - "time %d [%d]\n", + "time %d [%d] curLock %x\n", event->type == GDK_KEY_PRESS ? "PRESS" : "RELEASE", event->keyval, event->hardware_keycode, event->state, event->is_modifier, - event->send_event, event->group, event->time, _text_idx); + event->send_event, event->group, event->time, _text_idx, self->lock_mode_records); fflush(stdout); g_return_if_fail(event != nullptr); g_return_if_fail(callback != nullptr); - FlKeyEmbedderResponder* self = FL_KEY_EMBEDDER_RESPONDER(responder); uint64_t physical_key = event_to_physical_key(event, self->xkb_to_physical_key); @@ -384,6 +548,17 @@ static void fl_key_embedder_responder_handle_event( // next_logical_record, is_down_event, event->type); // fflush(stdout); + SyncPressedStatesLoopContext sync_pressed_state_context; + sync_pressed_state_context.self = self; + sync_pressed_state_context.state = event->state; + sync_pressed_state_context.timestamp = timestamp; + sync_pressed_state_context.is_down = is_down_event; + sync_pressed_state_context.event_physical_key = physical_key; + + g_hash_table_foreach(self->lock_mode_bit_to_checked_keys, + synchronize_lock_mode_states_loop_body, + &sync_pressed_state_context); + if (is_down_event) { g_hash_table_insert(self->pressing_records, uint64_to_gpointer(physical_key), @@ -392,14 +567,10 @@ static void fl_key_embedder_responder_handle_event( g_hash_table_remove(self->pressing_records, uint64_to_gpointer(physical_key)); } + possibly_update_lock_mode_bit(self, physical_key, is_down_event); // printf("Before foreach\n"); - SyncPressedStatesLoopContext sync_pressed_state_context; - sync_pressed_state_context.self = self; - sync_pressed_state_context.state = event->state; - sync_pressed_state_context.timestamp = timestamp; - sync_pressed_state_context.current_physical_key = physical_key; - g_hash_table_foreach(self->modifier_bit_to_physical_keys, + g_hash_table_foreach(self->modifier_bit_to_checked_keys, synchronize_pressed_states_loop_body, &sync_pressed_state_context); diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index 65b0461000e29..948f3f12b30f1 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -365,7 +365,7 @@ TEST(FlKeyEmbedderResponderTest, TapNumLockDuringNumpadKeyTap) { // Press Numpad 1 fl_key_responder_handle_event( responder, - key_event_new(101, kPress, GDK_KEY_KP_1, kKeyCodeNumpad1, 0x10, + key_event_new(101, kPress, GDK_KEY_KP_End, kKeyCodeNumpad1, 0, kIsNotModifier), responder_callback, &user_data); @@ -374,7 +374,7 @@ TEST(FlKeyEmbedderResponderTest, TapNumLockDuringNumpadKeyTap) { EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); EXPECT_EQ(record->event->physical, kPhysicalKeyNumpad1); EXPECT_EQ(record->event->logical, kLogicalKeyNumpad1); - EXPECT_STREQ(record->event->character, "1"); + EXPECT_STREQ(record->event->character, nullptr); // TODO EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); @@ -383,7 +383,7 @@ TEST(FlKeyEmbedderResponderTest, TapNumLockDuringNumpadKeyTap) { // Press NumLock fl_key_responder_handle_event( responder, - key_event_new(102, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock, 0x10, + key_event_new(102, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock, 0, kIsNotModifier), responder_callback, &user_data); @@ -419,7 +419,7 @@ TEST(FlKeyEmbedderResponderTest, TapNumLockDuringNumpadKeyTap) { // Release numpad 1 fl_key_responder_handle_event( responder, - key_event_new(104, kRelease, GDK_KEY_KP_End, kKeyCodeNumpad1, 0, + key_event_new(104, kRelease, GDK_KEY_KP_1, kKeyCodeNumpad1, 0x10, kIsNotModifier), responder_callback, &user_data); diff --git a/shell/platform/linux/key_mapping.cc b/shell/platform/linux/key_mapping.cc index 0ca865489f111..1a1e240f98126 100644 --- a/shell/platform/linux/key_mapping.cc +++ b/shell/platform/linux/key_mapping.cc @@ -426,7 +426,7 @@ void initialize_modifier_bit_to_checked_keys(GHashTable* table) { data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_SHIFT_MASK), data); data->length = 2; - data->first_logical_key = 0x30000010d; // shiftLeft + data->first_logical_key = 0x30000010d; // shiftLeft physical_keys = g_new(uint64_t, 2); data->physical_keys = physical_keys; *(physical_keys++) = 0x000700e1; // ShiftLeft @@ -435,7 +435,7 @@ void initialize_modifier_bit_to_checked_keys(GHashTable* table) { data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_CONTROL_MASK), data); data->length = 2; - data->first_logical_key = 0x300000105; // controlLeft + data->first_logical_key = 0x300000105; // controlLeft physical_keys = g_new(uint64_t, 2); data->physical_keys = physical_keys; *(physical_keys++) = 0x000700e0; // ControlLeft @@ -444,7 +444,7 @@ void initialize_modifier_bit_to_checked_keys(GHashTable* table) { data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_MOD1_MASK), data); data->length = 2; - data->first_logical_key = 0x300000102; // altLeft + data->first_logical_key = 0x300000102; // altLeft physical_keys = g_new(uint64_t, 2); data->physical_keys = physical_keys; *(physical_keys++) = 0x000700e2; // AltLeft @@ -453,21 +453,21 @@ void initialize_modifier_bit_to_checked_keys(GHashTable* table) { data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_MOD4_MASK), data); data->length = 2; - data->first_logical_key = 0x300000109; // metaLeft + data->first_logical_key = 0x300000109; // metaLeft physical_keys = g_new(uint64_t, 2); data->physical_keys = physical_keys; *(physical_keys++) = 0x000700e3; // MetaLeft *(physical_keys++) = 0x000700e7; // MetaRight } -void initialize_mode_bit_to_checked_keys(GHashTable* table) { +void initialize_lock_mode_bit_to_checked_keys(GHashTable* table) { FlKeyEmbedderCheckedKey* data; uint64_t* physical_keys; data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_LOCK_MASK), data); data->length = 1; - data->first_logical_key = 0x000000104; // capsLock + data->first_logical_key = 0x000000104; // capsLock physical_keys = g_new(uint64_t, 1); data->physical_keys = physical_keys; *(physical_keys++) = 0x00070039; // CapsLock @@ -475,7 +475,7 @@ void initialize_mode_bit_to_checked_keys(GHashTable* table) { data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_MOD2_MASK), data); data->length = 1; - data->first_logical_key = 0x00000010a; // numLock + data->first_logical_key = 0x00000010a; // numLock physical_keys = g_new(uint64_t, 1); data->physical_keys = physical_keys; *(physical_keys++) = 0x00070053; // NumLock diff --git a/shell/platform/linux/key_mapping.h b/shell/platform/linux/key_mapping.h index a4e466fb7dd9e..88c9c36b9fa9b 100644 --- a/shell/platform/linux/key_mapping.h +++ b/shell/platform/linux/key_mapping.h @@ -26,6 +26,6 @@ void initialize_gtk_keyval_to_logical_key(GHashTable* table); void initialize_modifier_bit_to_checked_keys(GHashTable* table); -void initialize_mode_bit_to_checked_keys(GHashTable* table); +void initialize_lock_mode_bit_to_checked_keys(GHashTable* table); #endif // KEYBOARD_MAP_H_ From a984ccc03852eaa1a1fb4f129d1e3fce8182ed1a Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Thu, 15 Apr 2021 15:24:40 -0700 Subject: [PATCH 034/126] Sync lock mode test --- .../linux/fl_key_embedder_responder.cc | 147 ++++++++++-------- .../linux/fl_key_embedder_responder_test.cc | 139 ++++++++++++++--- shell/platform/linux/fl_message_codec_test.cc | 4 - shell/platform/linux/key_mapping.cc | 12 +- 4 files changed, 210 insertions(+), 92 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index d5370ef4ce544..b9175415a6f90 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -161,14 +161,15 @@ static void checked_key_free_notify(gpointer pointer) { g_free(checked_key); } -static void initialize_physical_key_to_lock_mode_bit_loop_body(gpointer lock_mode_bit, - gpointer value, - gpointer user_data) { +static void initialize_physical_key_to_lock_mode_bit_loop_body( + gpointer lock_mode_bit, + gpointer value, + gpointer user_data) { FlKeyEmbedderCheckedKey* checked_key = reinterpret_cast(value); GHashTable* table = reinterpret_cast(user_data); g_hash_table_insert(table, uint64_to_gpointer(checked_key->physical_keys[0]), - GUINT_TO_POINTER(lock_mode_bit)); + GUINT_TO_POINTER(lock_mode_bit)); } // Creates a new FlKeyEmbedderResponder instance, with a messenger used to send @@ -205,10 +206,11 @@ FlKeyEmbedderResponder* fl_key_embedder_responder_new(FlEngine* engine) { g_direct_hash, g_direct_equal, NULL, checked_key_free_notify); initialize_lock_mode_bit_to_checked_keys(self->lock_mode_bit_to_checked_keys); - self->physical_key_to_lock_mode_bit = g_hash_table_new(g_direct_hash, g_direct_equal); + self->physical_key_to_lock_mode_bit = + g_hash_table_new(g_direct_hash, g_direct_equal); g_hash_table_foreach(self->lock_mode_bit_to_checked_keys, - initialize_physical_key_to_lock_mode_bit_loop_body, - self->physical_key_to_lock_mode_bit); + initialize_physical_key_to_lock_mode_bit_loop_body, + self->physical_key_to_lock_mode_bit); return self; } @@ -337,7 +339,8 @@ static void synchronize_pressed_states_loop_body(gpointer key, const guint modifier_bit = GPOINTER_TO_INT(key); FlKeyEmbedderResponder* self = context->self; const uint64_t* physical_keys = checked_key->physical_keys; - // printf("Syn: 1 state %x bit %x curPhy %lx\n", context->state, modifier_bit, context->event_physical_key); + // printf("Syn: 1 state %x bit %x curPhy %lx\n", context->state, modifier_bit, + // context->event_physical_key); const bool pressed_by_state = (context->state & modifier_bit) != 0; bool pressed_by_record = false; @@ -353,7 +356,8 @@ static void synchronize_pressed_states_loop_body(gpointer key, (pressed_logical_key != 0) ^ (physical_key == context->event_physical_key); - // printf("Syn: 2 phy %lx record %lx adju %d\n", physical_key, pressed_logical_key, adjusted_this_key_pressed); + // printf("Syn: 2 phy %lx record %lx adju %d\n", physical_key, + // pressed_logical_key, adjusted_this_key_pressed); if (adjusted_this_key_pressed) { pressed_by_record = true; if (!pressed_by_state) { @@ -384,10 +388,10 @@ static void synchronize_pressed_states_loop_body(gpointer key, // `synchronize_lock_mode_states_loop_body`) by the current record. static int find_stage_by_record(bool is_down, bool is_enabled) { constexpr int stage_by_record_index[] = { - 0, // isDown: 0, isEnabled: 0 - 2, // 0 1 - 3, // 1 0 - 1 // 1 1 + 0, // isDown: 0, isEnabled: 0 + 2, // 0 1 + 3, // 1 0 + 1 // 1 1 }; return stage_by_record_index[(is_down << 1) + is_enabled]; } @@ -396,10 +400,10 @@ static int find_stage_by_record(bool is_down, bool is_enabled) { // `synchronize_lock_mode_states_loop_body`) by the event. static int find_stage_by_event(bool is_down, bool is_enabled) { constexpr int stage_by_record_index[] = { - 3, // isDown: 0, isEnabled: 0 - 1, // 0 1 - 0, // 1 0 - 2 // 1 1 + 3, // isDown: 0, isEnabled: 0 + 1, // 0 1 + 0, // 1 0 + 2 // 1 1 }; return stage_by_record_index[(is_down << 1) + is_enabled]; } @@ -418,23 +422,41 @@ static int cycle_stage_to_after(int target, int start) { static int find_closest_next_stage(int start, int option1, int option2) { const int adjusted_option1 = cycle_stage_to_after(option1, start); const int adjusted_option2 = cycle_stage_to_after(option2, start); - return adjusted_option1 < adjusted_option2 ? adjusted_option1 : adjusted_option2; + return adjusted_option1 < adjusted_option2 ? adjusted_option1 + : adjusted_option2; +} + +static void update_pressing_state(FlKeyEmbedderResponder* self, + uint64_t physical_key, + uint64_t logical_key) { + if (logical_key != 0) { + g_return_if_fail(lookup_hash_table(self->pressing_records, physical_key) == 0); + g_hash_table_insert(self->pressing_records, + uint64_to_gpointer(physical_key), + uint64_to_gpointer(logical_key)); + } else { + g_return_if_fail(lookup_hash_table(self->pressing_records, physical_key) != 0); + g_hash_table_remove(self->pressing_records, + uint64_to_gpointer(physical_key)); + } } static void possibly_update_lock_mode_bit(FlKeyEmbedderResponder* self, - uint64_t physical_key, bool is_down) { + uint64_t physical_key, + bool is_down) { if (!is_down) { return; } - guint mode_bit = GPOINTER_TO_UINT(g_hash_table_lookup(self->physical_key_to_lock_mode_bit, uint64_to_gpointer(physical_key))); + guint mode_bit = GPOINTER_TO_UINT(g_hash_table_lookup( + self->physical_key_to_lock_mode_bit, uint64_to_gpointer(physical_key))); if (mode_bit != 0) { self->lock_mode_records ^= mode_bit; } } static void synchronize_lock_mode_states_loop_body(gpointer key, - gpointer value, - gpointer user_data) { + gpointer value, + gpointer user_data) { SyncPressedStatesLoopContext* context = reinterpret_cast(user_data); FlKeyEmbedderCheckedKey* checked_key = @@ -447,7 +469,8 @@ static void synchronize_lock_mode_states_loop_body(gpointer key, const uint64_t logical_key = checked_key->first_logical_key; const uint64_t physical_key = checked_key->physical_keys[0]; - // printf("Syn: 1 state %x bit %x curPhy %lx\n", context->state, modifier_bit, context->event_physical_key); + // printf("Syn: 1 state %x bit %x curPhy %lx\n", context->state, modifier_bit, + // context->event_physical_key); // A lock mode key can be at any of a 4-stage cycle: // @@ -463,25 +486,29 @@ static void synchronize_lock_mode_states_loop_body(gpointer key, // either 0/3 or 1/2. Choose the shorter one. const uint64_t pressed_logical_key = - lookup_hash_table(self->pressing_records, physical_key); - // For simplicity, we're not considering remapped lock keys until we meet such cases. - g_return_if_fail(pressed_logical_key == 0 || pressed_logical_key == logical_key); + lookup_hash_table(self->pressing_records, physical_key); + // For simplicity, we're not considering remapped lock keys until we meet such + // cases. + g_return_if_fail(pressed_logical_key == 0 || + pressed_logical_key == logical_key); const bool pressed_by_record = pressed_logical_key != 0; const bool enabled_by_record = (self->lock_mode_records & modifier_bit) != 0; - const int stage_by_record = find_stage_by_record(pressed_by_record, enabled_by_record); + const int stage_by_record = + find_stage_by_record(pressed_by_record, enabled_by_record); const bool event_is_target_key = physical_key == context->event_physical_key; - printf("SynLock: evtIsTarget %d ph %lx evPh %lx\n", event_is_target_key, physical_key, context->event_physical_key); + printf("SynLock: evtIsTarget %d ph %lx evPh %lx\n", event_is_target_key, + physical_key, context->event_physical_key); const bool enabled_by_state = (context->state & modifier_bit) != 0; - const int stage_by_event = event_is_target_key ? - find_stage_by_event(is_down_event, enabled_by_state) : - find_closest_next_stage( - stage_by_record, - find_stage_by_record(true, enabled_by_state), - find_stage_by_record(false, enabled_by_state)); - - // If the event is for the target key, then the last stage transition should be - // handled by the main event logic instead of synthesization. + const int stage_by_event = + event_is_target_key + ? find_stage_by_event(is_down_event, enabled_by_state) + : find_closest_next_stage( + stage_by_record, find_stage_by_record(true, enabled_by_state), + find_stage_by_record(false, enabled_by_state)); + + // If the event is for the target key, then the last stage transition should + // be handled by the main event logic instead of synthesization. const int destination_stage = stage_by_event; printf("SynLock: stage by recrd %d\n", stage_by_record); @@ -491,25 +518,26 @@ static void synchronize_lock_mode_states_loop_body(gpointer key, if (stage_by_record == destination_stage) { return; } - for (int current_stage = stage_by_record; current_stage < destination_stage; current_stage += 1) { + for (int current_stage = stage_by_record; current_stage < destination_stage; + current_stage += 1) { if (current_stage == 9) { return; } printf("SynLock: syn for stage %d\n", current_stage); - const int standard_current_stage = current_stage >= 4 ? current_stage - 4 : current_stage; - const bool is_down_event = standard_current_stage == 0 || standard_current_stage == 2; - FlutterKeyEventType type = is_down_event ? kFlutterKeyEventTypeDown : kFlutterKeyEventTypeUp; - if (is_down_event) { - g_hash_table_insert(self->pressing_records, - uint64_to_gpointer(physical_key), - uint64_to_gpointer(logical_key)); - } else { - g_hash_table_remove(self->pressing_records, - uint64_to_gpointer(physical_key)); - } + const int standard_current_stage = + current_stage >= 4 ? current_stage - 4 : current_stage; + const bool is_down_event = + standard_current_stage == 0 || standard_current_stage == 2; + FlutterKeyEventType type = + is_down_event ? kFlutterKeyEventTypeDown : kFlutterKeyEventTypeUp; + update_pressing_state( + self, + physical_key, + is_down_event ? logical_key : 0); possibly_update_lock_mode_bit(self, physical_key, is_down_event); - synthesize_simple_event(self, type, physical_key, logical_key, context->timestamp); + synthesize_simple_event(self, type, physical_key, logical_key, + context->timestamp); } } @@ -528,7 +556,8 @@ static void fl_key_embedder_responder_handle_event( "time %d [%d] curLock %x\n", event->type == GDK_KEY_PRESS ? "PRESS" : "RELEASE", event->keyval, event->hardware_keycode, event->state, event->is_modifier, - event->send_event, event->group, event->time, _text_idx, self->lock_mode_records); + event->send_event, event->group, event->time, _text_idx, + self->lock_mode_records); fflush(stdout); g_return_if_fail(event != nullptr); @@ -556,17 +585,13 @@ static void fl_key_embedder_responder_handle_event( sync_pressed_state_context.event_physical_key = physical_key; g_hash_table_foreach(self->lock_mode_bit_to_checked_keys, - synchronize_lock_mode_states_loop_body, - &sync_pressed_state_context); + synchronize_lock_mode_states_loop_body, + &sync_pressed_state_context); - if (is_down_event) { - g_hash_table_insert(self->pressing_records, - uint64_to_gpointer(physical_key), - uint64_to_gpointer(logical_key)); - } else { - g_hash_table_remove(self->pressing_records, - uint64_to_gpointer(physical_key)); - } + update_pressing_state( + self, + physical_key, + is_down_event ? logical_key : 0); possibly_update_lock_mode_bit(self, physical_key, is_down_event); // printf("Before foreach\n"); diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index 948f3f12b30f1..2f2ff00b88534 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -138,7 +138,7 @@ static GdkEventKey* key_event_new(guint32 time_in_milliseconds, static gboolean g_expected_handled; static gpointer g_expected_user_data; -static void responder_callback(bool handled, gpointer user_data) { +static void verify_response_handled(bool handled, gpointer user_data) { EXPECT_EQ(handled, g_expected_handled); } @@ -185,7 +185,7 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { fl_key_responder_handle_event( responder, key_event_new(12345, kPress, GDK_KEY_a, kKeyCodeKeyA, 0, kIsNotModifier), - responder_callback, &user_data); + verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); @@ -206,7 +206,7 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { fl_key_responder_handle_event(responder, key_event_new(12346, kRelease, GDK_KEY_a, kKeyCodeKeyA, 0, kIsNotModifier), - responder_callback, &user_data); + verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); @@ -226,7 +226,7 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { fl_key_responder_handle_event( responder, key_event_new(12347, kPress, GDK_KEY_q, kKeyCodeKeyA, 0, kIsNotModifier), - responder_callback, &user_data); + verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); @@ -245,7 +245,7 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { fl_key_responder_handle_event(responder, key_event_new(12348, kRelease, GDK_KEY_q, kKeyCodeKeyA, 0, kIsNotModifier), - responder_callback, &user_data); + verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); @@ -279,7 +279,7 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { responder, key_event_new(101, kPress, GDK_KEY_Shift_R, kKeyCodeShiftRight, 0, kIsModifier), - responder_callback, &user_data); + verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); @@ -296,7 +296,7 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { fl_key_responder_handle_event( responder, key_event_new(102, kPress, GDK_KEY_A, kKeyCodeKeyA, 0x1, kIsNotModifier), - responder_callback, &user_data); + verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); @@ -314,7 +314,7 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { responder, key_event_new(103, kRelease, GDK_KEY_Shift_R, kKeyCodeShiftRight, 0x1, kIsModifier), - responder_callback, &user_data); + verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); @@ -331,7 +331,7 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { fl_key_responder_handle_event( responder, key_event_new(104, kRelease, GDK_KEY_A, kKeyCodeKeyA, 0, kIsNotModifier), - responder_callback, &user_data); + verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); @@ -367,14 +367,14 @@ TEST(FlKeyEmbedderResponderTest, TapNumLockDuringNumpadKeyTap) { responder, key_event_new(101, kPress, GDK_KEY_KP_End, kKeyCodeNumpad1, 0, kIsNotModifier), - responder_callback, &user_data); + verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); EXPECT_EQ(record->event->physical, kPhysicalKeyNumpad1); EXPECT_EQ(record->event->logical, kLogicalKeyNumpad1); - EXPECT_STREQ(record->event->character, nullptr); // TODO + EXPECT_STREQ(record->event->character, nullptr); // TODO EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); @@ -385,7 +385,7 @@ TEST(FlKeyEmbedderResponderTest, TapNumLockDuringNumpadKeyTap) { responder, key_event_new(102, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock, 0, kIsNotModifier), - responder_callback, &user_data); + verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); @@ -403,7 +403,7 @@ TEST(FlKeyEmbedderResponderTest, TapNumLockDuringNumpadKeyTap) { responder, key_event_new(103, kRelease, GDK_KEY_Num_Lock, kKeyCodeNumLock, 0x10, kIsModifier), - responder_callback, &user_data); + verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); @@ -421,7 +421,7 @@ TEST(FlKeyEmbedderResponderTest, TapNumLockDuringNumpadKeyTap) { responder, key_event_new(104, kRelease, GDK_KEY_KP_1, kKeyCodeNumpad1, 0x10, kIsNotModifier), - responder_callback, &user_data); + verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); @@ -451,7 +451,7 @@ TEST(FlKeyEmbedderResponderTest, IgnoreDuplicateDownEvent) { fl_key_responder_handle_event( responder, key_event_new(101, kPress, GDK_KEY_a, kKeyCodeKeyA, 0, kIsNotModifier), - responder_callback, &user_data); + verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -461,10 +461,11 @@ TEST(FlKeyEmbedderResponderTest, IgnoreDuplicateDownEvent) { // Press KeyA again (with different logical key, not necessarily but for // coverage). + g_expected_handled = true; fl_key_responder_handle_event( responder, key_event_new(102, kPress, GDK_KEY_q, kKeyCodeKeyA, 0, kIsNotModifier), - responder_callback, &user_data); + verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 0u); @@ -472,7 +473,7 @@ TEST(FlKeyEmbedderResponderTest, IgnoreDuplicateDownEvent) { fl_key_responder_handle_event( responder, key_event_new(103, kRelease, GDK_KEY_q, kKeyCodeKeyA, 0, kIsNotModifier), - responder_callback, &user_data); + verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); @@ -491,17 +492,19 @@ TEST(FlKeyEmbedderResponderTest, IgnoreAbruptUpEvent) { int user_data = 123; // Arbitrary user data // Release KeyA before it was even pressed. + g_expected_handled = true; fl_key_responder_handle_event( responder, key_event_new(103, kRelease, GDK_KEY_q, kKeyCodeKeyA, 0, kIsNotModifier), - responder_callback, &user_data); + verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 0u); g_clear_object(&g_call_records); } -// Press Shift, key A, then release Shift, key A. +// Test if missed modifier keys can be detected and synthesized with state +// information. TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingState) { EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); @@ -520,7 +523,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingState) { responder, key_event_new(101, kPress, GDK_KEY_a, kKeyCodeKeyA, state, kIsNotModifier), - responder_callback, &user_data); + verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 2u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); @@ -550,7 +553,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingState) { responder, key_event_new(102, kRelease, GDK_KEY_A, kKeyCodeKeyA, state, kIsNotModifier), - responder_callback, &user_data); + verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 2u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); @@ -574,3 +577,97 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingState) { g_clear_object(&g_call_records); } + +// Test if missed lock keys can be detected and synthesized with state +// information. +TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { + EXPECT_EQ(g_call_records, nullptr); + g_call_records = g_ptr_array_new_with_free_func(g_object_unref); + g_autoptr(FlEngine) engine = make_mock_engine_with_records(); + g_autoptr(FlKeyResponder) responder = + FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); + int user_data = 123; // Arbitrary user data + + FlKeyEmbedderCallRecord* record; + + // The NumLock is desynchronized by being enabled. + guint state = GDK_MOD2_MASK; + + // Send a normal event + fl_key_responder_handle_event( + responder, + key_event_new(101, kPress, GDK_KEY_a, kKeyCodeKeyA, state, + kIsNotModifier), + verify_response_handled, &user_data); + + EXPECT_EQ(g_call_records->len, 2u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->timestamp, 101000); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); + EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, true); + + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 1)); + EXPECT_EQ(record->event->timestamp, 101000); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->physical, kPhysicalKeyA); + EXPECT_EQ(record->event->logical, kLogicalKeyA); + EXPECT_STREQ(record->event->character, "a"); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + // The NumLock is desynchronized by being disabled. + state = 0; + + // Release key A + fl_key_responder_handle_event( + responder, + key_event_new(102, kRelease, GDK_KEY_A, kKeyCodeKeyA, state, + kIsNotModifier), + verify_response_handled, &user_data); + + EXPECT_EQ(g_call_records->len, 3u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->timestamp, 102000); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); + EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); + EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, true); + + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 1)); + EXPECT_EQ(record->event->timestamp, 102000); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); + EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, true); + + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 2)); + EXPECT_EQ(record->event->timestamp, 102000); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); + EXPECT_EQ(record->event->physical, kPhysicalKeyA); + EXPECT_EQ(record->event->logical, kLogicalKeyA); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + // Press NumLock. Since the previous event should have synthesized NumLock to be + // pressed, this should result in no events. + g_expected_handled = true; + fl_key_responder_handle_event( + responder, + key_event_new(102, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock, state, + kIsNotModifier), + verify_response_handled, &user_data); + + EXPECT_EQ(g_call_records->len, 0u); + + g_clear_object(&g_call_records); +} diff --git a/shell/platform/linux/fl_message_codec_test.cc b/shell/platform/linux/fl_message_codec_test.cc index 69390803354ac..c2555ae9182ef 100644 --- a/shell/platform/linux/fl_message_codec_test.cc +++ b/shell/platform/linux/fl_message_codec_test.cc @@ -67,16 +67,12 @@ static FlTestCodec* fl_test_codec_new() { } TEST(FlMessageCodecTest, EncodeMessage) { - printf("T0\n"); g_autoptr(FlTestCodec) codec = fl_test_codec_new(); - printf("T1\n"); g_autoptr(FlValue) value = fl_value_new_int(1); g_autoptr(GError) error = nullptr; - printf("T2\n"); g_autoptr(GBytes) message = fl_message_codec_encode_message(FL_MESSAGE_CODEC(codec), value, &error); - printf("T3\n"); EXPECT_NE(message, nullptr); EXPECT_EQ(error, nullptr); EXPECT_EQ(g_bytes_get_size(message), static_cast(1)); diff --git a/shell/platform/linux/key_mapping.cc b/shell/platform/linux/key_mapping.cc index 1a1e240f98126..828ad3b92eb81 100644 --- a/shell/platform/linux/key_mapping.cc +++ b/shell/platform/linux/key_mapping.cc @@ -426,7 +426,7 @@ void initialize_modifier_bit_to_checked_keys(GHashTable* table) { data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_SHIFT_MASK), data); data->length = 2; - data->first_logical_key = 0x30000010d; // shiftLeft + data->first_logical_key = 0x30000010d; // shiftLeft physical_keys = g_new(uint64_t, 2); data->physical_keys = physical_keys; *(physical_keys++) = 0x000700e1; // ShiftLeft @@ -435,7 +435,7 @@ void initialize_modifier_bit_to_checked_keys(GHashTable* table) { data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_CONTROL_MASK), data); data->length = 2; - data->first_logical_key = 0x300000105; // controlLeft + data->first_logical_key = 0x300000105; // controlLeft physical_keys = g_new(uint64_t, 2); data->physical_keys = physical_keys; *(physical_keys++) = 0x000700e0; // ControlLeft @@ -444,7 +444,7 @@ void initialize_modifier_bit_to_checked_keys(GHashTable* table) { data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_MOD1_MASK), data); data->length = 2; - data->first_logical_key = 0x300000102; // altLeft + data->first_logical_key = 0x300000102; // altLeft physical_keys = g_new(uint64_t, 2); data->physical_keys = physical_keys; *(physical_keys++) = 0x000700e2; // AltLeft @@ -453,7 +453,7 @@ void initialize_modifier_bit_to_checked_keys(GHashTable* table) { data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_MOD4_MASK), data); data->length = 2; - data->first_logical_key = 0x300000109; // metaLeft + data->first_logical_key = 0x300000109; // metaLeft physical_keys = g_new(uint64_t, 2); data->physical_keys = physical_keys; *(physical_keys++) = 0x000700e3; // MetaLeft @@ -467,7 +467,7 @@ void initialize_lock_mode_bit_to_checked_keys(GHashTable* table) { data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_LOCK_MASK), data); data->length = 1; - data->first_logical_key = 0x000000104; // capsLock + data->first_logical_key = 0x000000104; // capsLock physical_keys = g_new(uint64_t, 1); data->physical_keys = physical_keys; *(physical_keys++) = 0x00070039; // CapsLock @@ -475,7 +475,7 @@ void initialize_lock_mode_bit_to_checked_keys(GHashTable* table) { data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_MOD2_MASK), data); data->length = 1; - data->first_logical_key = 0x00000010a; // numLock + data->first_logical_key = 0x00000010a; // numLock physical_keys = g_new(uint64_t, 1); data->physical_keys = physical_keys; *(physical_keys++) = 0x00070053; // NumLock From 3830b84339b5355814d1ea1aef16bce88a1db23b Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Thu, 15 Apr 2021 16:21:03 -0700 Subject: [PATCH 035/126] State sync --- .../linux/fl_key_embedder_responder.cc | 2 +- .../linux/fl_key_embedder_responder_test.cc | 110 +++++++++++++++++- 2 files changed, 105 insertions(+), 7 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index b9175415a6f90..0a03eecf3fbbb 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -509,7 +509,7 @@ static void synchronize_lock_mode_states_loop_body(gpointer key, // If the event is for the target key, then the last stage transition should // be handled by the main event logic instead of synthesization. - const int destination_stage = stage_by_event; + const int destination_stage = cycle_stage_to_after(stage_by_event, stage_by_record); printf("SynLock: stage by recrd %d\n", stage_by_record); printf("SynLock: stage by event %d\n", stage_by_event); diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index 2f2ff00b88534..6d87a0522dde8 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -579,7 +579,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingState) { } // Test if missed lock keys can be detected and synthesized with state -// information. +// information upon events that are not for this modifier key. TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); @@ -658,16 +658,114 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { invoke_record_callback_and_verify(record, TRUE, &user_data); g_ptr_array_clear(g_call_records); - // Press NumLock. Since the previous event should have synthesized NumLock to be - // pressed, this should result in no events. + // Release NumLock. Since the previous event should have synthesized NumLock to be + // pressed, this should result in a normal event. g_expected_handled = true; fl_key_responder_handle_event( responder, - key_event_new(102, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock, state, - kIsNotModifier), + key_event_new(103, kRelease, GDK_KEY_Num_Lock, kKeyCodeNumLock, state, + kIsModifier), verify_response_handled, &user_data); - EXPECT_EQ(g_call_records->len, 0u); + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->timestamp, 103000); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); + EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); + EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, false); + + g_clear_object(&g_call_records); +} + +// Test if missed lock keys can be detected and synthesized with state +// information upon events that are for this modifier key. +TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) { + EXPECT_EQ(g_call_records, nullptr); + g_call_records = g_ptr_array_new_with_free_func(g_object_unref); + g_autoptr(FlEngine) engine = make_mock_engine_with_records(); + g_autoptr(FlKeyResponder) responder = + FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); + int user_data = 123; // Arbitrary user data + + FlKeyEmbedderCallRecord* record; + + // The NumLock is desynchronized by being enabled. + guint state = GDK_MOD2_MASK; + + // NumLock down + fl_key_responder_handle_event( + responder, + key_event_new(101, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock, state, + kIsModifier), + verify_response_handled, &user_data); + + EXPECT_EQ(g_call_records->len, 3u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->timestamp, 101000); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); + EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, true); + + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 1)); + EXPECT_EQ(record->event->timestamp, 101000); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); + EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); + EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, true); + + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 2)); + EXPECT_EQ(record->event->timestamp, 101000); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); + EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + // The NumLock is desynchronized by staying enabled. + state = GDK_MOD2_MASK; + + // NumLock up + fl_key_responder_handle_event( + responder, + key_event_new(102, kRelease, GDK_KEY_Num_Lock, kKeyCodeNumLock, state, + kIsModifier), + verify_response_handled, &user_data); + + EXPECT_EQ(g_call_records->len, 3u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->timestamp, 102000); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); + EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); + EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, true); + + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 1)); + EXPECT_EQ(record->event->timestamp, 102000); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); + EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, true); + + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 2)); + EXPECT_EQ(record->event->timestamp, 102000); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); + EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); + EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); g_clear_object(&g_call_records); } From cf9726023cc86da665c2fd602e83fc0176f193e4 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Thu, 15 Apr 2021 16:45:46 -0700 Subject: [PATCH 036/126] Complete channel tests --- .../linux/fl_key_channel_responder_test.cc | 213 +++++++++--------- .../linux/fl_key_embedder_responder.cc | 23 +- .../linux/fl_key_embedder_responder_test.cc | 4 +- 3 files changed, 123 insertions(+), 117 deletions(-) diff --git a/shell/platform/linux/fl_key_channel_responder_test.cc b/shell/platform/linux/fl_key_channel_responder_test.cc index 00d46230b4d15..d99e27bdc7a6e 100644 --- a/shell/platform/linux/fl_key_channel_responder_test.cc +++ b/shell/platform/linux/fl_key_channel_responder_test.cc @@ -57,10 +57,8 @@ TEST(FlKeyChannelResponderTest, SendKeyEvent) { 0, // is a modifier }; - // printf("Test 1 %s\n", expected_value);fflush(stdout); fl_key_responder_handle_event(responder, &key_event, responder_callback, loop); - // printf("Test 2 %s\n", expected_value);fflush(stdout); expected_value = "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, keyCode: 65, " "modifiers: 0, unicodeScalarValues: 65}"; @@ -94,103 +92,114 @@ TEST(FlKeyChannelResponderTest, SendKeyEvent) { g_main_loop_run(loop); } -// void test_lock_event(guint key_code, -// const char* down_expected, -// const char* up_expected) { -// g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); - -// FlBinaryMessenger* messenger = fl_binary_messenger_new(engine); -// g_autoptr(FlKeyChannelResponder) responder = fl_key_channel_responder_new( -// messenger, text_input_plugin, echo_response_cb, "test/echo"); - -// GdkEventKey key_event = GdkEventKey{ -// GDK_KEY_PRESS, // event type -// nullptr, // window (not needed) -// FALSE, // event was sent explicitly -// 12345, // time -// 0x10, // modifier state -// key_code, // key code -// 1, // length of string representation -// nullptr, // string representation -// 0x04, // scan code -// 0, // keyboard group -// 0, // is a modifier -// }; - -// expected_value = down_expected; -// expected_handled = FALSE; -// bool handled = fl_key_responder_handle_event(responder, &key_event, loop); -// EXPECT_TRUE(handled); - -// // Blocks here until echo_response_cb is called. -// g_main_loop_run(loop); - -// key_event.type = GDK_KEY_RELEASE; -// key_event.time++; - -// expected_value = up_expected; -// expected_handled = FALSE; -// fl_key_responder_handle_event(responder, &key_event, loop); - -// // Blocks here until echo_response_cb is called. -// g_main_loop_run(loop); -// } - -// // Test sending a "NumLock" keypress. -// TEST(FlKeyChannelResponderTest, SendNumLockKeyEvent) { -// test_lock_event(GDK_KEY_Num_Lock, -// "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, -// " "keyCode: 65407, modifiers: 16}", -// "{type: keyup, keymap: linux, scanCode: 4, toolkit: gtk, " -// "keyCode: 65407, modifiers: 0}"); -// } - -// // Test sending a "CapsLock" keypress. -// TEST(FlKeyChannelResponderTest, SendCapsLockKeyEvent) { -// test_lock_event(GDK_KEY_Caps_Lock, -// "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, -// " "keyCode: 65509, modifiers: 2}", -// "{type: keyup, keymap: linux, scanCode: 4, toolkit: gtk, " -// "keyCode: 65509, modifiers: 0}"); -// } - -// // Test sending a "ShiftLock" keypress. -// TEST(FlKeyChannelResponderTest, SendShiftLockKeyEvent) { -// test_lock_event(GDK_KEY_Shift_Lock, -// "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, -// " "keyCode: 65510, modifiers: 2}", -// "{type: keyup, keymap: linux, scanCode: 4, toolkit: gtk, " -// "keyCode: 65510, modifiers: 0}"); -// } - -// TEST(FlKeyChannelResponderTest, TestKeyEventHandledByFramework) { -// g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); - -// FlBinaryMessenger* messenger = fl_binary_messenger_new(engine); -// g_autoptr(FlKeyChannelResponder) responder = fl_key_channel_responder_new( -// messenger, text_input_plugin, echo_response_cb, -// "test/key-event-handled"); - -// GdkEventKey key_event = GdkEventKey{ -// GDK_KEY_PRESS, // event type -// nullptr, // window (not needed) -// FALSE, // event was sent explicitly -// 12345, // time -// 0x10, // modifier state -// GDK_KEY_A, // key code -// 1, // length of string representation -// nullptr, // string representation -// 0x04, // scan code -// 0, // keyboard group -// 0, // is a modifier -// }; - -// expected_value = "{handled: true}"; -// expected_handled = TRUE; -// bool handled = fl_key_responder_handle_event(responder, &key_event, loop); -// // Should always be true, because the event was delayed. -// EXPECT_TRUE(handled); - -// // Blocks here until echo_response_cb is called. -// g_main_loop_run(loop); -// } +void test_lock_event(guint key_code, + const char* down_expected, + const char* up_expected) { + g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); + + g_autoptr(FlEngine) engine = make_mock_engine(); + g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine); + FlKeyChannelResponderMock mock{ + .value_converter = echo_response_cb, + .channel_name = "test/echo", + }; + g_autoptr(FlKeyResponder) responder = + FL_KEY_RESPONDER(fl_key_channel_responder_new(messenger, &mock)); + + GdkEventKey key_event = GdkEventKey{ + GDK_KEY_PRESS, // event type + nullptr, // window (not needed) + FALSE, // event was sent explicitly + 12345, // time + 0x10, // modifier state + key_code, // key code + 1, // length of string representation + nullptr, // string representation + 0x04, // scan code + 0, // keyboard group + 0, // is a modifier + }; + + fl_key_responder_handle_event(responder, &key_event, responder_callback, + loop); + expected_value = down_expected; + expected_handled = FALSE; + + // Blocks here until echo_response_cb is called. + g_main_loop_run(loop); + + key_event.type = GDK_KEY_RELEASE; + key_event.time++; + + expected_value = up_expected; + expected_handled = FALSE; + fl_key_responder_handle_event(responder, &key_event, responder_callback, + loop); + + // Blocks here until echo_response_cb is called. + g_main_loop_run(loop); +} + +// Test sending a "NumLock" keypress. +TEST(FlKeyChannelResponderTest, SendNumLockKeyEvent) { + test_lock_event(GDK_KEY_Num_Lock, + "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, " + "keyCode: 65407, modifiers: 16}", + "{type: keyup, keymap: linux, scanCode: 4, toolkit: gtk, " + "keyCode: 65407, modifiers: 0}"); +} + +// Test sending a "CapsLock" keypress. +TEST(FlKeyChannelResponderTest, SendCapsLockKeyEvent) { + test_lock_event(GDK_KEY_Caps_Lock, + "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, " + "keyCode: 65509, modifiers: 2}", + "{type: keyup, keymap: linux, scanCode: 4, toolkit: gtk, " + "keyCode: 65509, modifiers: 0}"); +} + +// Test sending a "ShiftLock" keypress. +TEST(FlKeyChannelResponderTest, SendShiftLockKeyEvent) { + test_lock_event(GDK_KEY_Shift_Lock, + "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, " + "keyCode: 65510, modifiers: 2}", + "{type: keyup, keymap: linux, scanCode: 4, toolkit: gtk, " + "keyCode: 65510, modifiers: 0}"); +} + +TEST(FlKeyChannelResponderTest, TestKeyEventHandledByFramework) { + g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); + + g_autoptr(FlEngine) engine = make_mock_engine(); + g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine); + FlKeyChannelResponderMock mock{ + .value_converter = echo_response_cb, + .channel_name = "test/echo", + }; + g_autoptr(FlKeyResponder) responder = + FL_KEY_RESPONDER(fl_key_channel_responder_new(messenger, &mock)); + + GdkEventKey key_event = GdkEventKey{ + GDK_KEY_PRESS, // event type + nullptr, // window (not needed) + FALSE, // event was sent explicitly + 12345, // time + 0x10, // modifier state + GDK_KEY_A, // key code + 1, // length of string representation + nullptr, // string representation + 0x04, // scan code + 0, // keyboard group + 0, // is a modifier + }; + + fl_key_responder_handle_event(responder, &key_event, responder_callback, + loop); + expected_handled = TRUE; + expected_value = + "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, " + "keyCode: 65, modifiers: 0, unicodeScalarValues: 65}"; + + // Blocks here until echo_response_cb is called. + g_main_loop_run(loop); +} diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index 0a03eecf3fbbb..c9a2bbcd2c82b 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -427,15 +427,17 @@ static int find_closest_next_stage(int start, int option1, int option2) { } static void update_pressing_state(FlKeyEmbedderResponder* self, - uint64_t physical_key, - uint64_t logical_key) { + uint64_t physical_key, + uint64_t logical_key) { if (logical_key != 0) { - g_return_if_fail(lookup_hash_table(self->pressing_records, physical_key) == 0); + g_return_if_fail(lookup_hash_table(self->pressing_records, physical_key) == + 0); g_hash_table_insert(self->pressing_records, uint64_to_gpointer(physical_key), uint64_to_gpointer(logical_key)); } else { - g_return_if_fail(lookup_hash_table(self->pressing_records, physical_key) != 0); + g_return_if_fail(lookup_hash_table(self->pressing_records, physical_key) != + 0); g_hash_table_remove(self->pressing_records, uint64_to_gpointer(physical_key)); } @@ -509,7 +511,8 @@ static void synchronize_lock_mode_states_loop_body(gpointer key, // If the event is for the target key, then the last stage transition should // be handled by the main event logic instead of synthesization. - const int destination_stage = cycle_stage_to_after(stage_by_event, stage_by_record); + const int destination_stage = + cycle_stage_to_after(stage_by_event, stage_by_record); printf("SynLock: stage by recrd %d\n", stage_by_record); printf("SynLock: stage by event %d\n", stage_by_event); @@ -531,10 +534,7 @@ static void synchronize_lock_mode_states_loop_body(gpointer key, standard_current_stage == 0 || standard_current_stage == 2; FlutterKeyEventType type = is_down_event ? kFlutterKeyEventTypeDown : kFlutterKeyEventTypeUp; - update_pressing_state( - self, - physical_key, - is_down_event ? logical_key : 0); + update_pressing_state(self, physical_key, is_down_event ? logical_key : 0); possibly_update_lock_mode_bit(self, physical_key, is_down_event); synthesize_simple_event(self, type, physical_key, logical_key, context->timestamp); @@ -588,10 +588,7 @@ static void fl_key_embedder_responder_handle_event( synchronize_lock_mode_states_loop_body, &sync_pressed_state_context); - update_pressing_state( - self, - physical_key, - is_down_event ? logical_key : 0); + update_pressing_state(self, physical_key, is_down_event ? logical_key : 0); possibly_update_lock_mode_bit(self, physical_key, is_down_event); // printf("Before foreach\n"); diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index 6d87a0522dde8..06a3bbb83ae33 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -658,8 +658,8 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { invoke_record_callback_and_verify(record, TRUE, &user_data); g_ptr_array_clear(g_call_records); - // Release NumLock. Since the previous event should have synthesized NumLock to be - // pressed, this should result in a normal event. + // Release NumLock. Since the previous event should have synthesized NumLock + // to be pressed, this should result in a normal event. g_expected_handled = true; fl_key_responder_handle_event( responder, From 72022c57ad99eb0d39b3637992e3535d5c06b48b Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Thu, 15 Apr 2021 17:20:40 -0700 Subject: [PATCH 037/126] Remove some prints --- .../linux/fl_key_embedder_responder.cc | 24 +++++++++---------- .../linux/fl_keyboard_manager_test.cc | 4 ---- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index c9a2bbcd2c82b..e23d72218075a 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -499,7 +499,7 @@ static void synchronize_lock_mode_states_loop_body(gpointer key, find_stage_by_record(pressed_by_record, enabled_by_record); const bool event_is_target_key = physical_key == context->event_physical_key; - printf("SynLock: evtIsTarget %d ph %lx evPh %lx\n", event_is_target_key, + // printf("SynLock: evtIsTarget %d ph %lx evPh %lx\n", event_is_target_key, physical_key, context->event_physical_key); const bool enabled_by_state = (context->state & modifier_bit) != 0; const int stage_by_event = @@ -514,9 +514,9 @@ static void synchronize_lock_mode_states_loop_body(gpointer key, const int destination_stage = cycle_stage_to_after(stage_by_event, stage_by_record); - printf("SynLock: stage by recrd %d\n", stage_by_record); - printf("SynLock: stage by event %d\n", stage_by_event); - printf("SynLock: stage by dest %d\n", destination_stage); + // printf("SynLock: stage by recrd %d\n", stage_by_record); + // printf("SynLock: stage by event %d\n", stage_by_event); + // printf("SynLock: stage by dest %d\n", destination_stage); g_return_if_fail(stage_by_record <= destination_stage); if (stage_by_record == destination_stage) { return; @@ -526,7 +526,7 @@ static void synchronize_lock_mode_states_loop_body(gpointer key, if (current_stage == 9) { return; } - printf("SynLock: syn for stage %d\n", current_stage); + // printf("SynLock: syn for stage %d\n", current_stage); const int standard_current_stage = current_stage >= 4 ? current_stage - 4 : current_stage; @@ -551,13 +551,13 @@ static void fl_key_embedder_responder_handle_event( gpointer user_data) { FlKeyEmbedderResponder* self = FL_KEY_EMBEDDER_RESPONDER(responder); _text_idx += 1; - printf( - "#%7s keyval 0x%x keycode 0x%x state 0x%x ismod %d snd %d grp %d " - "time %d [%d] curLock %x\n", - event->type == GDK_KEY_PRESS ? "PRESS" : "RELEASE", event->keyval, - event->hardware_keycode, event->state, event->is_modifier, - event->send_event, event->group, event->time, _text_idx, - self->lock_mode_records); + // printf( + // "#%7s keyval 0x%x keycode 0x%x state 0x%x ismod %d snd %d grp %d " + // "time %d [%d] curLock %x\n", + // event->type == GDK_KEY_PRESS ? "PRESS" : "RELEASE", event->keyval, + // event->hardware_keycode, event->state, event->is_modifier, + // event->send_event, event->group, event->time, _text_idx, + // self->lock_mode_records); fflush(stdout); g_return_if_fail(event != nullptr); diff --git a/shell/platform/linux/fl_keyboard_manager_test.cc b/shell/platform/linux/fl_keyboard_manager_test.cc index cf65993c1a513..7e5a3268ec965 100644 --- a/shell/platform/linux/fl_keyboard_manager_test.cc +++ b/shell/platform/linux/fl_keyboard_manager_test.cc @@ -121,13 +121,10 @@ static void fl_key_mock_responder_handle_event( GdkEventKey* event, FlKeyResponderAsyncCallback callback, gpointer user_data) { - printf("MockHandle 1\n"); FlKeyMockResponder* self = FL_KEY_MOCK_RESPONDER(responder); g_ptr_array_add(self->call_records, FL_KEYBOARD_CALL_RECORD(fl_keyboard_call_record_new( self, event, callback, user_data))); - printf("MockHandle [0] %lx\n", (uint64_t)FL_KEYBOARD_CALL_RECORD( - g_ptr_array_index(self->call_records, 0))); self->callback_handler(callback, user_data); } @@ -382,7 +379,6 @@ TEST(FlKeyboardManagerTest, WithTwoAsyncDelegates) { record = FL_KEYBOARD_CALL_RECORD(g_ptr_array_index(call_records, 0)); record->callback(true, record->user_data); - printf("T1 mid\n"); record = FL_KEYBOARD_CALL_RECORD(g_ptr_array_index(call_records, 1)); record->callback(false, record->user_data); EXPECT_EQ(redispatched_events()->len, 0u); From 22616c8a55d0f1e8d488210a306c86e71b1e4a10 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Thu, 15 Apr 2021 17:21:36 -0700 Subject: [PATCH 038/126] Add one print back --- shell/platform/linux/fl_key_embedder_responder.cc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index e23d72218075a..823c8c71dbbe9 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -551,13 +551,13 @@ static void fl_key_embedder_responder_handle_event( gpointer user_data) { FlKeyEmbedderResponder* self = FL_KEY_EMBEDDER_RESPONDER(responder); _text_idx += 1; - // printf( - // "#%7s keyval 0x%x keycode 0x%x state 0x%x ismod %d snd %d grp %d " - // "time %d [%d] curLock %x\n", - // event->type == GDK_KEY_PRESS ? "PRESS" : "RELEASE", event->keyval, - // event->hardware_keycode, event->state, event->is_modifier, - // event->send_event, event->group, event->time, _text_idx, - // self->lock_mode_records); + printf( + "#%7s keyval 0x%x keycode 0x%x state 0x%x ismod %d snd %d grp %d " + "time %d [%d] curLock %x\n", + event->type == GDK_KEY_PRESS ? "PRESS" : "RELEASE", event->keyval, + event->hardware_keycode, event->state, event->is_modifier, + event->send_event, event->group, event->time, _text_idx, + self->lock_mode_records); fflush(stdout); g_return_if_fail(event != nullptr); From 559724a04eb6d81f79218ab7e9a7bd5140ab98ab Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Fri, 16 Apr 2021 18:29:42 -0700 Subject: [PATCH 039/126] Fix capslock --- .../linux/fl_key_embedder_responder.cc | 163 +++++----- .../linux/fl_key_embedder_responder_private.h | 1 + .../linux/fl_key_embedder_responder_test.cc | 293 ++++++++++++++++-- shell/platform/linux/fl_view.cc | 5 +- shell/platform/linux/key_mapping.cc | 6 + 5 files changed, 364 insertions(+), 104 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index 823c8c71dbbe9..74bc7fa15f0cb 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -384,30 +384,6 @@ static void synchronize_pressed_states_loop_body(gpointer key, } } -// Find the stage # before the event (of the 4 stages as documented in -// `synchronize_lock_mode_states_loop_body`) by the current record. -static int find_stage_by_record(bool is_down, bool is_enabled) { - constexpr int stage_by_record_index[] = { - 0, // isDown: 0, isEnabled: 0 - 2, // 0 1 - 3, // 1 0 - 1 // 1 1 - }; - return stage_by_record_index[(is_down << 1) + is_enabled]; -} - -// Find the stage # before the event (of the 4 stages as documented in -// `synchronize_lock_mode_states_loop_body`) by the event. -static int find_stage_by_event(bool is_down, bool is_enabled) { - constexpr int stage_by_record_index[] = { - 3, // isDown: 0, isEnabled: 0 - 1, // 0 1 - 0, // 1 0 - 2 // 1 1 - }; - return stage_by_record_index[(is_down << 1) + is_enabled]; -} - // Find the first stage # greater than `start` that is equivalent to `target` in // a cycle of 4. // @@ -419,11 +395,43 @@ static int cycle_stage_to_after(int target, int start) { return target >= start ? target : target + kNumStages; } -static int find_closest_next_stage(int start, int option1, int option2) { - const int adjusted_option1 = cycle_stage_to_after(option1, start); - const int adjusted_option2 = cycle_stage_to_after(option2, start); - return adjusted_option1 < adjusted_option2 ? adjusted_option1 - : adjusted_option2; +// Find the stage # before the event (of the 4 stages as documented in +// `synchronize_lock_mode_states_loop_body`) by the current record. +static int find_stage_by_record(bool is_down, bool is_enabled) { + constexpr int stage_by_record_index[] = { + 0, // is_down: 0, is_enabled: 0 + 2, // 0 1 + 3, // 1 0 + 1 // 1 1 + }; + return stage_by_record_index[(is_down << 1) + is_enabled]; +} + +static int find_stage_by_self_event(int stage_by_record, + bool is_down_event, + bool is_state_on, + bool is_caps_lock) { + g_return_val_if_fail(stage_by_record >= 0 && stage_by_record < 4, + stage_by_record); + if (!is_state_on) { + return is_caps_lock ? 2 : 0; + } + if (is_down_event) { + return is_caps_lock ? 0 : 2; + } + return stage_by_record; +} + +static int find_stage_by_others_event(int stage_by_record, bool is_state_on) { + g_return_val_if_fail(stage_by_record >= 0 && stage_by_record < 4, + stage_by_record); + if (!is_state_on) { + return 0; + } + if (stage_by_record == 0) { + return 1; + } + return stage_by_record; } static void update_pressing_state(FlKeyEmbedderResponder* self, @@ -449,8 +457,9 @@ static void possibly_update_lock_mode_bit(FlKeyEmbedderResponder* self, if (!is_down) { return; } - guint mode_bit = GPOINTER_TO_UINT(g_hash_table_lookup( + const guint mode_bit = GPOINTER_TO_UINT(g_hash_table_lookup( self->physical_key_to_lock_mode_bit, uint64_to_gpointer(physical_key))); + printf("Mode bit for PhK %lx is %x\n", physical_key, mode_bit); if (mode_bit != 0) { self->lock_mode_records ^= mode_bit; } @@ -467,25 +476,27 @@ static void synchronize_lock_mode_states_loop_body(gpointer key, guint modifier_bit = GPOINTER_TO_INT(key); FlKeyEmbedderResponder* self = context->self; - const bool is_down_event = context->is_down; - const uint64_t logical_key = checked_key->first_logical_key; const uint64_t physical_key = checked_key->physical_keys[0]; - // printf("Syn: 1 state %x bit %x curPhy %lx\n", context->state, modifier_bit, - // context->event_physical_key); - - // A lock mode key can be at any of a 4-stage cycle: + printf("Syn: 1 state %x bit %x curPhy %lx\n", context->state, modifier_bit, + context->event_physical_key); + + // A lock mode key can be at any of a 4-stage cycle. The following table lists + // the definition of each stage (TruePressed and TrueEnabled), the event of + // the lock key between every 2 stages (SelfType and SelfState), and the event + // of other keys at each stage (OthersState). Notice that SelfState uses different + // rule for CapsLock. // - // Up,Disabled -> Down,Enabled -> Up,Enabled -> Down,Disabled -> - // [0] [1] [2] [3] - // EventType: Down Up Down Up - // State: 0 1 1 0 + // # [0] [1] [2] [3] + // TruePressed: Released Pressed Released Pressed + // TrueEnabled: Disabled Enabled Enabled Disabled + // SelfType: Down Up Down Up + // SelfState(Caps): 1 1 0 1 + // SelfState(Etc): 0 1 1 1 + // OthersState: 0 1 1 1 // - // If the incoming event is the target key, then we know exactly which stage - // the true state is at. - // - // Otherwise, since we only know "state", we can tell if the true stage is - // either 0/3 or 1/2. Choose the shorter one. + // Except for stage 0, we can't derive the exact stage just from event + // information. Choose the stage that requires the minimal synthesization. const uint64_t pressed_logical_key = lookup_hash_table(self->pressing_records, physical_key); @@ -493,30 +504,25 @@ static void synchronize_lock_mode_states_loop_body(gpointer key, // cases. g_return_if_fail(pressed_logical_key == 0 || pressed_logical_key == logical_key); - const bool pressed_by_record = pressed_logical_key != 0; - const bool enabled_by_record = (self->lock_mode_records & modifier_bit) != 0; - const int stage_by_record = - find_stage_by_record(pressed_by_record, enabled_by_record); - - const bool event_is_target_key = physical_key == context->event_physical_key; - // printf("SynLock: evtIsTarget %d ph %lx evPh %lx\n", event_is_target_key, - physical_key, context->event_physical_key); + const int stage_by_record = find_stage_by_record( + pressed_logical_key != 0, (self->lock_mode_records & modifier_bit) != 0); + const bool enabled_by_state = (context->state & modifier_bit) != 0; + const bool is_self_event = physical_key == context->event_physical_key; const int stage_by_event = - event_is_target_key - ? find_stage_by_event(is_down_event, enabled_by_state) - : find_closest_next_stage( - stage_by_record, find_stage_by_record(true, enabled_by_state), - find_stage_by_record(false, enabled_by_state)); + is_self_event + ? find_stage_by_self_event(stage_by_record, context->is_down, + enabled_by_state, checked_key->is_caps_lock) + : find_stage_by_others_event(stage_by_record, enabled_by_state); // If the event is for the target key, then the last stage transition should // be handled by the main event logic instead of synthesization. const int destination_stage = cycle_stage_to_after(stage_by_event, stage_by_record); - // printf("SynLock: stage by recrd %d\n", stage_by_record); - // printf("SynLock: stage by event %d\n", stage_by_event); - // printf("SynLock: stage by dest %d\n", destination_stage); + printf("SynLock: stage by recrd %d\n", stage_by_record); + printf("SynLock: stage by event %d\n", stage_by_event); + printf("SynLock: stage by dest %d\n", destination_stage); g_return_if_fail(stage_by_record <= destination_stage); if (stage_by_record == destination_stage) { return; @@ -526,7 +532,7 @@ static void synchronize_lock_mode_states_loop_body(gpointer key, if (current_stage == 9) { return; } - // printf("SynLock: syn for stage %d\n", current_stage); + printf("SynLock: syn for stage %d\n", current_stage); const int standard_current_stage = current_stage >= 4 ? current_stage - 4 : current_stage; @@ -551,31 +557,25 @@ static void fl_key_embedder_responder_handle_event( gpointer user_data) { FlKeyEmbedderResponder* self = FL_KEY_EMBEDDER_RESPONDER(responder); _text_idx += 1; - printf( - "#%7s keyval 0x%x keycode 0x%x state 0x%x ismod %d snd %d grp %d " - "time %d [%d] curLock %x\n", - event->type == GDK_KEY_PRESS ? "PRESS" : "RELEASE", event->keyval, - event->hardware_keycode, event->state, event->is_modifier, - event->send_event, event->group, event->time, _text_idx, - self->lock_mode_records); - fflush(stdout); g_return_if_fail(event != nullptr); g_return_if_fail(callback != nullptr); - uint64_t physical_key = + const uint64_t physical_key = event_to_physical_key(event, self->xkb_to_physical_key); - uint64_t logical_key = + const uint64_t logical_key = event_to_logical_key(event, self->keyval_to_logical_key); - double timestamp = event_to_timestamp(event); - bool is_down_event = event->type == GDK_KEY_PRESS; - - uint64_t last_logical_record = - lookup_hash_table(self->pressing_records, physical_key); + const double timestamp = event_to_timestamp(event); + const bool is_down_event = event->type == GDK_KEY_PRESS; - // printf("last %lu next %lu down %d type %d\n", last_logical_record, - // next_logical_record, is_down_event, event->type); - // fflush(stdout); + printf( + "#%7s keyval 0x%x keycode 0x%x state 0x%x ismod %d snd %d grp %d " + "time %d [%d] curLock %x PhK %lx\n", + event->type == GDK_KEY_PRESS ? "PRESS" : "RELEASE", event->keyval, + event->hardware_keycode, event->state, event->is_modifier, + event->send_event, event->group, event->time, _text_idx, + self->lock_mode_records, physical_key); + fflush(stdout); SyncPressedStatesLoopContext sync_pressed_state_context; sync_pressed_state_context.self = self; @@ -588,6 +588,8 @@ static void fl_key_embedder_responder_handle_event( synchronize_lock_mode_states_loop_body, &sync_pressed_state_context); + const uint64_t last_logical_record = + lookup_hash_table(self->pressing_records, physical_key); update_pressing_state(self, physical_key, is_down_event ? logical_key : 0); possibly_update_lock_mode_bit(self, physical_key, is_down_event); @@ -635,4 +637,5 @@ static void fl_key_embedder_responder_handle_event( fl_engine_send_key_event(self->engine, &out_event, handle_response, response_data); + fflush(stdout); } diff --git a/shell/platform/linux/fl_key_embedder_responder_private.h b/shell/platform/linux/fl_key_embedder_responder_private.h index 808649268b996..82ba769f6f9a5 100644 --- a/shell/platform/linux/fl_key_embedder_responder_private.h +++ b/shell/platform/linux/fl_key_embedder_responder_private.h @@ -16,6 +16,7 @@ typedef struct { size_t length; uint64_t* physical_keys; uint64_t first_logical_key; + bool is_caps_lock; } FlKeyEmbedderCheckedKey; #endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_KEY_EMBEDDER_RESPONDER_PRIVATE_H_ diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index 06a3bbb83ae33..2e13828a763d5 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -23,6 +23,7 @@ constexpr guint16 kKeyCodeKeyA = 0x26u; constexpr guint16 kKeyCodeShiftRight = 0x3eu; constexpr guint16 kKeyCodeNumpad1 = 0x57u; constexpr guint16 kKeyCodeNumLock = 0x4du; +constexpr guint16 kKeyCodeCapsLock = 0x42u; constexpr uint64_t kPhysicalKeyA = 0x00070004; // constexpr uint64_t kPhysicalKeyQ = 0x00070014; @@ -32,6 +33,7 @@ constexpr uint64_t kPhysicalControlLeft = 0x000700e0; constexpr uint64_t kPhysicalShiftRight = 0x000700e5; constexpr uint64_t kPhysicalKeyNumpad1 = 0x00070059; constexpr uint64_t kPhysicalKeyNumLock = 0x00070053; +constexpr uint64_t kPhysicalKeyCapsLock = 0x00070039; constexpr uint64_t kLogicalKeyA = 0x00000061; constexpr uint64_t kLogicalKeyQ = 0x00000071; @@ -41,6 +43,7 @@ constexpr uint64_t kLogicalControlLeft = 0x00300000105; constexpr uint64_t kLogicalShiftRight = 0x0040000010d; constexpr uint64_t kLogicalKeyNumpad1 = 0x00200000031; constexpr uint64_t kLogicalKeyNumLock = 0x0000000010a; +constexpr uint64_t kLogicalKeyCapsLock = 0x00000000104; } // namespace static void g_ptr_array_clear(GPtrArray* array) { @@ -145,6 +148,7 @@ static void verify_response_handled(bool handled, gpointer user_data) { static void invoke_record_callback_and_verify(FlKeyEmbedderCallRecord* record, bool expected_handled, void* expected_user_data) { + g_return_if_fail(record->callback != nullptr); g_expected_handled = expected_handled; g_expected_user_data = expected_user_data; record->callback(expected_handled, record->user_data); @@ -347,12 +351,15 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { g_clear_object(&g_call_records); } -// Press Numpad 1, tap NumLock, then release Numpad 1. +// Press or release Numpad 1 between presses/releases of NumLock. // -// This is special because the keyval for the numpad key will change -// before and after the NumLock tap, which should not alter the -// resulting logical key. -TEST(FlKeyEmbedderResponderTest, TapNumLockDuringNumpadKeyTap) { +// This tests interaction between lock keys and non-lock keys in cases that do +// not have events missed. +// +// This also tests the result of Numpad keys across NumLock taps, which is +// test-worthy because the keyval for the numpad key will change before and +// after the NumLock tap, which should not alter the resulting logical key. +TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); g_autoptr(FlEngine) engine = make_mock_engine_with_records(); @@ -362,7 +369,7 @@ TEST(FlKeyEmbedderResponderTest, TapNumLockDuringNumpadKeyTap) { FlKeyEmbedderCallRecord* record; - // Press Numpad 1 + // Press Numpad 1 (stage 0) fl_key_responder_handle_event( responder, key_event_new(101, kPress, GDK_KEY_KP_End, kKeyCodeNumpad1, 0, @@ -380,7 +387,7 @@ TEST(FlKeyEmbedderResponderTest, TapNumLockDuringNumpadKeyTap) { invoke_record_callback_and_verify(record, TRUE, &user_data); g_ptr_array_clear(g_call_records); - // Press NumLock + // Press NumLock (stage 0 -> 1) fl_key_responder_handle_event( responder, key_event_new(102, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock, 0, @@ -398,7 +405,25 @@ TEST(FlKeyEmbedderResponderTest, TapNumLockDuringNumpadKeyTap) { invoke_record_callback_and_verify(record, TRUE, &user_data); g_ptr_array_clear(g_call_records); - // Release NumLock + // Release numpad 1 (stage 1) + fl_key_responder_handle_event( + responder, + key_event_new(104, kRelease, GDK_KEY_KP_1, kKeyCodeNumpad1, 0x10, + kIsNotModifier), + verify_response_handled, &user_data); + + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); + EXPECT_EQ(record->event->physical, kPhysicalKeyNumpad1); + EXPECT_EQ(record->event->logical, kLogicalKeyNumpad1); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + // Release NumLock (stage 1 -> 2) fl_key_responder_handle_event( responder, key_event_new(103, kRelease, GDK_KEY_Num_Lock, kKeyCodeNumLock, 0x10, @@ -416,7 +441,43 @@ TEST(FlKeyEmbedderResponderTest, TapNumLockDuringNumpadKeyTap) { invoke_record_callback_and_verify(record, TRUE, &user_data); g_ptr_array_clear(g_call_records); - // Release numpad 1 + // Press Numpad 1 (stage 2) + fl_key_responder_handle_event( + responder, + key_event_new(101, kPress, GDK_KEY_KP_End, kKeyCodeNumpad1, 0x10, + kIsNotModifier), + verify_response_handled, &user_data); + + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->physical, kPhysicalKeyNumpad1); + EXPECT_EQ(record->event->logical, kLogicalKeyNumpad1); + EXPECT_STREQ(record->event->character, nullptr); // TODO + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + // Press NumLock (stage 2 -> 3) + fl_key_responder_handle_event( + responder, + key_event_new(102, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock, 0x10, + kIsNotModifier), + verify_response_handled, &user_data); + + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); + EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + // Release numpad 1 (stage 3) fl_key_responder_handle_event( responder, key_event_new(104, kRelease, GDK_KEY_KP_1, kKeyCodeNumpad1, 0x10, @@ -434,6 +495,185 @@ TEST(FlKeyEmbedderResponderTest, TapNumLockDuringNumpadKeyTap) { invoke_record_callback_and_verify(record, TRUE, &user_data); g_ptr_array_clear(g_call_records); + // Release NumLock (stage 3 -> 0) + fl_key_responder_handle_event( + responder, + key_event_new(103, kRelease, GDK_KEY_Num_Lock, kKeyCodeNumLock, 0x10, + kIsModifier), + verify_response_handled, &user_data); + + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); + EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); + EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + g_clear_object(&g_call_records); +} + +// Press or release letter key between presses/releases of CapsLock. +// +// This tests interaction between lock keys and non-lock keys in cases that do +// not have events missed. +TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { + EXPECT_EQ(g_call_records, nullptr); + g_call_records = g_ptr_array_new_with_free_func(g_object_unref); + g_autoptr(FlEngine) engine = make_mock_engine_with_records(); + g_autoptr(FlKeyResponder) responder = + FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); + int user_data = 123; // Arbitrary user data + + FlKeyEmbedderCallRecord* record; + + // Press key A (stage 0) + fl_key_responder_handle_event( + responder, + key_event_new(101, kPress, GDK_KEY_a, kKeyCodeKeyA, 0, + kIsNotModifier), + verify_response_handled, &user_data); + + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->physical, kPhysicalKeyA); + EXPECT_EQ(record->event->logical, kLogicalKeyA); + EXPECT_STREQ(record->event->character, "a"); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + // Press CapsLock (stage 0 -> 1) + fl_key_responder_handle_event( + responder, + key_event_new(102, kPress, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x2, + kIsNotModifier), + verify_response_handled, &user_data); + + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->physical, kPhysicalKeyCapsLock); + EXPECT_EQ(record->event->logical, kLogicalKeyCapsLock); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + // Release key A (stage 1) + fl_key_responder_handle_event( + responder, + key_event_new(104, kRelease, GDK_KEY_A, kKeyCodeKeyA, 0x2, + kIsNotModifier), + verify_response_handled, &user_data); + + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); + EXPECT_EQ(record->event->physical, kPhysicalKeyA); + EXPECT_EQ(record->event->logical, kLogicalKeyA); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + // Release CapsLock (stage 1 -> 2) + fl_key_responder_handle_event( + responder, + key_event_new(103, kRelease, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x2, + kIsModifier), + verify_response_handled, &user_data); + + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); + EXPECT_EQ(record->event->physical, kPhysicalKeyCapsLock); + EXPECT_EQ(record->event->logical, kLogicalKeyCapsLock); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + // Press key A (stage 2) + fl_key_responder_handle_event( + responder, + key_event_new(101, kPress, GDK_KEY_A, kKeyCodeKeyA, 0x2, + kIsNotModifier), + verify_response_handled, &user_data); + + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->physical, kPhysicalKeyA); + EXPECT_EQ(record->event->logical, kLogicalKeyA); + EXPECT_STREQ(record->event->character, "A"); // TODO + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + // Press CapsLock (stage 2 -> 3) + fl_key_responder_handle_event( + responder, + key_event_new(102, kPress, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x00, + kIsNotModifier), + verify_response_handled, &user_data); + + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->physical, kPhysicalKeyCapsLock); + EXPECT_EQ(record->event->logical, kLogicalKeyCapsLock); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + // Release key A (stage 3) + fl_key_responder_handle_event( + responder, + key_event_new(104, kRelease, GDK_KEY_A, kKeyCodeKeyA, 0x2, + kIsNotModifier), + verify_response_handled, &user_data); + + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); + EXPECT_EQ(record->event->physical, kPhysicalKeyA); + EXPECT_EQ(record->event->logical, kLogicalKeyA); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + // Release CapsLock (stage 3 -> 0) + fl_key_responder_handle_event( + responder, + key_event_new(103, kRelease, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x2, + kIsModifier), + verify_response_handled, &user_data); + + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); + EXPECT_EQ(record->event->physical, kPhysicalKeyCapsLock); + EXPECT_EQ(record->event->logical, kLogicalKeyCapsLock); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + g_clear_object(&g_call_records); } @@ -630,7 +870,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { kIsNotModifier), verify_response_handled, &user_data); - EXPECT_EQ(g_call_records->len, 3u); + EXPECT_EQ(g_call_records->len, 4u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); EXPECT_EQ(record->event->timestamp, 102000); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); @@ -650,6 +890,14 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 2)); EXPECT_EQ(record->event->timestamp, 102000); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); + EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); + EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, true); + + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 3)); + EXPECT_EQ(record->event->timestamp, 102000); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); EXPECT_EQ(record->event->physical, kPhysicalKeyA); EXPECT_EQ(record->event->logical, kLogicalKeyA); EXPECT_STREQ(record->event->character, nullptr); @@ -659,7 +907,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { g_ptr_array_clear(g_call_records); // Release NumLock. Since the previous event should have synthesized NumLock - // to be pressed, this should result in a normal event. + // to be released, this should result in no events. g_expected_handled = true; fl_key_responder_handle_event( responder, @@ -667,14 +915,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { kIsModifier), verify_response_handled, &user_data); - EXPECT_EQ(g_call_records->len, 1u); - record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); - EXPECT_EQ(record->event->timestamp, 103000); - EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); - EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); - EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); - EXPECT_STREQ(record->event->character, nullptr); - EXPECT_EQ(record->event->synthesized, false); + EXPECT_EQ(g_call_records->len, 0u); g_clear_object(&g_call_records); } @@ -729,17 +970,17 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) { invoke_record_callback_and_verify(record, TRUE, &user_data); g_ptr_array_clear(g_call_records); - // The NumLock is desynchronized by staying enabled. + // The NumLock is desynchronized by being enabled in a press event. state = GDK_MOD2_MASK; // NumLock up fl_key_responder_handle_event( responder, - key_event_new(102, kRelease, GDK_KEY_Num_Lock, kKeyCodeNumLock, state, + key_event_new(102, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock, state, kIsModifier), verify_response_handled, &user_data); - EXPECT_EQ(g_call_records->len, 3u); + EXPECT_EQ(g_call_records->len, 4u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); EXPECT_EQ(record->event->timestamp, 102000); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); @@ -762,6 +1003,14 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) { EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, true); + + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 3)); + EXPECT_EQ(record->event->timestamp, 102000); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); + EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); + EXPECT_STREQ(record->event->character, nullptr); EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); diff --git a/shell/platform/linux/fl_view.cc b/shell/platform/linux/fl_view.cc index adafa75a857a8..5aef7f9e20fa6 100644 --- a/shell/platform/linux/fl_view.cc +++ b/shell/platform/linux/fl_view.cc @@ -183,12 +183,13 @@ static void fl_view_constructed(GObject* object) { self->accessibility_plugin = fl_accessibility_plugin_new(self); self->keyboard_manager = fl_keyboard_manager_new( fl_text_input_plugin_new(messenger, self), gdk_event_put); + // The embedder responder must be added before the channel responder. fl_keyboard_manager_add_responder( self->keyboard_manager, - FL_KEY_RESPONDER(fl_key_channel_responder_new(messenger))); + FL_KEY_RESPONDER(fl_key_embedder_responder_new(self->engine))); fl_keyboard_manager_add_responder( self->keyboard_manager, - FL_KEY_RESPONDER(fl_key_embedder_responder_new(self->engine))); + FL_KEY_RESPONDER(fl_key_channel_responder_new(messenger))); self->mouse_cursor_plugin = fl_mouse_cursor_plugin_new(messenger, self); self->platform_plugin = fl_platform_plugin_new(messenger); diff --git a/shell/platform/linux/key_mapping.cc b/shell/platform/linux/key_mapping.cc index 828ad3b92eb81..b01709a0db871 100644 --- a/shell/platform/linux/key_mapping.cc +++ b/shell/platform/linux/key_mapping.cc @@ -429,6 +429,7 @@ void initialize_modifier_bit_to_checked_keys(GHashTable* table) { data->first_logical_key = 0x30000010d; // shiftLeft physical_keys = g_new(uint64_t, 2); data->physical_keys = physical_keys; + data->is_caps_lock = false; *(physical_keys++) = 0x000700e1; // ShiftLeft *(physical_keys++) = 0x000700e5; // ShiftRight @@ -438,6 +439,7 @@ void initialize_modifier_bit_to_checked_keys(GHashTable* table) { data->first_logical_key = 0x300000105; // controlLeft physical_keys = g_new(uint64_t, 2); data->physical_keys = physical_keys; + data->is_caps_lock = false; *(physical_keys++) = 0x000700e0; // ControlLeft *(physical_keys++) = 0x000700e4; // ControlRight @@ -447,6 +449,7 @@ void initialize_modifier_bit_to_checked_keys(GHashTable* table) { data->first_logical_key = 0x300000102; // altLeft physical_keys = g_new(uint64_t, 2); data->physical_keys = physical_keys; + data->is_caps_lock = false; *(physical_keys++) = 0x000700e2; // AltLeft *(physical_keys++) = 0x000700e6; // AltRight @@ -456,6 +459,7 @@ void initialize_modifier_bit_to_checked_keys(GHashTable* table) { data->first_logical_key = 0x300000109; // metaLeft physical_keys = g_new(uint64_t, 2); data->physical_keys = physical_keys; + data->is_caps_lock = false; *(physical_keys++) = 0x000700e3; // MetaLeft *(physical_keys++) = 0x000700e7; // MetaRight } @@ -470,6 +474,7 @@ void initialize_lock_mode_bit_to_checked_keys(GHashTable* table) { data->first_logical_key = 0x000000104; // capsLock physical_keys = g_new(uint64_t, 1); data->physical_keys = physical_keys; + data->is_caps_lock = true; *(physical_keys++) = 0x00070039; // CapsLock data = g_new(FlKeyEmbedderCheckedKey, 1); @@ -478,5 +483,6 @@ void initialize_lock_mode_bit_to_checked_keys(GHashTable* table) { data->first_logical_key = 0x00000010a; // numLock physical_keys = g_new(uint64_t, 1); data->physical_keys = physical_keys; + data->is_caps_lock = false; *(physical_keys++) = 0x00070053; // NumLock } From 81782906852c52676d9b2b55d1c240cfcc0e5ee9 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 19 Apr 2021 05:28:49 -0700 Subject: [PATCH 040/126] Fix warnings --- .../linux/fl_key_embedder_responder.cc | 17 ++++++++------ .../linux/fl_key_embedder_responder_test.cc | 23 +++++++++++-------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index 74bc7fa15f0cb..5e674dded8f4f 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -584,19 +584,15 @@ static void fl_key_embedder_responder_handle_event( sync_pressed_state_context.is_down = is_down_event; sync_pressed_state_context.event_physical_key = physical_key; + // Update lock mode states g_hash_table_foreach(self->lock_mode_bit_to_checked_keys, synchronize_lock_mode_states_loop_body, &sync_pressed_state_context); + // Construct the real event + printf("Real event\n"); const uint64_t last_logical_record = lookup_hash_table(self->pressing_records, physical_key); - update_pressing_state(self, physical_key, is_down_event ? logical_key : 0); - possibly_update_lock_mode_bit(self, physical_key, is_down_event); - - // printf("Before foreach\n"); - g_hash_table_foreach(self->modifier_bit_to_checked_keys, - synchronize_pressed_states_loop_body, - &sync_pressed_state_context); FlutterKeyEvent out_event; out_event.struct_size = sizeof(out_event); @@ -631,6 +627,13 @@ static void fl_key_embedder_responder_handle_event( out_event.type = kFlutterKeyEventTypeUp; } } + update_pressing_state(self, physical_key, is_down_event ? logical_key : 0); + possibly_update_lock_mode_bit(self, physical_key, is_down_event); + + // Update pressing states + g_hash_table_foreach(self->modifier_bit_to_checked_keys, + synchronize_pressed_states_loop_body, + &sync_pressed_state_context); FlKeyEmbedderUserData* response_data = fl_key_embedder_user_data_new(self, callback, user_data); diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index 2e13828a763d5..d1f664e3727e8 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -173,6 +173,11 @@ static FlEngine* make_mock_engine_with_records() { return engine; } +static void clear_g_call_records() { + g_ptr_array_free(g_call_records, TRUE); + g_call_records = nullptr; +} + // Basic key presses TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { EXPECT_EQ(g_call_records, nullptr); @@ -264,7 +269,7 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { invoke_record_callback_and_verify(record, FALSE, &user_data); g_ptr_array_clear(g_call_records); - g_clear_object(&g_call_records); + clear_g_call_records(); } // Press Shift, key A, then release Shift, key A. @@ -348,7 +353,7 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { invoke_record_callback_and_verify(record, TRUE, &user_data); g_ptr_array_clear(g_call_records); - g_clear_object(&g_call_records); + clear_g_call_records(); } // Press or release Numpad 1 between presses/releases of NumLock. @@ -513,7 +518,7 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { invoke_record_callback_and_verify(record, TRUE, &user_data); g_ptr_array_clear(g_call_records); - g_clear_object(&g_call_records); + clear_g_call_records(); } // Press or release letter key between presses/releases of CapsLock. @@ -674,7 +679,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { invoke_record_callback_and_verify(record, TRUE, &user_data); g_ptr_array_clear(g_call_records); - g_clear_object(&g_call_records); + clear_g_call_records(); } TEST(FlKeyEmbedderResponderTest, IgnoreDuplicateDownEvent) { @@ -720,7 +725,7 @@ TEST(FlKeyEmbedderResponderTest, IgnoreDuplicateDownEvent) { invoke_record_callback_and_verify(record, TRUE, &user_data); g_ptr_array_clear(g_call_records); - g_clear_object(&g_call_records); + clear_g_call_records(); } TEST(FlKeyEmbedderResponderTest, IgnoreAbruptUpEvent) { @@ -740,7 +745,7 @@ TEST(FlKeyEmbedderResponderTest, IgnoreAbruptUpEvent) { EXPECT_EQ(g_call_records->len, 0u); - g_clear_object(&g_call_records); + clear_g_call_records(); } // Test if missed modifier keys can be detected and synthesized with state @@ -815,7 +820,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingState) { invoke_record_callback_and_verify(record, TRUE, &user_data); g_ptr_array_clear(g_call_records); - g_clear_object(&g_call_records); + clear_g_call_records(); } // Test if missed lock keys can be detected and synthesized with state @@ -917,7 +922,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { EXPECT_EQ(g_call_records->len, 0u); - g_clear_object(&g_call_records); + clear_g_call_records(); } // Test if missed lock keys can be detected and synthesized with state @@ -1016,5 +1021,5 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) { invoke_record_callback_and_verify(record, TRUE, &user_data); g_ptr_array_clear(g_call_records); - g_clear_object(&g_call_records); + clear_g_call_records(); } From 1305f601f31982f492f3f06d5480cf17b62be7d7 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 19 Apr 2021 05:30:48 -0700 Subject: [PATCH 041/126] Hide some comments --- shell/platform/linux/fl_key_embedder_responder.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index 5e674dded8f4f..5b38816caed34 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -459,7 +459,7 @@ static void possibly_update_lock_mode_bit(FlKeyEmbedderResponder* self, } const guint mode_bit = GPOINTER_TO_UINT(g_hash_table_lookup( self->physical_key_to_lock_mode_bit, uint64_to_gpointer(physical_key))); - printf("Mode bit for PhK %lx is %x\n", physical_key, mode_bit); + // printf("Mode bit for PhK %lx is %x\n", physical_key, mode_bit); if (mode_bit != 0) { self->lock_mode_records ^= mode_bit; } @@ -590,7 +590,7 @@ static void fl_key_embedder_responder_handle_event( &sync_pressed_state_context); // Construct the real event - printf("Real event\n"); + // printf("Real event\n"); const uint64_t last_logical_record = lookup_hash_table(self->pressing_records, physical_key); From db89b3ba625d83a32d3b2c983bf9bb273193bae9 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Wed, 21 Apr 2021 23:07:43 -0700 Subject: [PATCH 042/126] format --- shell/platform/linux/fl_key_embedder_responder.cc | 11 ++++++----- .../platform/linux/fl_key_embedder_responder_test.cc | 6 ++---- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index 5b38816caed34..bc95d2b0308a0 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -479,18 +479,18 @@ static void synchronize_lock_mode_states_loop_body(gpointer key, const uint64_t logical_key = checked_key->first_logical_key; const uint64_t physical_key = checked_key->physical_keys[0]; printf("Syn: 1 state %x bit %x curPhy %lx\n", context->state, modifier_bit, - context->event_physical_key); + context->event_physical_key); // A lock mode key can be at any of a 4-stage cycle. The following table lists // the definition of each stage (TruePressed and TrueEnabled), the event of // the lock key between every 2 stages (SelfType and SelfState), and the event - // of other keys at each stage (OthersState). Notice that SelfState uses different - // rule for CapsLock. + // of other keys at each stage (OthersState). Notice that SelfState uses + // different rule for CapsLock. // // # [0] [1] [2] [3] // TruePressed: Released Pressed Released Pressed // TrueEnabled: Disabled Enabled Enabled Disabled - // SelfType: Down Up Down Up + // SelfType: Down Up Down Up // SelfState(Caps): 1 1 0 1 // SelfState(Etc): 0 1 1 1 // OthersState: 0 1 1 1 @@ -512,7 +512,8 @@ static void synchronize_lock_mode_states_loop_body(gpointer key, const int stage_by_event = is_self_event ? find_stage_by_self_event(stage_by_record, context->is_down, - enabled_by_state, checked_key->is_caps_lock) + enabled_by_state, + checked_key->is_caps_lock) : find_stage_by_others_event(stage_by_record, enabled_by_state); // If the event is for the target key, then the last stage transition should diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index d1f664e3727e8..8fc87fd2432f7 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -538,8 +538,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { // Press key A (stage 0) fl_key_responder_handle_event( responder, - key_event_new(101, kPress, GDK_KEY_a, kKeyCodeKeyA, 0, - kIsNotModifier), + key_event_new(101, kPress, GDK_KEY_a, kKeyCodeKeyA, 0, kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -610,8 +609,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { // Press key A (stage 2) fl_key_responder_handle_event( responder, - key_event_new(101, kPress, GDK_KEY_A, kKeyCodeKeyA, 0x2, - kIsNotModifier), + key_event_new(101, kPress, GDK_KEY_A, kKeyCodeKeyA, 0x2, kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); From 8bcafa4661866f25225f8e844cf974003793790e Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Sat, 24 Apr 2021 16:07:55 -0700 Subject: [PATCH 043/126] KeyboardManager doc --- .../framework/Source/FlutterKeyboardManager.h | 6 +- shell/platform/linux/fl_keyboard_manager.cc | 2 +- shell/platform/linux/fl_keyboard_manager.h | 90 +++++++++++++------ .../linux/fl_keyboard_manager_test.cc | 14 +-- 4 files changed, 74 insertions(+), 38 deletions(-) diff --git a/shell/platform/darwin/macos/framework/Source/FlutterKeyboardManager.h b/shell/platform/darwin/macos/framework/Source/FlutterKeyboardManager.h index 922f1ad0721f4..2ddae205e109d 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterKeyboardManager.h +++ b/shell/platform/darwin/macos/framework/Source/FlutterKeyboardManager.h @@ -17,7 +17,7 @@ * secondary responders. * * An event that is received by |handleEvent| is first dispatched to *all* - * primary resopnders. Each primary responder responds *ascynchronously* with a + * primary responders. Each primary responder responds *ascynchronously* with a * boolean, indicating whether it handles the event. * * An event that is not handled by any primary responders is then passed to to @@ -35,7 +35,7 @@ * because in reality this class will only support 2 hardcoded ones (channel * and embedder), where the only purpose of supporting two is to support the * legacy API (channel) during the deprecation window, after which the channel - * resopnder should be removed. + * responder should be removed. */ @interface FlutterKeyboardManager : NSObject @@ -50,7 +50,7 @@ - (nonnull instancetype)initWithOwner:(nonnull NSResponder*)weakOwner; /** - * Add a primary resopnder, which asynchronously decides whether to handle an + * Add a primary responder, which asynchronously decides whether to handle an * event. */ - (void)addPrimaryResponder:(nonnull id)responder; diff --git a/shell/platform/linux/fl_keyboard_manager.cc b/shell/platform/linux/fl_keyboard_manager.cc index 1b495000af3a7..cb7b7019e4ae1 100644 --- a/shell/platform/linux/fl_keyboard_manager.cc +++ b/shell/platform/linux/fl_keyboard_manager.cc @@ -343,7 +343,7 @@ gboolean fl_keyboard_manager_handle_event(FlKeyboardManager* self, return TRUE; } -gboolean fl_keyboard_manager_state_clear(FlKeyboardManager* self) { +gboolean fl_keyboard_manager_is_state_clear(FlKeyboardManager* self) { g_return_val_if_fail(FL_IS_KEYBOARD_MANAGER(self), FALSE); return self->pending_responds->len == 0 && self->pending_redispatches->len == 0; diff --git a/shell/platform/linux/fl_keyboard_manager.h b/shell/platform/linux/fl_keyboard_manager.h index e8021280404b0..e0ddc2f432f99 100644 --- a/shell/platform/linux/fl_keyboard_manager.h +++ b/shell/platform/linux/fl_keyboard_manager.h @@ -11,21 +11,18 @@ #include "flutter/shell/platform/linux/fl_text_input_plugin.h" /** - * FlKeyEventPluginCallback: - * @source_object: (nullable): the object the key event was started with. - * @message: the message returned from the framework. - * @handled: a boolean indicating whether the key event was handled in the - * framework. - * @user_data: user data passed to the callback. + * FlKeyboardManagerRedispatcher: * - * Type definition for a function that will be called when a key event is - * received from the engine. + * The signature for a function where #FlKeyboardManager redispatches key events + * that are not handled by anyone. + * + * @event: the event to dispatch. **/ typedef void (*FlKeyboardManagerRedispatcher)(const GdkEvent* event); G_BEGIN_DECLS -#define FL_KEYBOARD_MANAGER fl_keyboard_manager_get_type +#define FL_TYPE_KEYBOARD_MANAGER fl_keyboard_manager_get_type G_DECLARE_FINAL_TYPE(FlKeyboardManager, fl_keyboard_manager, FL, @@ -35,41 +32,80 @@ G_DECLARE_FINAL_TYPE(FlKeyboardManager, /** * FlKeyboardManager: * - * #FlKeyboardManager is a plugin that implements the shell side - * of SystemChannels.keyEvent from the Flutter services library. + * A hub that manages how key events are dispatched to various processing + * objects of Flutter, or possibly back to the system. + * + * This class manage one or more objects of #FlKeyResponder, as well as a + * #TextInputPlugin. + * + * An event that is received by #fl_keyboard_manager_handle_event is first + * dispatched to *all* responders. Each responder responds *ascynchronously* + * with a boolean, indicating whether it handles the event. + * + * An event that is not handled by any responders is then passed to to the + * #TextInputPlugin, which responds *synchronously* with a boolean, indicating + * whether it handles the event. + * + * If no processing objects handle the event, the event is then "redispatched": + * sent back to the system using #redispatch_callback. + * + * Preventing responders from receiving events is not supported, because in + * reality this class will only support 2 hardcoded ones (channel and + * embedder), where the only purpose of supporting two is to support the legacy + * API (channel) during the deprecation window, after which the channel + * responder should be removed. */ /** * fl_keyboard_manager_new: - * @messenger: an #FlBinaryMessenger. - * @response_callback: the callback to call when a response is received. If not - * given (nullptr), then the default response callback is - * used. Typically used for tests to receive event - * information. If specified, unhandled events will not be - * re-dispatched. - * @text_input_plugin: The #FlTextInputPlugin to send key events to if the - * framework doesn't handle them. - * @channel_name: the name of the channel to send key events to the framework - * on. If not given (nullptr), then the standard key event - * channel name is used. Typically used for tests to send on a - * test channel. + * @text_input_plugin: the #FlTextInputPlugin to send key events to if the + * framework doesn't handle them. + * @redispatch_callback: how the events should be sent if no processing + * objects handle the event. Typically #gdk_event_put. * - * Creates a new plugin that implements SystemChannels.keyEvent from the - * Flutter services library. + * Create a new #FlKeyboardManager. The text input plugin must be specified + * now, while the responders should be added later with + * #fl_keyboard_manager_add_responder. * - * Returns: a new #FlKeyEventPlugin. + * Returns: a new #FlKeyboardManager. */ FlKeyboardManager* fl_keyboard_manager_new( FlTextInputPlugin* text_input_plugin, FlKeyboardManagerRedispatcher redispatch_callback); +/** + * fl_keyboard_manager_add_responder: + * @manager: the #FlKeyboardManager self. + * @responder: the new responder to be added. + * + * Add a new #FlKeyResponder to the #FlKeyboardManager. Responders added + * earlier will receive events earlier. + */ void fl_keyboard_manager_add_responder(FlKeyboardManager* manager, FlKeyResponder* responder); +/** + * fl_keyboard_manager_handle_event: + * @manager: the #FlKeyboardManager self. + * @event: the event to be dispatched. + * + * Add a new #FlKeyResponder to the #FlKeyboardManager. Responders added + * earlier will receive events earlier. + */ gboolean fl_keyboard_manager_handle_event(FlKeyboardManager* manager, GdkEventKey* event); -gboolean fl_keyboard_manager_state_clear(FlKeyboardManager* manager); +/** + * fl_keyboard_manager_is_state_clear: + * @manager: the #FlKeyboardManager self. + * + * Whether the manager's various states are cleared, i.e. no pending events + * for redispatching or for responding. This is mostly used in unittests. + * + * Returns: true if the manager's various states are cleared. + */ +gboolean fl_keyboard_manager_is_state_clear( + 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 7e5a3268ec965..150ae04faaf5a 100644 --- a/shell/platform/linux/fl_keyboard_manager_test.cc +++ b/shell/platform/linux/fl_keyboard_manager_test.cc @@ -232,7 +232,7 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { record->callback(true, record->user_data); EXPECT_EQ(redispatched_events()->len, 0u); - EXPECT_TRUE(fl_keyboard_manager_state_clear(manager)); + EXPECT_TRUE(fl_keyboard_manager_is_state_clear(manager)); g_ptr_array_clear(call_records); /// Test 2: Two events that are unhandled by the framework @@ -281,7 +281,7 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { EXPECT_EQ(call_records->len, 0u); g_ptr_array_clear(redispatched_events()); - EXPECT_TRUE(fl_keyboard_manager_state_clear(manager)); + EXPECT_TRUE(fl_keyboard_manager_is_state_clear(manager)); /// Test 3: Dispatch the same event again to ensure that prevention from /// redispatching only works once. @@ -321,9 +321,9 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithSyncResponds) { EXPECT_EQ(record->event->hardware_keycode, 0x26u); EXPECT_EQ(redispatched_events()->len, 0u); - EXPECT_TRUE(fl_keyboard_manager_state_clear(manager)); + EXPECT_TRUE(fl_keyboard_manager_is_state_clear(manager)); - EXPECT_TRUE(fl_keyboard_manager_state_clear(manager)); + EXPECT_TRUE(fl_keyboard_manager_is_state_clear(manager)); g_ptr_array_clear(call_records); /// Test 2: An event unhandled by the framework @@ -346,7 +346,7 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithSyncResponds) { EXPECT_EQ(manager_handled, false); EXPECT_EQ(call_records->len, 0u); - EXPECT_TRUE(fl_keyboard_manager_state_clear(manager)); + EXPECT_TRUE(fl_keyboard_manager_is_state_clear(manager)); g_ptr_array_clear(redispatched_events()); } @@ -383,7 +383,7 @@ TEST(FlKeyboardManagerTest, WithTwoAsyncDelegates) { record->callback(false, record->user_data); EXPECT_EQ(redispatched_events()->len, 0u); - EXPECT_TRUE(fl_keyboard_manager_state_clear(manager)); + EXPECT_TRUE(fl_keyboard_manager_is_state_clear(manager)); g_ptr_array_clear(call_records); /// Test 2: All delegates respond false @@ -409,7 +409,7 @@ TEST(FlKeyboardManagerTest, WithTwoAsyncDelegates) { EXPECT_EQ(manager_handled, false); EXPECT_EQ(call_records->len, 0u); - EXPECT_TRUE(fl_keyboard_manager_state_clear(manager)); + EXPECT_TRUE(fl_keyboard_manager_is_state_clear(manager)); g_ptr_array_clear(call_records); g_ptr_array_clear(redispatched_events()); From c7a08fa57d5dec947ce4fe90c9c0227375e94fa6 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Sat, 24 Apr 2021 21:27:30 -0700 Subject: [PATCH 044/126] Docs --- .../platform/linux/fl_key_channel_responder.h | 35 +++++++++------- .../linux/fl_key_embedder_responder.h | 23 ++++------ shell/platform/linux/fl_key_responder.h | 42 ++++++++++++++----- shell/platform/linux/fl_keyboard_manager.h | 7 ++-- 4 files changed, 60 insertions(+), 47 deletions(-) diff --git a/shell/platform/linux/fl_key_channel_responder.h b/shell/platform/linux/fl_key_channel_responder.h index 75d14b693fe00..3f0a1cda652d8 100644 --- a/shell/platform/linux/fl_key_channel_responder.h +++ b/shell/platform/linux/fl_key_channel_responder.h @@ -14,8 +14,20 @@ typedef FlValue* (*FlValueConverter)(FlValue*); +/** + * FlKeyChannelResponderMock: + * + * Options to mock several functionalities. Only used in unittests. + */ typedef struct _FlKeyChannelResponderMock { + /** + * FlKeyChannelResponderMock::value_converter: + */ FlValueConverter value_converter; + + /** + * FlKeyChannelResponderMock::channel_name: + */ const char* channel_name; } FlKeyChannelResponderMock; @@ -31,27 +43,18 @@ G_DECLARE_FINAL_TYPE(FlKeyChannelResponder, /** * FlKeyChannelResponder: * - * #FlKeyChannelResponder is a plugin that implements the shell side - * of SystemChannels.keyEvent from the Flutter services library. + * A #FlKeyResponder that handles events by sending the raw event data + * in JSON through the message channel. + * + * This class corresponds to the RawKeyboard API in the framework. */ /** * fl_key_channel_responder_new: - * @messenger: an #FlBinaryMessenger. - * @response_callback: the callback to call when a response is received. If not - * given (nullptr), then the default response callback is - * used. Typically used for tests to receive event - * information. If specified, unhandled events will not be - * re-dispatched. - * @text_input_plugin: The #FlTextInputPlugin to send key events to if the - * framework doesn't handle them. - * @channel_name: the name of the channel to send key events to the framework - * on. If not given (nullptr), then the standard key event - * channel name is used. Typically used for tests to send on a - * test channel. + * @messenger: the messenger that the message channel should be built on. + * @mock: options to mock several functionalities. Only used in unittests. * - * Creates a new plugin that implements SystemChannels.keyEvent from the - * Flutter services library. + * Creates a new #FlKeyChannelResponder. * * Returns: a new #FlKeyChannelResponder. */ diff --git a/shell/platform/linux/fl_key_embedder_responder.h b/shell/platform/linux/fl_key_embedder_responder.h index 849d57039ea87..7e2ede7aff347 100644 --- a/shell/platform/linux/fl_key_embedder_responder.h +++ b/shell/platform/linux/fl_key_embedder_responder.h @@ -26,27 +26,18 @@ G_DECLARE_FINAL_TYPE(FlKeyEmbedderResponder, /** * FlKeyEmbedderResponder: * - * #FlKeyEmbedderResponder is a plugin that implements the shell side - * of SystemEmbedders.keyEvent from the Flutter services library. + * A #FlKeyResponder that handles events by sending the converted events + * through the embedder API. + * + * This class corresponds to the HardwareKeyboard API in the framework. */ /** * fl_key_embedder_responder_new: - * @messenger: an #FlBinaryMessenger. - * @response_callback: the callback to call when a response is received. If not - * given (nullptr), then the default response callback is - * used. Typically used for tests to receive event - * information. If specified, unhandled events will not be - * re-dispatched. - * @text_input_plugin: The #FlTextInputPlugin to send key events to if the - * framework doesn't handle them. - * @embedder_name: the name of the embedder to send key events to the framework - * on. If not given (nullptr), then the standard key event - * embedder name is used. Typically used for tests to send on a - * test embedder. + * @engine: The #FlEngine, whose the embedder API will be used to send + * the event. * - * Creates a new plugin that implements SystemEmbedders.keyEvent from the - * Flutter services library. + * Creates a new #FlKeyEmbedderResponder. * * Returns: a new #FlKeyEmbedderResponder. */ diff --git a/shell/platform/linux/fl_key_responder.h b/shell/platform/linux/fl_key_responder.h index fb1135411a9c0..1b415089c3aff 100644 --- a/shell/platform/linux/fl_key_responder.h +++ b/shell/platform/linux/fl_key_responder.h @@ -14,27 +14,41 @@ G_BEGIN_DECLS typedef struct _FlKeyboardManager FlKeyboardManager; + +/** + * FlKeyResponderAsyncCallback: + * @event: whether the event has been handled. + * @user_data: the same value as user_data sent by + * #fl_key_responder_handle_event. + * + * The signature for a callback with which a #FlKeyResponder asynchronously + * reports whether the responder handles the event. + **/ typedef void (*FlKeyResponderAsyncCallback)(bool handled, gpointer user_data); #define FL_TYPE_KEY_RESPONDER fl_key_responder_get_type() - G_DECLARE_INTERFACE(FlKeyResponder, fl_key_responder, FL, KEY_RESPONDER, GObject); +/** + * FlKeyResponder: + * + * An interface for a responder that can process a key event and decides + * asynchronously whether to handle an event. + * + * To use this class, add it with #fl_keyboard_manager_add_responder. + */ + struct _FlKeyResponderInterface { GTypeInterface g_iface; /** - * FlPluginRegistry::get_registrar_for_plugin: - * @registry: an #FlPluginRegistry. - * @name: plugin name. + * FlKeyResponder::handle_event: * - * Gets the plugin registrar for the the plugin with @name. - * - * Returns: (transfer full): an #FlPluginRegistrar. + * The implementation of #fl_key_responder_handle_event. */ void (*handle_event)(FlKeyResponder* responder, GdkEventKey* event, @@ -43,12 +57,18 @@ struct _FlKeyResponderInterface { }; /** - * FlKeyResponder: + * fl_key_responder_handle_event: + * @responder: the #FlKeyResponder self. + * @event: the event to be handled. Must not be null. + * @callback: the callback to report the result. It should be called exactly + * once. Must not be null. + * @user_data: a value that will be sent back in the callback. Can be null. * - * #FlKeyResponder is a plugin that implements the shell side - * of SystemChannels.keyEvent from the Flutter services library. + * Let the responder handle an event, expecting the responder to report + * whether to handle the event. The result will be reported by invoking + * `callback` exactly once, which might happen after + * `fl_key_responder_handle_event` or during it. */ - void fl_key_responder_handle_event(FlKeyResponder* responder, GdkEventKey* event, FlKeyResponderAsyncCallback callback, diff --git a/shell/platform/linux/fl_keyboard_manager.h b/shell/platform/linux/fl_keyboard_manager.h index e0ddc2f432f99..47bf2ff60da82 100644 --- a/shell/platform/linux/fl_keyboard_manager.h +++ b/shell/platform/linux/fl_keyboard_manager.h @@ -12,11 +12,10 @@ /** * FlKeyboardManagerRedispatcher: - * - * The signature for a function where #FlKeyboardManager redispatches key events - * that are not handled by anyone. - * * @event: the event to dispatch. + * + * The signature for a callback with which a #FlKeyboardManager redispatches + * key events that are not handled by anyone. **/ typedef void (*FlKeyboardManagerRedispatcher)(const GdkEvent* event); From 822cb129b2e0425e1952d3e489b5f257cd81d4ce Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Sun, 25 Apr 2021 21:30:32 -0700 Subject: [PATCH 045/126] Refactor Checked Key --- .../linux/fl_key_embedder_responder.cc | 77 +- .../linux/fl_key_embedder_responder_private.h | 30 +- shell/platform/linux/key_mapping.cc | 691 +++++++++--------- shell/platform/linux/key_mapping.h | 2 +- shell/platform/windows/flutter_key_map.cc | 250 +++---- 5 files changed, 527 insertions(+), 523 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index 5b38816caed34..ff642575efaaf 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -96,7 +96,7 @@ struct _FlKeyEmbedderResponder { // Both keys and values are directly stored uint64s. GHashTable* pressing_records; - guint lock_mode_records; + guint lock_records; // A static map from XKB to Flutter's physical key code GHashTable* xkb_to_physical_key; @@ -106,9 +106,9 @@ struct _FlKeyEmbedderResponder { GHashTable* modifier_bit_to_checked_keys; - GHashTable* lock_mode_bit_to_checked_keys; + GHashTable* lock_bit_to_checked_keys; - GHashTable* physical_key_to_lock_mode_bit; + GHashTable* physical_key_to_lock_bit; }; static void fl_key_embedder_responder_iface_init( @@ -140,7 +140,7 @@ static void fl_key_embedder_responder_dispose(GObject* object) { g_clear_pointer(&self->xkb_to_physical_key, g_hash_table_unref); g_clear_pointer(&self->keyval_to_logical_key, g_hash_table_unref); g_clear_pointer(&self->modifier_bit_to_checked_keys, g_hash_table_unref); - g_clear_pointer(&self->lock_mode_bit_to_checked_keys, g_hash_table_unref); + g_clear_pointer(&self->lock_bit_to_checked_keys, g_hash_table_unref); G_OBJECT_CLASS(fl_key_embedder_responder_parent_class)->dispose(object); } @@ -154,22 +154,15 @@ static void fl_key_embedder_responder_class_init( // Initializes an FlKeyEmbedderResponder instance. static void fl_key_embedder_responder_init(FlKeyEmbedderResponder* self) {} -static void checked_key_free_notify(gpointer pointer) { - FlKeyEmbedderCheckedKey* checked_key = - reinterpret_cast(pointer); - g_free(checked_key->physical_keys); - g_free(checked_key); -} - -static void initialize_physical_key_to_lock_mode_bit_loop_body( - gpointer lock_mode_bit, +static void initialize_physical_key_to_lock_bit_loop_body( + gpointer lock_bit, gpointer value, gpointer user_data) { FlKeyEmbedderCheckedKey* checked_key = reinterpret_cast(value); GHashTable* table = reinterpret_cast(user_data); g_hash_table_insert(table, uint64_to_gpointer(checked_key->physical_keys[0]), - GUINT_TO_POINTER(lock_mode_bit)); + GUINT_TO_POINTER(lock_bit)); } // Creates a new FlKeyEmbedderResponder instance, with a messenger used to send @@ -190,7 +183,7 @@ FlKeyEmbedderResponder* fl_key_embedder_responder_new(FlEngine* engine) { reinterpret_cast(&(self->engine))); self->pressing_records = g_hash_table_new(g_direct_hash, g_direct_equal); - self->lock_mode_records = 0; + self->lock_records = 0; self->xkb_to_physical_key = g_hash_table_new(g_direct_hash, g_direct_equal); initialize_xkb_to_physical_key(self->xkb_to_physical_key); @@ -199,18 +192,18 @@ FlKeyEmbedderResponder* fl_key_embedder_responder_new(FlEngine* engine) { initialize_gtk_keyval_to_logical_key(self->keyval_to_logical_key); self->modifier_bit_to_checked_keys = g_hash_table_new_full( - g_direct_hash, g_direct_equal, NULL, checked_key_free_notify); + g_direct_hash, g_direct_equal, NULL, g_free); initialize_modifier_bit_to_checked_keys(self->modifier_bit_to_checked_keys); - self->lock_mode_bit_to_checked_keys = g_hash_table_new_full( - g_direct_hash, g_direct_equal, NULL, checked_key_free_notify); - initialize_lock_mode_bit_to_checked_keys(self->lock_mode_bit_to_checked_keys); + self->lock_bit_to_checked_keys = g_hash_table_new_full( + g_direct_hash, g_direct_equal, NULL, g_free); + initialize_lock_bit_to_checked_keys(self->lock_bit_to_checked_keys); - self->physical_key_to_lock_mode_bit = + self->physical_key_to_lock_bit = g_hash_table_new(g_direct_hash, g_direct_equal); - g_hash_table_foreach(self->lock_mode_bit_to_checked_keys, - initialize_physical_key_to_lock_mode_bit_loop_body, - self->physical_key_to_lock_mode_bit); + g_hash_table_foreach(self->lock_bit_to_checked_keys, + initialize_physical_key_to_lock_bit_loop_body, + self->physical_key_to_lock_bit); return self; } @@ -338,14 +331,18 @@ static void synchronize_pressed_states_loop_body(gpointer key, const guint modifier_bit = GPOINTER_TO_INT(key); FlKeyEmbedderResponder* self = context->self; - const uint64_t* physical_keys = checked_key->physical_keys; + const uint64_t physical_keys[] = { + checked_key->primary_physical_key, + checked_key->secondary_physical_key, + }; + const int length = checked_key->secondary_physical_key == 0 ? 1 : 2; // printf("Syn: 1 state %x bit %x curPhy %lx\n", context->state, modifier_bit, // context->event_physical_key); const bool pressed_by_state = (context->state & modifier_bit) != 0; bool pressed_by_record = false; - for (guint physical_key_idx = 0; physical_key_idx < checked_key->length; + for (guint physical_key_idx = 0; physical_key_idx < length; physical_key_idx++) { const uint64_t physical_key = physical_keys[physical_key_idx]; const uint64_t pressed_logical_key = @@ -372,9 +369,9 @@ static void synchronize_pressed_states_loop_body(gpointer key, } } if (pressed_by_state && !pressed_by_record) { - uint64_t physical_key = physical_keys[0]; + uint64_t physical_key = checked_key->primary_physical_key; g_return_if_fail(physical_key != context->event_physical_key); - uint64_t logical_key = checked_key->first_logical_key; + uint64_t logical_key = checked_key->primary_logical_key; // printf("Syn: 4 SYN: phy %lx log %lx\n", physical_key, logical_key); synthesize_simple_event(self, kFlutterKeyEventTypeDown, physical_key, logical_key, context->timestamp); @@ -396,7 +393,7 @@ static int cycle_stage_to_after(int target, int start) { } // Find the stage # before the event (of the 4 stages as documented in -// `synchronize_lock_mode_states_loop_body`) by the current record. +// `synchronize_lock_states_loop_body`) by the current record. static int find_stage_by_record(bool is_down, bool is_enabled) { constexpr int stage_by_record_index[] = { 0, // is_down: 0, is_enabled: 0 @@ -451,21 +448,21 @@ static void update_pressing_state(FlKeyEmbedderResponder* self, } } -static void possibly_update_lock_mode_bit(FlKeyEmbedderResponder* self, +static void possibly_update_lock_bit(FlKeyEmbedderResponder* self, uint64_t physical_key, bool is_down) { if (!is_down) { return; } const guint mode_bit = GPOINTER_TO_UINT(g_hash_table_lookup( - self->physical_key_to_lock_mode_bit, uint64_to_gpointer(physical_key))); + self->physical_key_to_lock_bit, uint64_to_gpointer(physical_key))); // printf("Mode bit for PhK %lx is %x\n", physical_key, mode_bit); if (mode_bit != 0) { - self->lock_mode_records ^= mode_bit; + self->lock_records ^= mode_bit; } } -static void synchronize_lock_mode_states_loop_body(gpointer key, +static void synchronize_lock_states_loop_body(gpointer key, gpointer value, gpointer user_data) { SyncPressedStatesLoopContext* context = @@ -476,8 +473,8 @@ static void synchronize_lock_mode_states_loop_body(gpointer key, guint modifier_bit = GPOINTER_TO_INT(key); FlKeyEmbedderResponder* self = context->self; - const uint64_t logical_key = checked_key->first_logical_key; - const uint64_t physical_key = checked_key->physical_keys[0]; + const uint64_t logical_key = checked_key->primary_logical_key; + const uint64_t physical_key = checked_key->primary_physical_key; printf("Syn: 1 state %x bit %x curPhy %lx\n", context->state, modifier_bit, context->event_physical_key); @@ -505,7 +502,7 @@ static void synchronize_lock_mode_states_loop_body(gpointer key, g_return_if_fail(pressed_logical_key == 0 || pressed_logical_key == logical_key); const int stage_by_record = find_stage_by_record( - pressed_logical_key != 0, (self->lock_mode_records & modifier_bit) != 0); + pressed_logical_key != 0, (self->lock_records & modifier_bit) != 0); const bool enabled_by_state = (context->state & modifier_bit) != 0; const bool is_self_event = physical_key == context->event_physical_key; @@ -541,7 +538,7 @@ static void synchronize_lock_mode_states_loop_body(gpointer key, FlutterKeyEventType type = is_down_event ? kFlutterKeyEventTypeDown : kFlutterKeyEventTypeUp; update_pressing_state(self, physical_key, is_down_event ? logical_key : 0); - possibly_update_lock_mode_bit(self, physical_key, is_down_event); + possibly_update_lock_bit(self, physical_key, is_down_event); synthesize_simple_event(self, type, physical_key, logical_key, context->timestamp); } @@ -574,7 +571,7 @@ static void fl_key_embedder_responder_handle_event( event->type == GDK_KEY_PRESS ? "PRESS" : "RELEASE", event->keyval, event->hardware_keycode, event->state, event->is_modifier, event->send_event, event->group, event->time, _text_idx, - self->lock_mode_records, physical_key); + self->lock_records, physical_key); fflush(stdout); SyncPressedStatesLoopContext sync_pressed_state_context; @@ -585,8 +582,8 @@ static void fl_key_embedder_responder_handle_event( sync_pressed_state_context.event_physical_key = physical_key; // Update lock mode states - g_hash_table_foreach(self->lock_mode_bit_to_checked_keys, - synchronize_lock_mode_states_loop_body, + g_hash_table_foreach(self->lock_bit_to_checked_keys, + synchronize_lock_states_loop_body, &sync_pressed_state_context); // Construct the real event @@ -628,7 +625,7 @@ static void fl_key_embedder_responder_handle_event( } } update_pressing_state(self, physical_key, is_down_event ? logical_key : 0); - possibly_update_lock_mode_bit(self, physical_key, is_down_event); + possibly_update_lock_bit(self, physical_key, is_down_event); // Update pressing states g_hash_table_foreach(self->modifier_bit_to_checked_keys, diff --git a/shell/platform/linux/fl_key_embedder_responder_private.h b/shell/platform/linux/fl_key_embedder_responder_private.h index 82ba769f6f9a5..daa3611990775 100644 --- a/shell/platform/linux/fl_key_embedder_responder_private.h +++ b/shell/platform/linux/fl_key_embedder_responder_private.h @@ -12,10 +12,34 @@ #include "flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_value.h" +/** + * FlKeyEmbedderCheckedKey: + * + * The information for a key that #FlKeyEmbedderResponder should keep state + * synchronous on. For every record of #FlKeyEmbedderCheckedKey, the responder + * will check the #GdkEvent::state and the internal state, and synchronize + * events if they don't match. + * + * #FlKeyEmbedderCheckedKey can synchronize pressing states (such as + * whether ControlLeft is pressed) or lock states (such as whether CapsLock + * is enabled). + * + * #FlKeyEmbedderCheckedKey has a "primary key". For pressing states, the + * primary key is the left of the modifiers. For lock states, the primary + * key is the key. + * + * #FlKeyEmbedderCheckedKey may also have a "secondary key". It is only + * available to pressing states, which is the right of the modifiers. + */ typedef struct { - size_t length; - uint64_t* physical_keys; - uint64_t first_logical_key; + // The logical key for the primary key. + uint64_t primary_logical_key; + // The physical key for the primary key. + uint64_t primary_physical_key; + // The physical key for the secondary key. + uint64_t secondary_physical_key; + // Whether this key is CapsLock. CapsLock uses a different event model in GDK + // and needs special treatment. bool is_caps_lock; } FlKeyEmbedderCheckedKey; diff --git a/shell/platform/linux/key_mapping.cc b/shell/platform/linux/key_mapping.cc index b01709a0db871..f1f01edfadd5d 100644 --- a/shell/platform/linux/key_mapping.cc +++ b/shell/platform/linux/key_mapping.cc @@ -26,36 +26,7 @@ static bool insert_record(GHashTable* table, guint64 xkb, guint64 fl_key) { } void initialize_xkb_to_physical_key(GHashTable* table) { - insert_record(table, 0x00000281, 0x00000017); // privacyScreenToggle - insert_record(table, 0x00000096, 0x00010082); // sleep - insert_record(table, 0x00000097, 0x00010083); // wakeUp - insert_record(table, 0x000000eb, 0x000100b5); // displayToggleIntExt - insert_record(table, 0x00000026, 0x00070004); // keyA - insert_record(table, 0x00000038, 0x00070005); // keyB - insert_record(table, 0x00000036, 0x00070006); // keyC - insert_record(table, 0x00000028, 0x00070007); // keyD - insert_record(table, 0x0000001a, 0x00070008); // keyE - insert_record(table, 0x00000029, 0x00070009); // keyF - insert_record(table, 0x0000002a, 0x0007000a); // keyG - insert_record(table, 0x0000002b, 0x0007000b); // keyH - insert_record(table, 0x0000001f, 0x0007000c); // keyI - insert_record(table, 0x0000002c, 0x0007000d); // keyJ - insert_record(table, 0x0000002d, 0x0007000e); // keyK - insert_record(table, 0x0000002e, 0x0007000f); // keyL - insert_record(table, 0x0000003a, 0x00070010); // keyM - insert_record(table, 0x00000039, 0x00070011); // keyN - insert_record(table, 0x00000020, 0x00070012); // keyO - insert_record(table, 0x00000021, 0x00070013); // keyP - insert_record(table, 0x00000018, 0x00070014); // keyQ - insert_record(table, 0x0000001b, 0x00070015); // keyR - insert_record(table, 0x00000027, 0x00070016); // keyS - insert_record(table, 0x0000001c, 0x00070017); // keyT - insert_record(table, 0x0000001e, 0x00070018); // keyU - insert_record(table, 0x00000037, 0x00070019); // keyV - insert_record(table, 0x00000019, 0x0007001a); // keyW - insert_record(table, 0x00000035, 0x0007001b); // keyX - insert_record(table, 0x0000001d, 0x0007001c); // keyY - insert_record(table, 0x00000034, 0x0007001d); // keyZ + insert_record(table, 0x00000009, 0x00070029); // escape insert_record(table, 0x0000000a, 0x0007001e); // digit1 insert_record(table, 0x0000000b, 0x0007001f); // digit2 insert_record(table, 0x0000000c, 0x00070020); // digit3 @@ -66,22 +37,52 @@ void initialize_xkb_to_physical_key(GHashTable* table) { insert_record(table, 0x00000011, 0x00070025); // digit8 insert_record(table, 0x00000012, 0x00070026); // digit9 insert_record(table, 0x00000013, 0x00070027); // digit0 - insert_record(table, 0x00000024, 0x00070028); // enter - insert_record(table, 0x00000009, 0x00070029); // escape - insert_record(table, 0x00000016, 0x0007002a); // backspace - insert_record(table, 0x00000017, 0x0007002b); // tab - insert_record(table, 0x00000041, 0x0007002c); // space insert_record(table, 0x00000014, 0x0007002d); // minus insert_record(table, 0x00000015, 0x0007002e); // equal + insert_record(table, 0x00000016, 0x0007002a); // backspace + insert_record(table, 0x00000017, 0x0007002b); // tab + insert_record(table, 0x00000018, 0x00070014); // keyQ + insert_record(table, 0x00000019, 0x0007001a); // keyW + insert_record(table, 0x0000001a, 0x00070008); // keyE + insert_record(table, 0x0000001b, 0x00070015); // keyR + insert_record(table, 0x0000001c, 0x00070017); // keyT + insert_record(table, 0x0000001d, 0x0007001c); // keyY + insert_record(table, 0x0000001e, 0x00070018); // keyU + insert_record(table, 0x0000001f, 0x0007000c); // keyI + insert_record(table, 0x00000020, 0x00070012); // keyO + insert_record(table, 0x00000021, 0x00070013); // keyP insert_record(table, 0x00000022, 0x0007002f); // bracketLeft insert_record(table, 0x00000023, 0x00070030); // bracketRight - insert_record(table, 0x00000033, 0x00070031); // backslash + insert_record(table, 0x00000024, 0x00070028); // enter + insert_record(table, 0x00000025, 0x000700e0); // controlLeft + insert_record(table, 0x00000026, 0x00070004); // keyA + insert_record(table, 0x00000027, 0x00070016); // keyS + insert_record(table, 0x00000028, 0x00070007); // keyD + insert_record(table, 0x00000029, 0x00070009); // keyF + insert_record(table, 0x0000002a, 0x0007000a); // keyG + insert_record(table, 0x0000002b, 0x0007000b); // keyH + insert_record(table, 0x0000002c, 0x0007000d); // keyJ + insert_record(table, 0x0000002d, 0x0007000e); // keyK + insert_record(table, 0x0000002e, 0x0007000f); // keyL insert_record(table, 0x0000002f, 0x00070033); // semicolon insert_record(table, 0x00000030, 0x00070034); // quote insert_record(table, 0x00000031, 0x00070035); // backquote + insert_record(table, 0x00000032, 0x000700e1); // shiftLeft + insert_record(table, 0x00000033, 0x00070031); // backslash + insert_record(table, 0x00000034, 0x0007001d); // keyZ + insert_record(table, 0x00000035, 0x0007001b); // keyX + insert_record(table, 0x00000036, 0x00070006); // keyC + insert_record(table, 0x00000037, 0x00070019); // keyV + insert_record(table, 0x00000038, 0x00070005); // keyB + insert_record(table, 0x00000039, 0x00070011); // keyN + insert_record(table, 0x0000003a, 0x00070010); // keyM insert_record(table, 0x0000003b, 0x00070036); // comma insert_record(table, 0x0000003c, 0x00070037); // period insert_record(table, 0x0000003d, 0x00070038); // slash + insert_record(table, 0x0000003e, 0x000700e5); // shiftRight + insert_record(table, 0x0000003f, 0x00070055); // numpadMultiply + insert_record(table, 0x00000040, 0x000700e2); // altLeft + insert_record(table, 0x00000041, 0x0007002c); // space insert_record(table, 0x00000042, 0x00070039); // capsLock insert_record(table, 0x00000043, 0x0007003a); // f1 insert_record(table, 0x00000044, 0x0007003b); // f2 @@ -93,42 +94,97 @@ void initialize_xkb_to_physical_key(GHashTable* table) { insert_record(table, 0x0000004a, 0x00070041); // f8 insert_record(table, 0x0000004b, 0x00070042); // f9 insert_record(table, 0x0000004c, 0x00070043); // f10 - insert_record(table, 0x0000005f, 0x00070044); // f11 - insert_record(table, 0x00000060, 0x00070045); // f12 - insert_record(table, 0x0000006b, 0x00070046); // printScreen - insert_record(table, 0x0000004e, 0x00070047); // scrollLock - insert_record(table, 0x0000007f, 0x00070048); // pause - insert_record(table, 0x00000076, 0x00070049); // insert - insert_record(table, 0x0000006e, 0x0007004a); // home - insert_record(table, 0x00000070, 0x0007004b); // pageUp - insert_record(table, 0x00000077, 0x0007004c); // delete - insert_record(table, 0x00000073, 0x0007004d); // end - insert_record(table, 0x00000075, 0x0007004e); // pageDown - insert_record(table, 0x00000072, 0x0007004f); // arrowRight - insert_record(table, 0x00000071, 0x00070050); // arrowLeft - insert_record(table, 0x00000074, 0x00070051); // arrowDown - insert_record(table, 0x0000006f, 0x00070052); // arrowUp insert_record(table, 0x0000004d, 0x00070053); // numLock - insert_record(table, 0x0000006a, 0x00070054); // numpadDivide - insert_record(table, 0x0000003f, 0x00070055); // numpadMultiply + insert_record(table, 0x0000004e, 0x00070047); // scrollLock + insert_record(table, 0x0000004f, 0x0007005f); // numpad7 + insert_record(table, 0x00000050, 0x00070060); // numpad8 + insert_record(table, 0x00000051, 0x00070061); // numpad9 insert_record(table, 0x00000052, 0x00070056); // numpadSubtract + insert_record(table, 0x00000053, 0x0007005c); // numpad4 + insert_record(table, 0x00000054, 0x0007005d); // numpad5 + insert_record(table, 0x00000055, 0x0007005e); // numpad6 insert_record(table, 0x00000056, 0x00070057); // numpadAdd - insert_record(table, 0x00000068, 0x00070058); // numpadEnter insert_record(table, 0x00000057, 0x00070059); // numpad1 insert_record(table, 0x00000058, 0x0007005a); // numpad2 insert_record(table, 0x00000059, 0x0007005b); // numpad3 - insert_record(table, 0x00000053, 0x0007005c); // numpad4 - insert_record(table, 0x00000054, 0x0007005d); // numpad5 - insert_record(table, 0x00000055, 0x0007005e); // numpad6 - insert_record(table, 0x0000004f, 0x0007005f); // numpad7 - insert_record(table, 0x00000050, 0x00070060); // numpad8 - insert_record(table, 0x00000051, 0x00070061); // numpad9 insert_record(table, 0x0000005a, 0x00070062); // numpad0 insert_record(table, 0x0000005b, 0x00070063); // numpadDecimal + insert_record(table, 0x0000005d, 0x00070094); // lang5 insert_record(table, 0x0000005e, 0x00070064); // intlBackslash - insert_record(table, 0x00000087, 0x00070065); // contextMenu + insert_record(table, 0x0000005f, 0x00070044); // f11 + insert_record(table, 0x00000060, 0x00070045); // f12 + insert_record(table, 0x00000061, 0x00070087); // intlRo + insert_record(table, 0x00000062, 0x00070092); // lang3 + insert_record(table, 0x00000063, 0x00070093); // lang4 + insert_record(table, 0x00000064, 0x0007008a); // convert + insert_record(table, 0x00000065, 0x00070088); // kanaMode + insert_record(table, 0x00000066, 0x0007008b); // nonConvert + insert_record(table, 0x00000068, 0x00070058); // numpadEnter + insert_record(table, 0x00000069, 0x000700e4); // controlRight + insert_record(table, 0x0000006a, 0x00070054); // numpadDivide + insert_record(table, 0x0000006b, 0x00070046); // printScreen + insert_record(table, 0x0000006c, 0x000700e6); // altRight + insert_record(table, 0x0000006e, 0x0007004a); // home + insert_record(table, 0x0000006f, 0x00070052); // arrowUp + insert_record(table, 0x00000070, 0x0007004b); // pageUp + insert_record(table, 0x00000071, 0x00070050); // arrowLeft + insert_record(table, 0x00000072, 0x0007004f); // arrowRight + insert_record(table, 0x00000073, 0x0007004d); // end + insert_record(table, 0x00000074, 0x00070051); // arrowDown + insert_record(table, 0x00000075, 0x0007004e); // pageDown + insert_record(table, 0x00000076, 0x00070049); // insert + insert_record(table, 0x00000077, 0x0007004c); // delete + insert_record(table, 0x00000079, 0x0007007f); // audioVolumeMute + insert_record(table, 0x0000007a, 0x00070081); // audioVolumeDown + insert_record(table, 0x0000007b, 0x00070080); // audioVolumeUp insert_record(table, 0x0000007c, 0x00070066); // power insert_record(table, 0x0000007d, 0x00070067); // numpadEqual + insert_record(table, 0x0000007e, 0x000700d7); // numpadSignChange + insert_record(table, 0x0000007f, 0x00070048); // pause + insert_record(table, 0x00000080, 0x000c029f); // showAllWindows + insert_record(table, 0x00000081, 0x00070085); // numpadComma + insert_record(table, 0x00000082, 0x00070090); // lang1 + insert_record(table, 0x00000083, 0x00070091); // lang2 + insert_record(table, 0x00000084, 0x00070089); // intlYen + insert_record(table, 0x00000085, 0x000700e3); // metaLeft + insert_record(table, 0x00000086, 0x000700e7); // metaRight + insert_record(table, 0x00000087, 0x00070065); // contextMenu + insert_record(table, 0x00000088, 0x000c0226); // browserStop + insert_record(table, 0x00000089, 0x00070079); // again + insert_record(table, 0x0000008b, 0x0007007a); // undo + insert_record(table, 0x0000008c, 0x00070077); // select + insert_record(table, 0x0000008d, 0x0007007c); // copy + insert_record(table, 0x0000008e, 0x00070074); // open + insert_record(table, 0x0000008f, 0x0007007d); // paste + insert_record(table, 0x00000090, 0x0007007e); // find + insert_record(table, 0x00000091, 0x0007007b); // cut + insert_record(table, 0x00000092, 0x00070075); // help + insert_record(table, 0x00000094, 0x000c0192); // launchApp2 + insert_record(table, 0x00000096, 0x00010082); // sleep + insert_record(table, 0x00000097, 0x00010083); // wakeUp + insert_record(table, 0x00000098, 0x000c0194); // launchApp1 + insert_record(table, 0x0000009e, 0x000c0196); // launchInternetBrowser + insert_record(table, 0x000000a0, 0x000c019e); // lockScreen + insert_record(table, 0x000000a3, 0x000c018a); // launchMail + insert_record(table, 0x000000a4, 0x000c022a); // browserFavorites + insert_record(table, 0x000000a6, 0x000c0224); // browserBack + insert_record(table, 0x000000a7, 0x000c0225); // browserForward + insert_record(table, 0x000000a9, 0x000c00b8); // eject + insert_record(table, 0x000000ab, 0x000c00b5); // mediaTrackNext + insert_record(table, 0x000000ac, 0x000c00cd); // mediaPlayPause + insert_record(table, 0x000000ad, 0x000c00b6); // mediaTrackPrevious + insert_record(table, 0x000000ae, 0x000c00b7); // mediaStop + insert_record(table, 0x000000af, 0x000c00b2); // mediaRecord + insert_record(table, 0x000000b0, 0x000c00b4); // mediaRewind + insert_record(table, 0x000000b1, 0x000c008c); // launchPhone + insert_record(table, 0x000000b3, 0x000c0183); // mediaSelect + insert_record(table, 0x000000b4, 0x000c0223); // browserHome + insert_record(table, 0x000000b5, 0x000c0227); // browserRefresh + insert_record(table, 0x000000b6, 0x000c0094); // exit + insert_record(table, 0x000000bb, 0x000700b6); // numpadParenLeft + insert_record(table, 0x000000bc, 0x000700b7); // numpadParenRight + insert_record(table, 0x000000bd, 0x000c0201); // newKey + insert_record(table, 0x000000be, 0x000c0279); // redo insert_record(table, 0x000000bf, 0x00070068); // f13 insert_record(table, 0x000000c0, 0x00070069); // f14 insert_record(table, 0x000000c1, 0x0007006a); // f15 @@ -141,282 +197,225 @@ void initialize_xkb_to_physical_key(GHashTable* table) { insert_record(table, 0x000000c8, 0x00070071); // f22 insert_record(table, 0x000000c9, 0x00070072); // f23 insert_record(table, 0x000000ca, 0x00070073); // f24 - insert_record(table, 0x0000008e, 0x00070074); // open - insert_record(table, 0x00000092, 0x00070075); // help - insert_record(table, 0x0000008c, 0x00070077); // select - insert_record(table, 0x00000089, 0x00070079); // again - insert_record(table, 0x0000008b, 0x0007007a); // undo - insert_record(table, 0x00000091, 0x0007007b); // cut - insert_record(table, 0x0000008d, 0x0007007c); // copy - insert_record(table, 0x0000008f, 0x0007007d); // paste - insert_record(table, 0x00000090, 0x0007007e); // find - insert_record(table, 0x00000079, 0x0007007f); // audioVolumeMute - insert_record(table, 0x0000007b, 0x00070080); // audioVolumeUp - insert_record(table, 0x0000007a, 0x00070081); // audioVolumeDown - insert_record(table, 0x00000081, 0x00070085); // numpadComma - insert_record(table, 0x00000061, 0x00070087); // intlRo - insert_record(table, 0x00000065, 0x00070088); // kanaMode - insert_record(table, 0x00000084, 0x00070089); // intlYen - insert_record(table, 0x00000064, 0x0007008a); // convert - insert_record(table, 0x00000066, 0x0007008b); // nonConvert - insert_record(table, 0x00000082, 0x00070090); // lang1 - insert_record(table, 0x00000083, 0x00070091); // lang2 - insert_record(table, 0x00000062, 0x00070092); // lang3 - insert_record(table, 0x00000063, 0x00070093); // lang4 - insert_record(table, 0x0000005d, 0x00070094); // lang5 - insert_record(table, 0x000000bb, 0x000700b6); // numpadParenLeft - insert_record(table, 0x000000bc, 0x000700b7); // numpadParenRight - insert_record(table, 0x0000007e, 0x000700d7); // numpadSignChange - insert_record(table, 0x00000025, 0x000700e0); // controlLeft - insert_record(table, 0x00000032, 0x000700e1); // shiftLeft - insert_record(table, 0x00000040, 0x000700e2); // altLeft - insert_record(table, 0x00000085, 0x000700e3); // metaLeft - insert_record(table, 0x00000069, 0x000700e4); // controlRight - insert_record(table, 0x0000003e, 0x000700e5); // shiftRight - insert_record(table, 0x0000006c, 0x000700e6); // altRight - insert_record(table, 0x00000086, 0x000700e7); // metaRight - insert_record(table, 0x0000016e, 0x000c0060); // info - insert_record(table, 0x0000017a, 0x000c0061); // closedCaptionToggle - insert_record(table, 0x000000e9, 0x000c006f); // brightnessUp + insert_record(table, 0x000000d1, 0x000c00b1); // mediaPause + insert_record(table, 0x000000d6, 0x000c0203); // close + insert_record(table, 0x000000d7, 0x000c00b0); // mediaPlay + insert_record(table, 0x000000d8, 0x000c00b3); // mediaFastForward + insert_record(table, 0x000000d9, 0x000c00e5); // bassBoost + insert_record(table, 0x000000da, 0x000c0208); // print + insert_record(table, 0x000000e1, 0x000c0221); // browserSearch insert_record(table, 0x000000e8, 0x000c0070); // brightnessDown - insert_record(table, 0x000001b7, 0x000c0072); // brightnessToggle - insert_record(table, 0x00000258, 0x000c0073); // brightnessMinimum - insert_record(table, 0x00000259, 0x000c0074); // brightnessMaximum - insert_record(table, 0x000000fc, 0x000c0075); // brightnessAuto - insert_record(table, 0x000000ee, 0x000c0079); // kbdIllumUp + insert_record(table, 0x000000e9, 0x000c006f); // brightnessUp + insert_record(table, 0x000000eb, 0x000100b5); // displayToggleIntExt insert_record(table, 0x000000ed, 0x000c007a); // kbdIllumDown - insert_record(table, 0x0000019d, 0x000c0083); // mediaLast - insert_record(table, 0x000000b1, 0x000c008c); // launchPhone + insert_record(table, 0x000000ee, 0x000c0079); // kbdIllumUp + insert_record(table, 0x000000ef, 0x000c028c); // mailSend + insert_record(table, 0x000000f0, 0x000c0289); // mailReply + insert_record(table, 0x000000f1, 0x000c028b); // mailForward + insert_record(table, 0x000000f2, 0x000c0207); // save + insert_record(table, 0x000000f3, 0x000c01a7); // launchDocuments + insert_record(table, 0x000000fc, 0x000c0075); // brightnessAuto + insert_record(table, 0x0000016e, 0x000c0060); // info insert_record(table, 0x00000172, 0x000c008d); // programGuide - insert_record(table, 0x000000b6, 0x000c0094); // exit + insert_record(table, 0x0000017a, 0x000c0061); // closedCaptionToggle + insert_record(table, 0x0000017c, 0x000c0232); // zoomToggle + insert_record(table, 0x0000017e, 0x000c01ae); // launchKeyboardLayout + insert_record(table, 0x00000190, 0x000c01b7); // launchAudioBrowser + insert_record(table, 0x00000195, 0x000c018e); // launchCalendar + insert_record(table, 0x0000019d, 0x000c0083); // mediaLast insert_record(table, 0x000001a2, 0x000c009c); // channelUp insert_record(table, 0x000001a3, 0x000c009d); // channelDown - insert_record(table, 0x000000d7, 0x000c00b0); // mediaPlay - insert_record(table, 0x000000d1, 0x000c00b1); // mediaPause - insert_record(table, 0x000000af, 0x000c00b2); // mediaRecord - insert_record(table, 0x000000d8, 0x000c00b3); // mediaFastForward - insert_record(table, 0x000000b0, 0x000c00b4); // mediaRewind - insert_record(table, 0x000000ab, 0x000c00b5); // mediaTrackNext - insert_record(table, 0x000000ad, 0x000c00b6); // mediaTrackPrevious - insert_record(table, 0x000000ae, 0x000c00b7); // mediaStop - insert_record(table, 0x000000a9, 0x000c00b8); // eject - insert_record(table, 0x000000ac, 0x000c00cd); // mediaPlayPause - insert_record(table, 0x0000024e, 0x000c00cf); // speechInputToggle - insert_record(table, 0x000000d9, 0x000c00e5); // bassBoost - insert_record(table, 0x000000b3, 0x000c0183); // mediaSelect + insert_record(table, 0x000001aa, 0x000c022d); // zoomIn + insert_record(table, 0x000001ab, 0x000c022e); // zoomOut insert_record(table, 0x000001ad, 0x000c0184); // launchWordProcessor insert_record(table, 0x000001af, 0x000c0186); // launchSpreadsheet - insert_record(table, 0x000000a3, 0x000c018a); // launchMail insert_record(table, 0x000001b5, 0x000c018d); // launchContacts - insert_record(table, 0x00000195, 0x000c018e); // launchCalendar - insert_record(table, 0x00000094, 0x000c0192); // launchApp2 - insert_record(table, 0x00000098, 0x000c0194); // launchApp1 - insert_record(table, 0x0000009e, 0x000c0196); // launchInternetBrowser + insert_record(table, 0x000001b7, 0x000c0072); // brightnessToggle + insert_record(table, 0x000001b8, 0x000c01ab); // spellCheck insert_record(table, 0x000001b9, 0x000c019c); // logOff - insert_record(table, 0x000000a0, 0x000c019e); // lockScreen insert_record(table, 0x0000024b, 0x000c019f); // launchControlPanel insert_record(table, 0x0000024c, 0x000c01a2); // selectTask - insert_record(table, 0x000000f3, 0x000c01a7); // launchDocuments - insert_record(table, 0x000001b8, 0x000c01ab); // spellCheck - insert_record(table, 0x0000017e, 0x000c01ae); // launchKeyboardLayout insert_record(table, 0x0000024d, 0x000c01b1); // launchScreenSaver + insert_record(table, 0x0000024e, 0x000c00cf); // speechInputToggle insert_record(table, 0x0000024f, 0x000c01cb); // launchAssistant - insert_record(table, 0x00000190, 0x000c01b7); // launchAudioBrowser - insert_record(table, 0x000000bd, 0x000c0201); // newKey - insert_record(table, 0x000000d6, 0x000c0203); // close - insert_record(table, 0x000000f2, 0x000c0207); // save - insert_record(table, 0x000000da, 0x000c0208); // print - insert_record(table, 0x000000e1, 0x000c0221); // browserSearch - insert_record(table, 0x000000b4, 0x000c0223); // browserHome - insert_record(table, 0x000000a6, 0x000c0224); // browserBack - insert_record(table, 0x000000a7, 0x000c0225); // browserForward - insert_record(table, 0x00000088, 0x000c0226); // browserStop - insert_record(table, 0x000000b5, 0x000c0227); // browserRefresh - insert_record(table, 0x000000a4, 0x000c022a); // browserFavorites - insert_record(table, 0x000001aa, 0x000c022d); // zoomIn - insert_record(table, 0x000001ab, 0x000c022e); // zoomOut - insert_record(table, 0x0000017c, 0x000c0232); // zoomToggle - insert_record(table, 0x000000be, 0x000c0279); // redo - insert_record(table, 0x000000f0, 0x000c0289); // mailReply - insert_record(table, 0x000000f1, 0x000c028b); // mailForward - insert_record(table, 0x000000ef, 0x000c028c); // mailSend insert_record(table, 0x00000250, 0x000c029d); // keyboardLayoutSelect - insert_record(table, 0x00000080, 0x000c029f); // showAllWindows + insert_record(table, 0x00000258, 0x000c0073); // brightnessMinimum + insert_record(table, 0x00000259, 0x000c0074); // brightnessMaximum + insert_record(table, 0x00000281, 0x00000017); // privacyScreenToggle } void initialize_gtk_keyval_to_logical_key(GHashTable* table) { - insert_record(table, 0x0000ff08, 0x000000008); // BackSpace - insert_record(table, 0x0000ff09, 0x000000009); // Tab - insert_record(table, 0x0000ff89, 0x000000009); // KP_Tab - insert_record(table, 0x0000fe20, 0x000000009); // ISO_Left_Tab - insert_record(table, 0x0000ff0d, 0x00000000d); // Return - insert_record(table, 0x0000fe34, 0x00000000d); // ISO_Enter - insert_record(table, 0x0000fd1e, 0x00000000d); // 3270_Enter - insert_record(table, 0x0000ff1b, 0x00000001b); // Escape - insert_record(table, 0x0000ff80, 0x000000020); // KP_Space - insert_record(table, 0x0000ffae, 0x00000002e); // KP_Decimal - insert_record(table, 0x0000ffff, 0x00000007f); // Delete - insert_record(table, 0x0000ffe5, 0x000000104); // Caps_Lock - insert_record(table, 0x0000ffed, 0x000000108); // Hyper_L - insert_record(table, 0x0000ffee, 0x000000108); // Hyper_R - insert_record(table, 0x0000ff7f, 0x00000010a); // Num_Lock - insert_record(table, 0x0000ff14, 0x00000010c); // Scroll_Lock - insert_record(table, 0x0000ffeb, 0x00000010e); // Super_L - insert_record(table, 0x0000ffec, 0x00000010e); // Super_R - insert_record(table, 0x0000ff54, 0x000000301); // Down - insert_record(table, 0x0000ff51, 0x000000302); // Left - insert_record(table, 0x0000ff53, 0x000000303); // Right - insert_record(table, 0x0000ff52, 0x000000304); // Up - insert_record(table, 0x0000ff57, 0x000000305); // End - insert_record(table, 0x0000ff50, 0x000000306); // Home - insert_record(table, 0x0000ff56, 0x000000307); // Page_Down - insert_record(table, 0x0000ff55, 0x000000308); // Page_Up - insert_record(table, 0x0000ff0b, 0x000000401); // Clear - insert_record(table, 0x0000fd15, 0x000000402); // 3270_Copy - insert_record(table, 0x1008ff57, 0x000000402); // Copy - insert_record(table, 0x1008ff58, 0x000000404); // Cut - insert_record(table, 0x0000fd06, 0x000000405); // 3270_EraseEOF - insert_record(table, 0x0000fd1b, 0x000000406); // 3270_ExSelect - insert_record(table, 0x0000ff63, 0x000000407); // Insert - insert_record(table, 0x1008ff6d, 0x000000408); // Paste - insert_record(table, 0x0000ff66, 0x000000409); // Redo - insert_record(table, 0x0000ff65, 0x00000040a); // Undo - insert_record(table, 0x0000fd0e, 0x000000503); // 3270_Attn - insert_record(table, 0x0000ff69, 0x000000504); // Cancel - insert_record(table, 0x0000ff67, 0x000000505); // Menu - insert_record(table, 0x0000ff62, 0x000000506); // Execute - insert_record(table, 0x0000ff68, 0x000000507); // Find - insert_record(table, 0x0000ff6a, 0x000000508); // Help - insert_record(table, 0x0000ff13, 0x000000509); // Pause - insert_record(table, 0x0000ff60, 0x00000050c); // Select - insert_record(table, 0x1008ff8b, 0x00000050d); // ZoomIn - insert_record(table, 0x1008ff8c, 0x00000050e); // ZoomOut - insert_record(table, 0x1008ff03, 0x000000601); // MonBrightnessDown - insert_record(table, 0x1008ff02, 0x000000602); // MonBrightnessUp - insert_record(table, 0x1008ff2c, 0x000000604); // Eject - insert_record(table, 0x1008ff61, 0x000000605); // LogOff - insert_record(table, 0x1008ff2a, 0x000000607); // PowerOff - insert_record(table, 0x0000fd1d, 0x000000608); // 3270_PrintScreen - insert_record(table, 0x1008ff10, 0x00000060a); // Standby - insert_record(table, 0x1008ff2b, 0x00000060b); // WakeUp - insert_record(table, 0x0000ff37, 0x000000703); // Codeinput - insert_record(table, 0x0000fe0c, 0x000000707); // ISO_First_Group - insert_record(table, 0x0000fe0e, 0x000000708); // ISO_Last_Group - insert_record(table, 0x0000fe08, 0x000000709); // ISO_Next_Group - insert_record(table, 0x0000fe0a, 0x00000070a); // ISO_Prev_Group - insert_record(table, 0x0000ff7e, 0x00000070b); // Mode_switch - insert_record(table, 0x0000ff3e, 0x00000070e); // PreviousCandidate - insert_record(table, 0x0000ff3c, 0x000000710); // SingleCandidate - insert_record(table, 0x0000ff31, 0x000000711); // Hangul - insert_record(table, 0x0000ff34, 0x000000712); // Hangul_Hanja - insert_record(table, 0x0000ff2f, 0x000000714); // Eisu_Shift - insert_record(table, 0x0000ff29, 0x000000715); // Hankaku - insert_record(table, 0x0000ff25, 0x000000716); // Hiragana - insert_record(table, 0x0000ff27, 0x000000717); // Hiragana_Katakana - insert_record(table, 0x0000ff7e, 0x000000718); // kana_switch - insert_record(table, 0x0000ff21, 0x000000719); // Kanji - insert_record(table, 0x0000ff26, 0x00000071a); // Katakana - insert_record(table, 0x0000ff24, 0x00000071b); // Romaji - insert_record(table, 0x0000ff28, 0x00000071c); // Zenkaku - insert_record(table, 0x0000ff2a, 0x00000071d); // Zenkaku_Hankaku - insert_record(table, 0x0000ff91, 0x000000801); // KP_F1 - insert_record(table, 0x0000ffbe, 0x000000801); // F1 - insert_record(table, 0x0000ff92, 0x000000802); // KP_F2 - insert_record(table, 0x0000ffbf, 0x000000802); // F2 - insert_record(table, 0x0000ff93, 0x000000803); // KP_F3 - insert_record(table, 0x0000ffc0, 0x000000803); // F3 - insert_record(table, 0x0000ff94, 0x000000804); // KP_F4 - insert_record(table, 0x0000ffc1, 0x000000804); // F4 - insert_record(table, 0x0000ffc2, 0x000000805); // F5 - insert_record(table, 0x0000ffc3, 0x000000806); // F6 - insert_record(table, 0x0000ffc4, 0x000000807); // F7 - insert_record(table, 0x0000ffc5, 0x000000808); // F8 - insert_record(table, 0x0000ffc6, 0x000000809); // F9 - insert_record(table, 0x0000ffc7, 0x00000080a); // F10 - insert_record(table, 0x0000ffc8, 0x00000080b); // F11 - insert_record(table, 0x0000ffc9, 0x00000080c); // F12 - insert_record(table, 0x0000ffca, 0x00000080d); // F13 - insert_record(table, 0x0000ffcb, 0x00000080e); // F14 - insert_record(table, 0x0000ffcc, 0x00000080f); // F15 - insert_record(table, 0x0000ffcd, 0x000000810); // F16 - insert_record(table, 0x0000ffce, 0x000000811); // F17 - insert_record(table, 0x0000ffcf, 0x000000812); // F18 - insert_record(table, 0x0000ffd0, 0x000000813); // F19 - insert_record(table, 0x0000ffd1, 0x000000814); // F20 - insert_record(table, 0x0000ffd2, 0x000000815); // F21 - insert_record(table, 0x0000ffd3, 0x000000816); // F22 - insert_record(table, 0x0000ffd4, 0x000000817); // F23 - insert_record(table, 0x0000ffd5, 0x000000818); // F24 - insert_record(table, 0x1008ff56, 0x000000a01); // Close - insert_record(table, 0x1008ff90, 0x000000a02); // MailForward - insert_record(table, 0x1008ff72, 0x000000a03); // Reply - insert_record(table, 0x1008ff7b, 0x000000a04); // Send - insert_record(table, 0x1008ff15, 0x000000a07); // AudioStop - insert_record(table, 0x1008ff17, 0x000000a08); // AudioNext - insert_record(table, 0x1008ff16, 0x000000a09); // AudioPrev - insert_record(table, 0x1008ff68, 0x000000a0a); // New - insert_record(table, 0x1008ff6b, 0x000000a0b); // Open - insert_record(table, 0x0000ff61, 0x000000a0c); // Print - insert_record(table, 0x1008ff77, 0x000000a0d); // Save - insert_record(table, 0x1008ff7c, 0x000000a0e); // Spell - insert_record(table, 0x1008ff11, 0x000000a0f); // AudioLowerVolume - insert_record(table, 0x1008ff13, 0x000000a10); // AudioRaiseVolume - insert_record(table, 0x1008ff12, 0x000000a11); // AudioMute - insert_record(table, 0x1008ff20, 0x000000b02); // Calendar - insert_record(table, 0x1008ff19, 0x000000b03); // Mail - insert_record(table, 0x1008ff2d, 0x000000b07); // ScreenSaver - insert_record(table, 0x1008ff6e, 0x000000b0d); // Phone - insert_record(table, 0x1008ff26, 0x000000c01); // Back - insert_record(table, 0x1008ff30, 0x000000c02); // Favorites - insert_record(table, 0x1008ff27, 0x000000c03); // Forward - insert_record(table, 0x1008ff18, 0x000000c04); // HomePage - insert_record(table, 0x1008ff29, 0x000000c05); // Refresh - insert_record(table, 0x1008ff1b, 0x000000c06); // Search - insert_record(table, 0x1008ff28, 0x000000c07); // Stop - insert_record(table, 0x1008ff97, 0x000000d2c); // AudioForward - insert_record(table, 0x1008ff31, 0x000000d2e); // AudioPause - insert_record(table, 0x0000fd16, 0x000000d2f); // 3270_Play - insert_record(table, 0x1008ff14, 0x000000d2f); // AudioPlay - insert_record(table, 0x1008ff1c, 0x000000d30); // AudioRecord - insert_record(table, 0x1008ff3e, 0x000000d31); // AudioRewind - insert_record(table, 0x1008ffa7, 0x100000014); // Suspend - insert_record(table, 0x1008ff2f, 0x100010082); // Sleep - insert_record(table, 0x000000a5, 0x100070089); // yen - insert_record(table, 0x0000ff8d, 0x20000000d); // KP_Enter - insert_record(table, 0x0000ffaa, 0x20000002a); // KP_Multiply - insert_record(table, 0x0000ffab, 0x20000002b); // KP_Add - insert_record(table, 0x0000ffad, 0x20000002d); // KP_Subtract - insert_record(table, 0x0000ff9f, 0x20000002e); // KP_Delete - insert_record(table, 0x0000ffaf, 0x20000002f); // KP_Divide - insert_record(table, 0x0000ff9e, 0x200000030); // KP_Insert - insert_record(table, 0x0000ffb0, 0x200000030); // KP_0 - insert_record(table, 0x0000ff9c, 0x200000031); // KP_End - insert_record(table, 0x0000ffb1, 0x200000031); // KP_1 - insert_record(table, 0x0000ff99, 0x200000032); // KP_Down - insert_record(table, 0x0000ffb2, 0x200000032); // KP_2 - insert_record(table, 0x0000ff9b, 0x200000033); // KP_Page_Down - insert_record(table, 0x0000ffb3, 0x200000033); // KP_3 - insert_record(table, 0x0000ff96, 0x200000034); // KP_Left - insert_record(table, 0x0000ffb4, 0x200000034); // KP_4 - insert_record(table, 0x0000ffb5, 0x200000035); // KP_5 - insert_record(table, 0x0000ff98, 0x200000036); // KP_Right - insert_record(table, 0x0000ffb6, 0x200000036); // KP_6 - insert_record(table, 0x0000ff95, 0x200000037); // KP_Home - insert_record(table, 0x0000ffb7, 0x200000037); // KP_7 - insert_record(table, 0x0000ff97, 0x200000038); // KP_Up - insert_record(table, 0x0000ffb8, 0x200000038); // KP_8 - insert_record(table, 0x0000ff9a, 0x200000039); // KP_Page_Up - insert_record(table, 0x0000ffb9, 0x200000039); // KP_9 - insert_record(table, 0x0000ffbd, 0x20000003d); // KP_Equal - insert_record(table, 0x0000ffe9, 0x300000102); // Alt_L - insert_record(table, 0x0000ffe3, 0x300000105); // Control_L - insert_record(table, 0x0000ffe7, 0x300000109); // Meta_L - insert_record(table, 0x0000ffe1, 0x30000010d); // Shift_L - insert_record(table, 0x0000ffea, 0x400000102); // Alt_R - insert_record(table, 0x0000fe03, 0x400000102); // ISO_Level3_Shift - insert_record(table, 0x0000ffe4, 0x400000105); // Control_R - insert_record(table, 0x0000ffe8, 0x400000109); // Meta_R - insert_record(table, 0x0000ffe2, 0x40000010d); // Shift_R + insert_record(table, 0x000000a5, 0x1100070089); // yen + insert_record(table, 0x0000fd06, 0x1000000405); // 3270_EraseEOF + insert_record(table, 0x0000fd0e, 0x1000000503); // 3270_Attn + insert_record(table, 0x0000fd15, 0x1000000402); // 3270_Copy + insert_record(table, 0x0000fd16, 0x1000000d2f); // 3270_Play + insert_record(table, 0x0000fd1b, 0x1000000406); // 3270_ExSelect + insert_record(table, 0x0000fd1d, 0x1000000608); // 3270_PrintScreen + insert_record(table, 0x0000fd1e, 0x100000000d); // 3270_Enter + insert_record(table, 0x0000fe03, 0x40000000102); // ISO_Level3_Shift + insert_record(table, 0x0000fe08, 0x1000000709); // ISO_Next_Group + insert_record(table, 0x0000fe0a, 0x100000070a); // ISO_Prev_Group + insert_record(table, 0x0000fe0c, 0x1000000707); // ISO_First_Group + insert_record(table, 0x0000fe0e, 0x1000000708); // ISO_Last_Group + insert_record(table, 0x0000fe20, 0x1000000009); // ISO_Left_Tab + insert_record(table, 0x0000fe34, 0x100000000d); // ISO_Enter + insert_record(table, 0x0000ff08, 0x1000000008); // BackSpace + insert_record(table, 0x0000ff09, 0x1000000009); // Tab + insert_record(table, 0x0000ff0b, 0x1000000401); // Clear + insert_record(table, 0x0000ff0d, 0x100000000d); // Return + insert_record(table, 0x0000ff13, 0x1000000509); // Pause + insert_record(table, 0x0000ff14, 0x100000010c); // Scroll_Lock + insert_record(table, 0x0000ff1b, 0x100000001b); // Escape + insert_record(table, 0x0000ff21, 0x1000000719); // Kanji + insert_record(table, 0x0000ff24, 0x100000071b); // Romaji + insert_record(table, 0x0000ff25, 0x1000000716); // Hiragana + insert_record(table, 0x0000ff26, 0x100000071a); // Katakana + insert_record(table, 0x0000ff27, 0x1000000717); // Hiragana_Katakana + insert_record(table, 0x0000ff28, 0x100000071c); // Zenkaku + insert_record(table, 0x0000ff29, 0x1000000715); // Hankaku + insert_record(table, 0x0000ff2a, 0x100000071d); // Zenkaku_Hankaku + insert_record(table, 0x0000ff2f, 0x1000000714); // Eisu_Shift + insert_record(table, 0x0000ff31, 0x1000000711); // Hangul + insert_record(table, 0x0000ff34, 0x1000000712); // Hangul_Hanja + insert_record(table, 0x0000ff37, 0x1000000703); // Codeinput + insert_record(table, 0x0000ff3c, 0x1000000710); // SingleCandidate + insert_record(table, 0x0000ff3e, 0x100000070e); // PreviousCandidate + insert_record(table, 0x0000ff50, 0x1000000306); // Home + insert_record(table, 0x0000ff51, 0x1000000302); // Left + insert_record(table, 0x0000ff52, 0x1000000304); // Up + insert_record(table, 0x0000ff53, 0x1000000303); // Right + insert_record(table, 0x0000ff54, 0x1000000301); // Down + insert_record(table, 0x0000ff55, 0x1000000308); // Page_Up + insert_record(table, 0x0000ff56, 0x1000000307); // Page_Down + insert_record(table, 0x0000ff57, 0x1000000305); // End + insert_record(table, 0x0000ff60, 0x100000050c); // Select + insert_record(table, 0x0000ff61, 0x1000000a0c); // Print + insert_record(table, 0x0000ff62, 0x1000000506); // Execute + insert_record(table, 0x0000ff63, 0x1000000407); // Insert + insert_record(table, 0x0000ff65, 0x100000040a); // Undo + insert_record(table, 0x0000ff66, 0x1000000409); // Redo + insert_record(table, 0x0000ff67, 0x1000000505); // Menu + insert_record(table, 0x0000ff68, 0x1000000507); // Find + insert_record(table, 0x0000ff69, 0x1000000504); // Cancel + insert_record(table, 0x0000ff6a, 0x1000000508); // Help + insert_record(table, 0x0000ff7e, 0x100000070b); // Mode_switch + insert_record(table, 0x0000ff7f, 0x100000010a); // Num_Lock + insert_record(table, 0x0000ff80, 0x0000000020); // KP_Space + insert_record(table, 0x0000ff89, 0x1000000009); // KP_Tab + insert_record(table, 0x0000ff8d, 0x5000000000d); // KP_Enter + insert_record(table, 0x0000ff91, 0x1000000801); // KP_F1 + insert_record(table, 0x0000ff92, 0x1000000802); // KP_F2 + insert_record(table, 0x0000ff93, 0x1000000803); // KP_F3 + insert_record(table, 0x0000ff94, 0x1000000804); // KP_F4 + insert_record(table, 0x0000ff95, 0x50000000037); // KP_Home + insert_record(table, 0x0000ff96, 0x50000000034); // KP_Left + insert_record(table, 0x0000ff97, 0x50000000038); // KP_Up + insert_record(table, 0x0000ff98, 0x50000000036); // KP_Right + insert_record(table, 0x0000ff99, 0x50000000032); // KP_Down + insert_record(table, 0x0000ff9a, 0x50000000039); // KP_Page_Up + insert_record(table, 0x0000ff9b, 0x50000000033); // KP_Page_Down + insert_record(table, 0x0000ff9c, 0x50000000031); // KP_End + insert_record(table, 0x0000ff9e, 0x50000000030); // KP_Insert + insert_record(table, 0x0000ff9f, 0x5000000002e); // KP_Delete + insert_record(table, 0x0000ffaa, 0x5000000002a); // KP_Multiply + insert_record(table, 0x0000ffab, 0x5000000002b); // KP_Add + insert_record(table, 0x0000ffad, 0x5000000002d); // KP_Subtract + insert_record(table, 0x0000ffae, 0x000000002e); // KP_Decimal + insert_record(table, 0x0000ffaf, 0x5000000002f); // KP_Divide + insert_record(table, 0x0000ffb0, 0x50000000030); // KP_0 + insert_record(table, 0x0000ffb1, 0x50000000031); // KP_1 + insert_record(table, 0x0000ffb2, 0x50000000032); // KP_2 + insert_record(table, 0x0000ffb3, 0x50000000033); // KP_3 + insert_record(table, 0x0000ffb4, 0x50000000034); // KP_4 + insert_record(table, 0x0000ffb5, 0x50000000035); // KP_5 + insert_record(table, 0x0000ffb6, 0x50000000036); // KP_6 + insert_record(table, 0x0000ffb7, 0x50000000037); // KP_7 + insert_record(table, 0x0000ffb8, 0x50000000038); // KP_8 + insert_record(table, 0x0000ffb9, 0x50000000039); // KP_9 + insert_record(table, 0x0000ffbd, 0x5000000003d); // KP_Equal + insert_record(table, 0x0000ffbe, 0x1000000801); // F1 + insert_record(table, 0x0000ffbf, 0x1000000802); // F2 + insert_record(table, 0x0000ffc0, 0x1000000803); // F3 + insert_record(table, 0x0000ffc1, 0x1000000804); // F4 + insert_record(table, 0x0000ffc2, 0x1000000805); // F5 + insert_record(table, 0x0000ffc3, 0x1000000806); // F6 + insert_record(table, 0x0000ffc4, 0x1000000807); // F7 + insert_record(table, 0x0000ffc5, 0x1000000808); // F8 + insert_record(table, 0x0000ffc6, 0x1000000809); // F9 + insert_record(table, 0x0000ffc7, 0x100000080a); // F10 + insert_record(table, 0x0000ffc8, 0x100000080b); // F11 + insert_record(table, 0x0000ffc9, 0x100000080c); // F12 + insert_record(table, 0x0000ffca, 0x100000080d); // F13 + insert_record(table, 0x0000ffcb, 0x100000080e); // F14 + insert_record(table, 0x0000ffcc, 0x100000080f); // F15 + insert_record(table, 0x0000ffcd, 0x1000000810); // F16 + insert_record(table, 0x0000ffce, 0x1000000811); // F17 + insert_record(table, 0x0000ffcf, 0x1000000812); // F18 + insert_record(table, 0x0000ffd0, 0x1000000813); // F19 + insert_record(table, 0x0000ffd1, 0x1000000814); // F20 + insert_record(table, 0x0000ffd2, 0x1000000815); // F21 + insert_record(table, 0x0000ffd3, 0x1000000816); // F22 + insert_record(table, 0x0000ffd4, 0x1000000817); // F23 + insert_record(table, 0x0000ffd5, 0x1000000818); // F24 + insert_record(table, 0x0000ffe1, 0x3000000010d); // Shift_L + insert_record(table, 0x0000ffe2, 0x4000000010d); // Shift_R + insert_record(table, 0x0000ffe3, 0x30000000105); // Control_L + insert_record(table, 0x0000ffe4, 0x40000000105); // Control_R + insert_record(table, 0x0000ffe5, 0x1000000104); // Caps_Lock + insert_record(table, 0x0000ffe7, 0x30000000109); // Meta_L + insert_record(table, 0x0000ffe8, 0x40000000109); // Meta_R + insert_record(table, 0x0000ffe9, 0x30000000102); // Alt_L + insert_record(table, 0x0000ffea, 0x40000000102); // Alt_R + insert_record(table, 0x0000ffeb, 0x100000010e); // Super_L + insert_record(table, 0x0000ffec, 0x100000010e); // Super_R + insert_record(table, 0x0000ffed, 0x1000000108); // Hyper_L + insert_record(table, 0x0000ffee, 0x1000000108); // Hyper_R + insert_record(table, 0x0000ffff, 0x100000007f); // Delete + insert_record(table, 0x1008ff02, 0x1000000602); // MonBrightnessUp + insert_record(table, 0x1008ff03, 0x1000000601); // MonBrightnessDown + insert_record(table, 0x1008ff10, 0x100000060a); // Standby + insert_record(table, 0x1008ff11, 0x1000000a0f); // AudioLowerVolume + insert_record(table, 0x1008ff12, 0x1000000a11); // AudioMute + insert_record(table, 0x1008ff13, 0x1000000a10); // AudioRaiseVolume + insert_record(table, 0x1008ff14, 0x1000000d2f); // AudioPlay + insert_record(table, 0x1008ff15, 0x1000000a07); // AudioStop + insert_record(table, 0x1008ff16, 0x1000000a09); // AudioPrev + insert_record(table, 0x1008ff17, 0x1000000a08); // AudioNext + insert_record(table, 0x1008ff18, 0x1000000c04); // HomePage + insert_record(table, 0x1008ff19, 0x1000000b03); // Mail + insert_record(table, 0x1008ff1b, 0x1000000c06); // Search + insert_record(table, 0x1008ff1c, 0x1000000d30); // AudioRecord + insert_record(table, 0x1008ff20, 0x1000000b02); // Calendar + insert_record(table, 0x1008ff26, 0x1000000c01); // Back + insert_record(table, 0x1008ff27, 0x1000000c03); // Forward + insert_record(table, 0x1008ff28, 0x1000000c07); // Stop + insert_record(table, 0x1008ff29, 0x1000000c05); // Refresh + insert_record(table, 0x1008ff2a, 0x1000000607); // PowerOff + insert_record(table, 0x1008ff2b, 0x100000060b); // WakeUp + insert_record(table, 0x1008ff2c, 0x1000000604); // Eject + insert_record(table, 0x1008ff2d, 0x1000000b07); // ScreenSaver + insert_record(table, 0x1008ff2f, 0x1100010082); // Sleep + insert_record(table, 0x1008ff30, 0x1000000c02); // Favorites + insert_record(table, 0x1008ff31, 0x1000000d2e); // AudioPause + insert_record(table, 0x1008ff3e, 0x1000000d31); // AudioRewind + insert_record(table, 0x1008ff56, 0x1000000a01); // Close + insert_record(table, 0x1008ff57, 0x1000000402); // Copy + insert_record(table, 0x1008ff58, 0x1000000404); // Cut + insert_record(table, 0x1008ff61, 0x1000000605); // LogOff + insert_record(table, 0x1008ff68, 0x1000000a0a); // New + insert_record(table, 0x1008ff6b, 0x1000000a0b); // Open + insert_record(table, 0x1008ff6d, 0x1000000408); // Paste + insert_record(table, 0x1008ff6e, 0x1000000b0d); // Phone + insert_record(table, 0x1008ff72, 0x1000000a03); // Reply + insert_record(table, 0x1008ff77, 0x1000000a0d); // Save + insert_record(table, 0x1008ff7b, 0x1000000a04); // Send + insert_record(table, 0x1008ff7c, 0x1000000a0e); // Spell + insert_record(table, 0x1008ff8b, 0x100000050d); // ZoomIn + insert_record(table, 0x1008ff8c, 0x100000050e); // ZoomOut + insert_record(table, 0x1008ff90, 0x1000000a02); // MailForward + insert_record(table, 0x1008ff97, 0x1000000d2c); // AudioForward + insert_record(table, 0x1008ffa7, 0x1100000014); // Suspend } void initialize_modifier_bit_to_checked_keys(GHashTable* table) { @@ -425,64 +424,46 @@ void initialize_modifier_bit_to_checked_keys(GHashTable* table) { data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_SHIFT_MASK), data); - data->length = 2; - data->first_logical_key = 0x30000010d; // shiftLeft - physical_keys = g_new(uint64_t, 2); - data->physical_keys = physical_keys; + data->primary_logical_key = 0x3000000010d; // shiftLeft + data->primary_physical_key = 0x0000700e1; // shiftLeft + data->secondary_physical_key = 0x0000700e5; // shiftRight data->is_caps_lock = false; - *(physical_keys++) = 0x000700e1; // ShiftLeft - *(physical_keys++) = 0x000700e5; // ShiftRight data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_CONTROL_MASK), data); - data->length = 2; - data->first_logical_key = 0x300000105; // controlLeft - physical_keys = g_new(uint64_t, 2); - data->physical_keys = physical_keys; + data->primary_logical_key = 0x30000000105; // controlLeft + data->primary_physical_key = 0x0000700e0; // controlLeft + data->secondary_physical_key = 0x0000700e4; // controlRight data->is_caps_lock = false; - *(physical_keys++) = 0x000700e0; // ControlLeft - *(physical_keys++) = 0x000700e4; // ControlRight data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_MOD1_MASK), data); - data->length = 2; - data->first_logical_key = 0x300000102; // altLeft - physical_keys = g_new(uint64_t, 2); - data->physical_keys = physical_keys; + data->primary_logical_key = 0x30000000102; // altLeft + data->primary_physical_key = 0x0000700e2; // altLeft + data->secondary_physical_key = 0x0000700e6; // altRight data->is_caps_lock = false; - *(physical_keys++) = 0x000700e2; // AltLeft - *(physical_keys++) = 0x000700e6; // AltRight data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_MOD4_MASK), data); - data->length = 2; - data->first_logical_key = 0x300000109; // metaLeft - physical_keys = g_new(uint64_t, 2); - data->physical_keys = physical_keys; + data->primary_logical_key = 0x30000000109; // metaLeft + data->primary_physical_key = 0x0000700e3; // metaLeft + data->secondary_physical_key = 0x0000700e7; // metaRight data->is_caps_lock = false; - *(physical_keys++) = 0x000700e3; // MetaLeft - *(physical_keys++) = 0x000700e7; // MetaRight } -void initialize_lock_mode_bit_to_checked_keys(GHashTable* table) { +void initialize_lock_bit_to_checked_keys(GHashTable* table) { FlKeyEmbedderCheckedKey* data; uint64_t* physical_keys; data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_LOCK_MASK), data); - data->length = 1; - data->first_logical_key = 0x000000104; // capsLock - physical_keys = g_new(uint64_t, 1); - data->physical_keys = physical_keys; + data->primary_logical_key = 0x1000000104; // capsLock + data->primary_physical_key = 0x000070039; // capsLock data->is_caps_lock = true; - *(physical_keys++) = 0x00070039; // CapsLock data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_MOD2_MASK), data); - data->length = 1; - data->first_logical_key = 0x00000010a; // numLock - physical_keys = g_new(uint64_t, 1); - data->physical_keys = physical_keys; + data->primary_logical_key = 0x100000010a; // numLock + data->primary_physical_key = 0x000070053; // numLock data->is_caps_lock = false; - *(physical_keys++) = 0x00070053; // NumLock } diff --git a/shell/platform/linux/key_mapping.h b/shell/platform/linux/key_mapping.h index 88c9c36b9fa9b..3f75ecfc68615 100644 --- a/shell/platform/linux/key_mapping.h +++ b/shell/platform/linux/key_mapping.h @@ -26,6 +26,6 @@ void initialize_gtk_keyval_to_logical_key(GHashTable* table); void initialize_modifier_bit_to_checked_keys(GHashTable* table); -void initialize_lock_mode_bit_to_checked_keys(GHashTable* table); +void initialize_lock_bit_to_checked_keys(GHashTable* table); #endif // KEYBOARD_MAP_H_ diff --git a/shell/platform/windows/flutter_key_map.cc b/shell/platform/windows/flutter_key_map.cc index 69256a78f2606..c9b854ed1235e 100644 --- a/shell/platform/windows/flutter_key_map.cc +++ b/shell/platform/windows/flutter_key_map.cc @@ -182,10 +182,6 @@ std::map KeyboardKeyEmbedderHandler::windowsToPhysicalMap_ = std::map KeyboardKeyEmbedderHandler::windowsToLogicalMap_ = { - {0x00000008, 0x00000000008}, // BACK - {0x00000009, 0x00000000009}, // TAB - {0x0000000d, 0x0000000000d}, // RETURN - {0x0000001b, 0x0000000001b}, // ESCAPE {0x00000020, 0x00000000020}, // SPACE {0x000000de, 0x00000000022}, // OEM_7 {0x000000bc, 0x0000000002c}, // OEM_COMMA @@ -198,130 +194,136 @@ std::map KeyboardKeyEmbedderHandler::windowsToLogicalMap_ = {0x000000dc, 0x0000000005c}, // OEM_5 {0x000000dd, 0x0000000005d}, // OEM_6 {0x000000c0, 0x00000000060}, // OEM_3 - {0x0000002e, 0x0000000007f}, // DELETE - {0x00000014, 0x00000000104}, // CAPITAL - {0x00000090, 0x0000000010a}, // NUMLOCK - {0x00000091, 0x0000000010c}, // SCROLL - {0x00000028, 0x00000000301}, // DOWN - {0x00000025, 0x00000000302}, // LEFT - {0x00000027, 0x00000000303}, // RIGHT - {0x00000026, 0x00000000304}, // UP - {0x00000023, 0x00000000305}, // END - {0x00000024, 0x00000000306}, // HOME - {0x00000022, 0x00000000307}, // NEXT - {0x00000021, 0x00000000308}, // PRIOR - {0x0000000c, 0x00000000401}, // CLEAR - {0x0000002d, 0x00000000407}, // INSERT - {0x0000001e, 0x00000000501}, // ACCEPT - {0x000000f6, 0x00000000503}, // ATTN - {0x00000003, 0x00000000504}, // CANCEL - {0x0000005d, 0x00000000505}, // APPS - {0x0000002b, 0x00000000506}, // EXECUTE - {0x0000002f, 0x00000000508}, // HELP - {0x00000013, 0x00000000509}, // PAUSE - {0x000000fa, 0x0000000050a}, // PLAY - {0x00000029, 0x0000000050c}, // SELECT - {0x0000001c, 0x00000000705}, // CONVERT - {0x0000001f, 0x0000000070b}, // MODECHANGE - {0x00000070, 0x00000000801}, // F1 - {0x00000071, 0x00000000802}, // F2 - {0x00000072, 0x00000000803}, // F3 - {0x00000073, 0x00000000804}, // F4 - {0x00000074, 0x00000000805}, // F5 - {0x00000075, 0x00000000806}, // F6 - {0x00000076, 0x00000000807}, // F7 - {0x00000077, 0x00000000808}, // F8 - {0x00000078, 0x00000000809}, // F9 - {0x00000079, 0x0000000080a}, // F10 - {0x0000007a, 0x0000000080b}, // F11 - {0x0000007b, 0x0000000080c}, // F12 - {0x0000007c, 0x0000000080d}, // F13 - {0x0000007d, 0x0000000080e}, // F14 - {0x0000007e, 0x0000000080f}, // F15 - {0x0000007f, 0x00000000810}, // F16 - {0x00000080, 0x00000000811}, // F17 - {0x00000081, 0x00000000812}, // F18 - {0x00000082, 0x00000000813}, // F19 - {0x00000083, 0x00000000814}, // F20 - {0x00000084, 0x00000000815}, // F21 - {0x00000085, 0x00000000816}, // F22 - {0x00000086, 0x00000000817}, // F23 - {0x00000087, 0x00000000818}, // F24 - {0x000000b3, 0x00000000a05}, // MEDIA_PLAY_PAUSE - {0x000000b2, 0x00000000a07}, // MEDIA_STOP - {0x0000002a, 0x00000000a0c}, // PRINT - {0x000000ae, 0x00000000a0f}, // VOLUME_DOWN - {0x000000af, 0x00000000a10}, // VOLUME_UP - {0x000000ad, 0x00000000a11}, // VOLUME_MUTE - {0x000000b4, 0x00000000b03}, // LAUNCH_MAIL - {0x000000a6, 0x00000000c01}, // BROWSER_BACK - {0x000000ab, 0x00000000c02}, // BROWSER_FAVORITES - {0x000000a7, 0x00000000c03}, // BROWSER_FORWARD - {0x000000ac, 0x00000000c04}, // BROWSER_HOME - {0x000000a8, 0x00000000c05}, // BROWSER_REFRESH - {0x000000aa, 0x00000000c06}, // BROWSER_SEARCH - {0x000000a9, 0x00000000c07}, // BROWSER_STOP - {0x000000c3, 0x0000005ff08}, // GAMEPAD_A - {0x000000c4, 0x0000005ff09}, // GAMEPAD_B - {0x000000c5, 0x0000005ff0a}, // GAMEPAD_X - {0x000000c6, 0x0000005ff0b}, // GAMEPAD_Y - {0x000000c7, 0x0000005ff0c}, // GAMEPAD_RIGHT_SHOULDER - {0x000000c8, 0x0000005ff0d}, // GAMEPAD_LEFT_SHOULDER - {0x000000c9, 0x0000005ff0e}, // GAMEPAD_LEFT_TRIGGER - {0x000000ca, 0x0000005ff0f}, // GAMEPAD_RIGHT_TRIGGER - {0x000000cb, 0x0000005ff10}, // GAMEPAD_DPAD_UP - {0x0000005f, 0x00100010082}, // SLEEP - {0x00000015, 0x00100070090}, // KANA - {0x00000015, 0x00100070090}, // HANGEUL - {0x00000015, 0x00100070090}, // HANGUL - {0x0000006a, 0x0020000002a}, // MULTIPLY - {0x0000006b, 0x0020000002b}, // ADD - {0x0000006d, 0x0020000002d}, // SUBTRACT - {0x0000006e, 0x0020000002e}, // DECIMAL - {0x0000006f, 0x0020000002f}, // DIVIDE - {0x00000060, 0x00200000030}, // NUMPAD0 - {0x00000061, 0x00200000031}, // NUMPAD1 - {0x00000062, 0x00200000032}, // NUMPAD2 - {0x00000063, 0x00200000033}, // NUMPAD3 - {0x00000064, 0x00200000034}, // NUMPAD4 - {0x00000065, 0x00200000035}, // NUMPAD5 - {0x00000066, 0x00200000036}, // NUMPAD6 - {0x00000067, 0x00200000037}, // NUMPAD7 - {0x00000068, 0x00200000038}, // NUMPAD8 - {0x00000069, 0x00200000039}, // NUMPAD9 - {0x00000092, 0x0020000003d}, // OEM_NEC_EQUAL - {0x000000a4, 0x00300000102}, // LMENU - {0x00000011, 0x00300000105}, // CONTROL - {0x000000a2, 0x00300000105}, // LCONTROL - {0x0000005b, 0x00300000109}, // LWIN - {0x00000010, 0x0030000010d}, // SHIFT - {0x000000a0, 0x0030000010d}, // LSHIFT - {0x000000a5, 0x00400000102}, // RMENU - {0x000000a3, 0x00400000105}, // RCONTROL - {0x0000005c, 0x00400000109}, // RWIN - {0x000000a1, 0x0040000010d}, // RSHIFT + {0x00000008, 0x01000000008}, // BACK + {0x00000009, 0x01000000009}, // TAB + {0x0000000d, 0x0100000000d}, // RETURN + {0x0000001b, 0x0100000001b}, // ESCAPE + {0x0000002e, 0x0100000007f}, // DELETE + {0x00000014, 0x01000000104}, // CAPITAL + {0x00000090, 0x0100000010a}, // NUMLOCK + {0x00000091, 0x0100000010c}, // SCROLL + {0x00000028, 0x01000000301}, // DOWN + {0x00000025, 0x01000000302}, // LEFT + {0x00000027, 0x01000000303}, // RIGHT + {0x00000026, 0x01000000304}, // UP + {0x00000023, 0x01000000305}, // END + {0x00000024, 0x01000000306}, // HOME + {0x00000022, 0x01000000307}, // NEXT + {0x00000021, 0x01000000308}, // PRIOR + {0x0000000c, 0x01000000401}, // CLEAR + {0x0000002d, 0x01000000407}, // INSERT + {0x0000001e, 0x01000000501}, // ACCEPT + {0x000000f6, 0x01000000503}, // ATTN + {0x00000003, 0x01000000504}, // CANCEL + {0x0000005d, 0x01000000505}, // APPS + {0x0000002b, 0x01000000506}, // EXECUTE + {0x0000002f, 0x01000000508}, // HELP + {0x00000013, 0x01000000509}, // PAUSE + {0x000000fa, 0x0100000050a}, // PLAY + {0x00000029, 0x0100000050c}, // SELECT + {0x0000001c, 0x01000000705}, // CONVERT + {0x00000018, 0x01000000706}, // FINAL + {0x0000001f, 0x0100000070b}, // MODECHANGE + {0x00000019, 0x01000000712}, // HANJA + {0x00000017, 0x01000000713}, // JUNJA + {0x00000019, 0x01000000719}, // KANJI + {0x00000070, 0x01000000801}, // F1 + {0x00000071, 0x01000000802}, // F2 + {0x00000072, 0x01000000803}, // F3 + {0x00000073, 0x01000000804}, // F4 + {0x00000074, 0x01000000805}, // F5 + {0x00000075, 0x01000000806}, // F6 + {0x00000076, 0x01000000807}, // F7 + {0x00000077, 0x01000000808}, // F8 + {0x00000078, 0x01000000809}, // F9 + {0x00000079, 0x0100000080a}, // F10 + {0x0000007a, 0x0100000080b}, // F11 + {0x0000007b, 0x0100000080c}, // F12 + {0x0000007c, 0x0100000080d}, // F13 + {0x0000007d, 0x0100000080e}, // F14 + {0x0000007e, 0x0100000080f}, // F15 + {0x0000007f, 0x01000000810}, // F16 + {0x00000080, 0x01000000811}, // F17 + {0x00000081, 0x01000000812}, // F18 + {0x00000082, 0x01000000813}, // F19 + {0x00000083, 0x01000000814}, // F20 + {0x00000084, 0x01000000815}, // F21 + {0x00000085, 0x01000000816}, // F22 + {0x00000086, 0x01000000817}, // F23 + {0x00000087, 0x01000000818}, // F24 + {0x000000b3, 0x01000000a05}, // MEDIA_PLAY_PAUSE + {0x000000b2, 0x01000000a07}, // MEDIA_STOP + {0x0000002a, 0x01000000a0c}, // PRINT + {0x000000ae, 0x01000000a0f}, // VOLUME_DOWN + {0x000000af, 0x01000000a10}, // VOLUME_UP + {0x000000ad, 0x01000000a11}, // VOLUME_MUTE + {0x000000b4, 0x01000000b03}, // LAUNCH_MAIL + {0x000000a6, 0x01000000c01}, // BROWSER_BACK + {0x000000ab, 0x01000000c02}, // BROWSER_FAVORITES + {0x000000a7, 0x01000000c03}, // BROWSER_FORWARD + {0x000000ac, 0x01000000c04}, // BROWSER_HOME + {0x000000a8, 0x01000000c05}, // BROWSER_REFRESH + {0x000000aa, 0x01000000c06}, // BROWSER_SEARCH + {0x000000a9, 0x01000000c07}, // BROWSER_STOP + {0x000000c3, 0x0100005ff08}, // GAMEPAD_A + {0x000000c4, 0x0100005ff09}, // GAMEPAD_B + {0x000000c5, 0x0100005ff0a}, // GAMEPAD_X + {0x000000c6, 0x0100005ff0b}, // GAMEPAD_Y + {0x000000c7, 0x0100005ff0c}, // GAMEPAD_RIGHT_SHOULDER + {0x000000c8, 0x0100005ff0d}, // GAMEPAD_LEFT_SHOULDER + {0x000000c9, 0x0100005ff0e}, // GAMEPAD_LEFT_TRIGGER + {0x000000ca, 0x0100005ff0f}, // GAMEPAD_RIGHT_TRIGGER + {0x000000cb, 0x0100005ff10}, // GAMEPAD_DPAD_UP + {0x0000005f, 0x01100010082}, // SLEEP + {0x00000015, 0x01100070090}, // KANA, HANGEUL, HANGUL + {0x000000a4, 0x30000000102}, // LMENU + {0x00000011, 0x30000000105}, // CONTROL + {0x000000a2, 0x30000000105}, // LCONTROL + {0x0000005b, 0x30000000109}, // LWIN + {0x00000010, 0x3000000010d}, // SHIFT + {0x000000a0, 0x3000000010d}, // LSHIFT + {0x000000a5, 0x40000000102}, // RMENU + {0x000000a3, 0x40000000105}, // RCONTROL + {0x0000005c, 0x40000000109}, // RWIN + {0x000000a1, 0x4000000010d}, // RSHIFT + {0x0000006a, 0x5000000002a}, // MULTIPLY + {0x0000006b, 0x5000000002b}, // ADD + {0x0000006d, 0x5000000002d}, // SUBTRACT + {0x0000006e, 0x5000000002e}, // DECIMAL + {0x0000006f, 0x5000000002f}, // DIVIDE + {0x00000060, 0x50000000030}, // NUMPAD0 + {0x00000061, 0x50000000031}, // NUMPAD1 + {0x00000062, 0x50000000032}, // NUMPAD2 + {0x00000063, 0x50000000033}, // NUMPAD3 + {0x00000064, 0x50000000034}, // NUMPAD4 + {0x00000065, 0x50000000035}, // NUMPAD5 + {0x00000066, 0x50000000036}, // NUMPAD6 + {0x00000067, 0x50000000037}, // NUMPAD7 + {0x00000068, 0x50000000038}, // NUMPAD8 + {0x00000069, 0x50000000039}, // NUMPAD9 + {0x00000092, 0x5000000003d}, // OEM_NEC_EQUAL }; std::map KeyboardKeyEmbedderHandler::scanCodeToLogicalMap_ = { - {0x0000e01d, 0x0400000105}, // ControlRight - {0x0000e038, 0x0400000102}, // AltRight - {0x0000004f, 0x0200000031}, // Numpad1 - {0x00000050, 0x0200000032}, // Numpad2 - {0x00000051, 0x0200000033}, // Numpad3 - {0x0000004b, 0x0200000034}, // Numpad4 - {0x0000004c, 0x0200000035}, // Numpad5 - {0x0000004d, 0x0200000036}, // Numpad6 - {0x00000047, 0x0200000037}, // Numpad7 - {0x00000048, 0x0200000038}, // Numpad8 - {0x00000049, 0x0200000039}, // Numpad9 - {0x00000052, 0x0200000030}, // Numpad0 - {0x0000004e, 0x020000002b}, // NumpadAdd - {0x00000053, 0x020000002e}, // NumpadDecimal - {0x0000e035, 0x020000002f}, // NumpadDivide - {0x00000059, 0x020000003d}, // NumpadEqual - {0x00000037, 0x020000002a}, // NumpadMultiply - {0x0000004a, 0x020000002d}, // NumpadSubtract + {0x0000e01d, 0x40000000105}, // ControlRight + {0x0000e038, 0x40000000102}, // AltRight + {0x0000004f, 0x50000000031}, // Numpad1 + {0x00000050, 0x50000000032}, // Numpad2 + {0x00000051, 0x50000000033}, // Numpad3 + {0x0000004b, 0x50000000034}, // Numpad4 + {0x0000004c, 0x50000000035}, // Numpad5 + {0x0000004d, 0x50000000036}, // Numpad6 + {0x00000047, 0x50000000037}, // Numpad7 + {0x00000048, 0x50000000038}, // Numpad8 + {0x00000049, 0x50000000039}, // Numpad9 + {0x00000052, 0x50000000030}, // Numpad0 + {0x0000004e, 0x5000000002b}, // NumpadAdd + {0x00000053, 0x5000000002e}, // NumpadDecimal + {0x0000e035, 0x5000000002f}, // NumpadDivide + {0x00000059, 0x5000000003d}, // NumpadEqual + {0x00000037, 0x5000000002a}, // NumpadMultiply + {0x0000004a, 0x5000000002d}, // NumpadSubtract }; } // namespace flutter From c66f16b98bb6272022352fdb58ea6d51d5f532f5 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 26 Apr 2021 04:29:43 -0700 Subject: [PATCH 046/126] ATP --- .../linux/fl_key_embedder_responder.cc | 32 +- .../linux/fl_key_embedder_responder_test.cc | 22 +- shell/platform/linux/fl_keyboard_manager.h | 3 +- shell/platform/linux/key_mapping.cc | 290 +++++++++--------- 4 files changed, 169 insertions(+), 178 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index ae3d063a2a82c..69066f475c2b4 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -154,14 +154,14 @@ static void fl_key_embedder_responder_class_init( // Initializes an FlKeyEmbedderResponder instance. static void fl_key_embedder_responder_init(FlKeyEmbedderResponder* self) {} -static void initialize_physical_key_to_lock_bit_loop_body( - gpointer lock_bit, - gpointer value, - gpointer user_data) { +static void initialize_physical_key_to_lock_bit_loop_body(gpointer lock_bit, + gpointer value, + gpointer user_data) { FlKeyEmbedderCheckedKey* checked_key = reinterpret_cast(value); GHashTable* table = reinterpret_cast(user_data); - g_hash_table_insert(table, uint64_to_gpointer(checked_key->physical_keys[0]), + g_hash_table_insert(table, + uint64_to_gpointer(checked_key->primary_physical_key), GUINT_TO_POINTER(lock_bit)); } @@ -191,12 +191,12 @@ FlKeyEmbedderResponder* fl_key_embedder_responder_new(FlEngine* engine) { self->keyval_to_logical_key = g_hash_table_new(g_direct_hash, g_direct_equal); initialize_gtk_keyval_to_logical_key(self->keyval_to_logical_key); - self->modifier_bit_to_checked_keys = g_hash_table_new_full( - g_direct_hash, g_direct_equal, NULL, g_free); + self->modifier_bit_to_checked_keys = + g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free); initialize_modifier_bit_to_checked_keys(self->modifier_bit_to_checked_keys); - self->lock_bit_to_checked_keys = g_hash_table_new_full( - g_direct_hash, g_direct_equal, NULL, g_free); + self->lock_bit_to_checked_keys = + g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free); initialize_lock_bit_to_checked_keys(self->lock_bit_to_checked_keys); self->physical_key_to_lock_bit = @@ -332,10 +332,10 @@ static void synchronize_pressed_states_loop_body(gpointer key, const guint modifier_bit = GPOINTER_TO_INT(key); FlKeyEmbedderResponder* self = context->self; const uint64_t physical_keys[] = { - checked_key->primary_physical_key, - checked_key->secondary_physical_key, + checked_key->primary_physical_key, + checked_key->secondary_physical_key, }; - const int length = checked_key->secondary_physical_key == 0 ? 1 : 2; + const guint length = checked_key->secondary_physical_key == 0 ? 1 : 2; // printf("Syn: 1 state %x bit %x curPhy %lx\n", context->state, modifier_bit, // context->event_physical_key); @@ -449,8 +449,8 @@ static void update_pressing_state(FlKeyEmbedderResponder* self, } static void possibly_update_lock_bit(FlKeyEmbedderResponder* self, - uint64_t physical_key, - bool is_down) { + uint64_t physical_key, + bool is_down) { if (!is_down) { return; } @@ -463,8 +463,8 @@ static void possibly_update_lock_bit(FlKeyEmbedderResponder* self, } static void synchronize_lock_states_loop_body(gpointer key, - gpointer value, - gpointer user_data) { + gpointer value, + gpointer user_data) { SyncPressedStatesLoopContext* context = reinterpret_cast(user_data); FlKeyEmbedderCheckedKey* checked_key = diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index 8fc87fd2432f7..8b9e58f379fa8 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -19,31 +19,25 @@ constexpr gboolean kIsModifier = TRUE; constexpr gboolean kIsNotModifier = FALSE; constexpr guint16 kKeyCodeKeyA = 0x26u; -// constexpr guint16 kKeyCodeKeyB = 0x38u; -constexpr guint16 kKeyCodeShiftRight = 0x3eu; +constexpr guint16 kKeyCodeShiftRight = 0x3Eu; constexpr guint16 kKeyCodeNumpad1 = 0x57u; -constexpr guint16 kKeyCodeNumLock = 0x4du; +constexpr guint16 kKeyCodeNumLock = 0x4Du; constexpr guint16 kKeyCodeCapsLock = 0x42u; constexpr uint64_t kPhysicalKeyA = 0x00070004; -// constexpr uint64_t kPhysicalKeyQ = 0x00070014; constexpr uint64_t kPhysicalControlLeft = 0x000700e0; -// constexpr uint64_t kPhysicalControlRight = 0x000700e4; -// constexpr uint64_t kPhysicalShiftLeft = 0x000700e1; -constexpr uint64_t kPhysicalShiftRight = 0x000700e5; +constexpr uint64_t kPhysicalShiftRight = 0x000700E5; constexpr uint64_t kPhysicalKeyNumpad1 = 0x00070059; constexpr uint64_t kPhysicalKeyNumLock = 0x00070053; constexpr uint64_t kPhysicalKeyCapsLock = 0x00070039; constexpr uint64_t kLogicalKeyA = 0x00000061; constexpr uint64_t kLogicalKeyQ = 0x00000071; -constexpr uint64_t kLogicalControlLeft = 0x00300000105; -// constexpr uint64_t kLogicalControlRight = 0x00400000105; -// constexpr uint64_t kLogicalShiftLeft = 0x0030000010d; -constexpr uint64_t kLogicalShiftRight = 0x0040000010d; -constexpr uint64_t kLogicalKeyNumpad1 = 0x00200000031; -constexpr uint64_t kLogicalKeyNumLock = 0x0000000010a; -constexpr uint64_t kLogicalKeyCapsLock = 0x00000000104; +constexpr uint64_t kLogicalControlLeft = 0x30000000105; +constexpr uint64_t kLogicalShiftRight = 0x4000000010D; +constexpr uint64_t kLogicalKeyNumpad1 = 0x50000000031; +constexpr uint64_t kLogicalKeyNumLock = 0x100000010A; +constexpr uint64_t kLogicalKeyCapsLock = 0x1000000104; } // namespace static void g_ptr_array_clear(GPtrArray* array) { diff --git a/shell/platform/linux/fl_keyboard_manager.h b/shell/platform/linux/fl_keyboard_manager.h index 47bf2ff60da82..db9524fabe5ac 100644 --- a/shell/platform/linux/fl_keyboard_manager.h +++ b/shell/platform/linux/fl_keyboard_manager.h @@ -103,8 +103,7 @@ gboolean fl_keyboard_manager_handle_event(FlKeyboardManager* manager, * * Returns: true if the manager's various states are cleared. */ -gboolean fl_keyboard_manager_is_state_clear( - FlKeyboardManager* manager); +gboolean fl_keyboard_manager_is_state_clear(FlKeyboardManager* manager); G_END_DECLS diff --git a/shell/platform/linux/key_mapping.cc b/shell/platform/linux/key_mapping.cc index f1f01edfadd5d..177b8367a22d4 100644 --- a/shell/platform/linux/key_mapping.cc +++ b/shell/platform/linux/key_mapping.cc @@ -245,69 +245,69 @@ void initialize_xkb_to_physical_key(GHashTable* table) { } void initialize_gtk_keyval_to_logical_key(GHashTable* table) { - insert_record(table, 0x000000a5, 0x1100070089); // yen - insert_record(table, 0x0000fd06, 0x1000000405); // 3270_EraseEOF - insert_record(table, 0x0000fd0e, 0x1000000503); // 3270_Attn - insert_record(table, 0x0000fd15, 0x1000000402); // 3270_Copy - insert_record(table, 0x0000fd16, 0x1000000d2f); // 3270_Play - insert_record(table, 0x0000fd1b, 0x1000000406); // 3270_ExSelect - insert_record(table, 0x0000fd1d, 0x1000000608); // 3270_PrintScreen - insert_record(table, 0x0000fd1e, 0x100000000d); // 3270_Enter + insert_record(table, 0x000000a5, 0x1100070089); // yen + insert_record(table, 0x0000fd06, 0x1000000405); // 3270_EraseEOF + insert_record(table, 0x0000fd0e, 0x1000000503); // 3270_Attn + insert_record(table, 0x0000fd15, 0x1000000402); // 3270_Copy + insert_record(table, 0x0000fd16, 0x1000000d2f); // 3270_Play + insert_record(table, 0x0000fd1b, 0x1000000406); // 3270_ExSelect + insert_record(table, 0x0000fd1d, 0x1000000608); // 3270_PrintScreen + insert_record(table, 0x0000fd1e, 0x100000000d); // 3270_Enter insert_record(table, 0x0000fe03, 0x40000000102); // ISO_Level3_Shift - insert_record(table, 0x0000fe08, 0x1000000709); // ISO_Next_Group - insert_record(table, 0x0000fe0a, 0x100000070a); // ISO_Prev_Group - insert_record(table, 0x0000fe0c, 0x1000000707); // ISO_First_Group - insert_record(table, 0x0000fe0e, 0x1000000708); // ISO_Last_Group - insert_record(table, 0x0000fe20, 0x1000000009); // ISO_Left_Tab - insert_record(table, 0x0000fe34, 0x100000000d); // ISO_Enter - insert_record(table, 0x0000ff08, 0x1000000008); // BackSpace - insert_record(table, 0x0000ff09, 0x1000000009); // Tab - insert_record(table, 0x0000ff0b, 0x1000000401); // Clear - insert_record(table, 0x0000ff0d, 0x100000000d); // Return - insert_record(table, 0x0000ff13, 0x1000000509); // Pause - insert_record(table, 0x0000ff14, 0x100000010c); // Scroll_Lock - insert_record(table, 0x0000ff1b, 0x100000001b); // Escape - insert_record(table, 0x0000ff21, 0x1000000719); // Kanji - insert_record(table, 0x0000ff24, 0x100000071b); // Romaji - insert_record(table, 0x0000ff25, 0x1000000716); // Hiragana - insert_record(table, 0x0000ff26, 0x100000071a); // Katakana - insert_record(table, 0x0000ff27, 0x1000000717); // Hiragana_Katakana - insert_record(table, 0x0000ff28, 0x100000071c); // Zenkaku - insert_record(table, 0x0000ff29, 0x1000000715); // Hankaku - insert_record(table, 0x0000ff2a, 0x100000071d); // Zenkaku_Hankaku - insert_record(table, 0x0000ff2f, 0x1000000714); // Eisu_Shift - insert_record(table, 0x0000ff31, 0x1000000711); // Hangul - insert_record(table, 0x0000ff34, 0x1000000712); // Hangul_Hanja - insert_record(table, 0x0000ff37, 0x1000000703); // Codeinput - insert_record(table, 0x0000ff3c, 0x1000000710); // SingleCandidate - insert_record(table, 0x0000ff3e, 0x100000070e); // PreviousCandidate - insert_record(table, 0x0000ff50, 0x1000000306); // Home - insert_record(table, 0x0000ff51, 0x1000000302); // Left - insert_record(table, 0x0000ff52, 0x1000000304); // Up - insert_record(table, 0x0000ff53, 0x1000000303); // Right - insert_record(table, 0x0000ff54, 0x1000000301); // Down - insert_record(table, 0x0000ff55, 0x1000000308); // Page_Up - insert_record(table, 0x0000ff56, 0x1000000307); // Page_Down - insert_record(table, 0x0000ff57, 0x1000000305); // End - insert_record(table, 0x0000ff60, 0x100000050c); // Select - insert_record(table, 0x0000ff61, 0x1000000a0c); // Print - insert_record(table, 0x0000ff62, 0x1000000506); // Execute - insert_record(table, 0x0000ff63, 0x1000000407); // Insert - insert_record(table, 0x0000ff65, 0x100000040a); // Undo - insert_record(table, 0x0000ff66, 0x1000000409); // Redo - insert_record(table, 0x0000ff67, 0x1000000505); // Menu - insert_record(table, 0x0000ff68, 0x1000000507); // Find - insert_record(table, 0x0000ff69, 0x1000000504); // Cancel - insert_record(table, 0x0000ff6a, 0x1000000508); // Help - insert_record(table, 0x0000ff7e, 0x100000070b); // Mode_switch - insert_record(table, 0x0000ff7f, 0x100000010a); // Num_Lock - insert_record(table, 0x0000ff80, 0x0000000020); // KP_Space - insert_record(table, 0x0000ff89, 0x1000000009); // KP_Tab + insert_record(table, 0x0000fe08, 0x1000000709); // ISO_Next_Group + insert_record(table, 0x0000fe0a, 0x100000070a); // ISO_Prev_Group + insert_record(table, 0x0000fe0c, 0x1000000707); // ISO_First_Group + insert_record(table, 0x0000fe0e, 0x1000000708); // ISO_Last_Group + insert_record(table, 0x0000fe20, 0x1000000009); // ISO_Left_Tab + insert_record(table, 0x0000fe34, 0x100000000d); // ISO_Enter + insert_record(table, 0x0000ff08, 0x1000000008); // BackSpace + insert_record(table, 0x0000ff09, 0x1000000009); // Tab + insert_record(table, 0x0000ff0b, 0x1000000401); // Clear + insert_record(table, 0x0000ff0d, 0x100000000d); // Return + insert_record(table, 0x0000ff13, 0x1000000509); // Pause + insert_record(table, 0x0000ff14, 0x100000010c); // Scroll_Lock + insert_record(table, 0x0000ff1b, 0x100000001b); // Escape + insert_record(table, 0x0000ff21, 0x1000000719); // Kanji + insert_record(table, 0x0000ff24, 0x100000071b); // Romaji + insert_record(table, 0x0000ff25, 0x1000000716); // Hiragana + insert_record(table, 0x0000ff26, 0x100000071a); // Katakana + insert_record(table, 0x0000ff27, 0x1000000717); // Hiragana_Katakana + insert_record(table, 0x0000ff28, 0x100000071c); // Zenkaku + insert_record(table, 0x0000ff29, 0x1000000715); // Hankaku + insert_record(table, 0x0000ff2a, 0x100000071d); // Zenkaku_Hankaku + insert_record(table, 0x0000ff2f, 0x1000000714); // Eisu_Shift + insert_record(table, 0x0000ff31, 0x1000000711); // Hangul + insert_record(table, 0x0000ff34, 0x1000000712); // Hangul_Hanja + insert_record(table, 0x0000ff37, 0x1000000703); // Codeinput + insert_record(table, 0x0000ff3c, 0x1000000710); // SingleCandidate + insert_record(table, 0x0000ff3e, 0x100000070e); // PreviousCandidate + insert_record(table, 0x0000ff50, 0x1000000306); // Home + insert_record(table, 0x0000ff51, 0x1000000302); // Left + insert_record(table, 0x0000ff52, 0x1000000304); // Up + insert_record(table, 0x0000ff53, 0x1000000303); // Right + insert_record(table, 0x0000ff54, 0x1000000301); // Down + insert_record(table, 0x0000ff55, 0x1000000308); // Page_Up + insert_record(table, 0x0000ff56, 0x1000000307); // Page_Down + insert_record(table, 0x0000ff57, 0x1000000305); // End + insert_record(table, 0x0000ff60, 0x100000050c); // Select + insert_record(table, 0x0000ff61, 0x1000000a0c); // Print + insert_record(table, 0x0000ff62, 0x1000000506); // Execute + insert_record(table, 0x0000ff63, 0x1000000407); // Insert + insert_record(table, 0x0000ff65, 0x100000040a); // Undo + insert_record(table, 0x0000ff66, 0x1000000409); // Redo + insert_record(table, 0x0000ff67, 0x1000000505); // Menu + insert_record(table, 0x0000ff68, 0x1000000507); // Find + insert_record(table, 0x0000ff69, 0x1000000504); // Cancel + insert_record(table, 0x0000ff6a, 0x1000000508); // Help + insert_record(table, 0x0000ff7e, 0x100000070b); // Mode_switch + insert_record(table, 0x0000ff7f, 0x100000010a); // Num_Lock + insert_record(table, 0x0000ff80, 0x0000000020); // KP_Space + insert_record(table, 0x0000ff89, 0x1000000009); // KP_Tab insert_record(table, 0x0000ff8d, 0x5000000000d); // KP_Enter - insert_record(table, 0x0000ff91, 0x1000000801); // KP_F1 - insert_record(table, 0x0000ff92, 0x1000000802); // KP_F2 - insert_record(table, 0x0000ff93, 0x1000000803); // KP_F3 - insert_record(table, 0x0000ff94, 0x1000000804); // KP_F4 + insert_record(table, 0x0000ff91, 0x1000000801); // KP_F1 + insert_record(table, 0x0000ff92, 0x1000000802); // KP_F2 + insert_record(table, 0x0000ff93, 0x1000000803); // KP_F3 + insert_record(table, 0x0000ff94, 0x1000000804); // KP_F4 insert_record(table, 0x0000ff95, 0x50000000037); // KP_Home insert_record(table, 0x0000ff96, 0x50000000034); // KP_Left insert_record(table, 0x0000ff97, 0x50000000038); // KP_Up @@ -321,7 +321,7 @@ void initialize_gtk_keyval_to_logical_key(GHashTable* table) { insert_record(table, 0x0000ffaa, 0x5000000002a); // KP_Multiply insert_record(table, 0x0000ffab, 0x5000000002b); // KP_Add insert_record(table, 0x0000ffad, 0x5000000002d); // KP_Subtract - insert_record(table, 0x0000ffae, 0x000000002e); // KP_Decimal + insert_record(table, 0x0000ffae, 0x000000002e); // KP_Decimal insert_record(table, 0x0000ffaf, 0x5000000002f); // KP_Divide insert_record(table, 0x0000ffb0, 0x50000000030); // KP_0 insert_record(table, 0x0000ffb1, 0x50000000031); // KP_1 @@ -334,126 +334,124 @@ void initialize_gtk_keyval_to_logical_key(GHashTable* table) { insert_record(table, 0x0000ffb8, 0x50000000038); // KP_8 insert_record(table, 0x0000ffb9, 0x50000000039); // KP_9 insert_record(table, 0x0000ffbd, 0x5000000003d); // KP_Equal - insert_record(table, 0x0000ffbe, 0x1000000801); // F1 - insert_record(table, 0x0000ffbf, 0x1000000802); // F2 - insert_record(table, 0x0000ffc0, 0x1000000803); // F3 - insert_record(table, 0x0000ffc1, 0x1000000804); // F4 - insert_record(table, 0x0000ffc2, 0x1000000805); // F5 - insert_record(table, 0x0000ffc3, 0x1000000806); // F6 - insert_record(table, 0x0000ffc4, 0x1000000807); // F7 - insert_record(table, 0x0000ffc5, 0x1000000808); // F8 - insert_record(table, 0x0000ffc6, 0x1000000809); // F9 - insert_record(table, 0x0000ffc7, 0x100000080a); // F10 - insert_record(table, 0x0000ffc8, 0x100000080b); // F11 - insert_record(table, 0x0000ffc9, 0x100000080c); // F12 - insert_record(table, 0x0000ffca, 0x100000080d); // F13 - insert_record(table, 0x0000ffcb, 0x100000080e); // F14 - insert_record(table, 0x0000ffcc, 0x100000080f); // F15 - insert_record(table, 0x0000ffcd, 0x1000000810); // F16 - insert_record(table, 0x0000ffce, 0x1000000811); // F17 - insert_record(table, 0x0000ffcf, 0x1000000812); // F18 - insert_record(table, 0x0000ffd0, 0x1000000813); // F19 - insert_record(table, 0x0000ffd1, 0x1000000814); // F20 - insert_record(table, 0x0000ffd2, 0x1000000815); // F21 - insert_record(table, 0x0000ffd3, 0x1000000816); // F22 - insert_record(table, 0x0000ffd4, 0x1000000817); // F23 - insert_record(table, 0x0000ffd5, 0x1000000818); // F24 + insert_record(table, 0x0000ffbe, 0x1000000801); // F1 + insert_record(table, 0x0000ffbf, 0x1000000802); // F2 + insert_record(table, 0x0000ffc0, 0x1000000803); // F3 + insert_record(table, 0x0000ffc1, 0x1000000804); // F4 + insert_record(table, 0x0000ffc2, 0x1000000805); // F5 + insert_record(table, 0x0000ffc3, 0x1000000806); // F6 + insert_record(table, 0x0000ffc4, 0x1000000807); // F7 + insert_record(table, 0x0000ffc5, 0x1000000808); // F8 + insert_record(table, 0x0000ffc6, 0x1000000809); // F9 + insert_record(table, 0x0000ffc7, 0x100000080a); // F10 + insert_record(table, 0x0000ffc8, 0x100000080b); // F11 + insert_record(table, 0x0000ffc9, 0x100000080c); // F12 + insert_record(table, 0x0000ffca, 0x100000080d); // F13 + insert_record(table, 0x0000ffcb, 0x100000080e); // F14 + insert_record(table, 0x0000ffcc, 0x100000080f); // F15 + insert_record(table, 0x0000ffcd, 0x1000000810); // F16 + insert_record(table, 0x0000ffce, 0x1000000811); // F17 + insert_record(table, 0x0000ffcf, 0x1000000812); // F18 + insert_record(table, 0x0000ffd0, 0x1000000813); // F19 + insert_record(table, 0x0000ffd1, 0x1000000814); // F20 + insert_record(table, 0x0000ffd2, 0x1000000815); // F21 + insert_record(table, 0x0000ffd3, 0x1000000816); // F22 + insert_record(table, 0x0000ffd4, 0x1000000817); // F23 + insert_record(table, 0x0000ffd5, 0x1000000818); // F24 insert_record(table, 0x0000ffe1, 0x3000000010d); // Shift_L insert_record(table, 0x0000ffe2, 0x4000000010d); // Shift_R insert_record(table, 0x0000ffe3, 0x30000000105); // Control_L insert_record(table, 0x0000ffe4, 0x40000000105); // Control_R - insert_record(table, 0x0000ffe5, 0x1000000104); // Caps_Lock + insert_record(table, 0x0000ffe5, 0x1000000104); // Caps_Lock insert_record(table, 0x0000ffe7, 0x30000000109); // Meta_L insert_record(table, 0x0000ffe8, 0x40000000109); // Meta_R insert_record(table, 0x0000ffe9, 0x30000000102); // Alt_L insert_record(table, 0x0000ffea, 0x40000000102); // Alt_R - insert_record(table, 0x0000ffeb, 0x100000010e); // Super_L - insert_record(table, 0x0000ffec, 0x100000010e); // Super_R - insert_record(table, 0x0000ffed, 0x1000000108); // Hyper_L - insert_record(table, 0x0000ffee, 0x1000000108); // Hyper_R - insert_record(table, 0x0000ffff, 0x100000007f); // Delete - insert_record(table, 0x1008ff02, 0x1000000602); // MonBrightnessUp - insert_record(table, 0x1008ff03, 0x1000000601); // MonBrightnessDown - insert_record(table, 0x1008ff10, 0x100000060a); // Standby - insert_record(table, 0x1008ff11, 0x1000000a0f); // AudioLowerVolume - insert_record(table, 0x1008ff12, 0x1000000a11); // AudioMute - insert_record(table, 0x1008ff13, 0x1000000a10); // AudioRaiseVolume - insert_record(table, 0x1008ff14, 0x1000000d2f); // AudioPlay - insert_record(table, 0x1008ff15, 0x1000000a07); // AudioStop - insert_record(table, 0x1008ff16, 0x1000000a09); // AudioPrev - insert_record(table, 0x1008ff17, 0x1000000a08); // AudioNext - insert_record(table, 0x1008ff18, 0x1000000c04); // HomePage - insert_record(table, 0x1008ff19, 0x1000000b03); // Mail - insert_record(table, 0x1008ff1b, 0x1000000c06); // Search - insert_record(table, 0x1008ff1c, 0x1000000d30); // AudioRecord - insert_record(table, 0x1008ff20, 0x1000000b02); // Calendar - insert_record(table, 0x1008ff26, 0x1000000c01); // Back - insert_record(table, 0x1008ff27, 0x1000000c03); // Forward - insert_record(table, 0x1008ff28, 0x1000000c07); // Stop - insert_record(table, 0x1008ff29, 0x1000000c05); // Refresh - insert_record(table, 0x1008ff2a, 0x1000000607); // PowerOff - insert_record(table, 0x1008ff2b, 0x100000060b); // WakeUp - insert_record(table, 0x1008ff2c, 0x1000000604); // Eject - insert_record(table, 0x1008ff2d, 0x1000000b07); // ScreenSaver - insert_record(table, 0x1008ff2f, 0x1100010082); // Sleep - insert_record(table, 0x1008ff30, 0x1000000c02); // Favorites - insert_record(table, 0x1008ff31, 0x1000000d2e); // AudioPause - insert_record(table, 0x1008ff3e, 0x1000000d31); // AudioRewind - insert_record(table, 0x1008ff56, 0x1000000a01); // Close - insert_record(table, 0x1008ff57, 0x1000000402); // Copy - insert_record(table, 0x1008ff58, 0x1000000404); // Cut - insert_record(table, 0x1008ff61, 0x1000000605); // LogOff - insert_record(table, 0x1008ff68, 0x1000000a0a); // New - insert_record(table, 0x1008ff6b, 0x1000000a0b); // Open - insert_record(table, 0x1008ff6d, 0x1000000408); // Paste - insert_record(table, 0x1008ff6e, 0x1000000b0d); // Phone - insert_record(table, 0x1008ff72, 0x1000000a03); // Reply - insert_record(table, 0x1008ff77, 0x1000000a0d); // Save - insert_record(table, 0x1008ff7b, 0x1000000a04); // Send - insert_record(table, 0x1008ff7c, 0x1000000a0e); // Spell - insert_record(table, 0x1008ff8b, 0x100000050d); // ZoomIn - insert_record(table, 0x1008ff8c, 0x100000050e); // ZoomOut - insert_record(table, 0x1008ff90, 0x1000000a02); // MailForward - insert_record(table, 0x1008ff97, 0x1000000d2c); // AudioForward - insert_record(table, 0x1008ffa7, 0x1100000014); // Suspend + insert_record(table, 0x0000ffeb, 0x100000010e); // Super_L + insert_record(table, 0x0000ffec, 0x100000010e); // Super_R + insert_record(table, 0x0000ffed, 0x1000000108); // Hyper_L + insert_record(table, 0x0000ffee, 0x1000000108); // Hyper_R + insert_record(table, 0x0000ffff, 0x100000007f); // Delete + insert_record(table, 0x1008ff02, 0x1000000602); // MonBrightnessUp + insert_record(table, 0x1008ff03, 0x1000000601); // MonBrightnessDown + insert_record(table, 0x1008ff10, 0x100000060a); // Standby + insert_record(table, 0x1008ff11, 0x1000000a0f); // AudioLowerVolume + insert_record(table, 0x1008ff12, 0x1000000a11); // AudioMute + insert_record(table, 0x1008ff13, 0x1000000a10); // AudioRaiseVolume + insert_record(table, 0x1008ff14, 0x1000000d2f); // AudioPlay + insert_record(table, 0x1008ff15, 0x1000000a07); // AudioStop + insert_record(table, 0x1008ff16, 0x1000000a09); // AudioPrev + insert_record(table, 0x1008ff17, 0x1000000a08); // AudioNext + insert_record(table, 0x1008ff18, 0x1000000c04); // HomePage + insert_record(table, 0x1008ff19, 0x1000000b03); // Mail + insert_record(table, 0x1008ff1b, 0x1000000c06); // Search + insert_record(table, 0x1008ff1c, 0x1000000d30); // AudioRecord + insert_record(table, 0x1008ff20, 0x1000000b02); // Calendar + insert_record(table, 0x1008ff26, 0x1000000c01); // Back + insert_record(table, 0x1008ff27, 0x1000000c03); // Forward + insert_record(table, 0x1008ff28, 0x1000000c07); // Stop + insert_record(table, 0x1008ff29, 0x1000000c05); // Refresh + insert_record(table, 0x1008ff2a, 0x1000000607); // PowerOff + insert_record(table, 0x1008ff2b, 0x100000060b); // WakeUp + insert_record(table, 0x1008ff2c, 0x1000000604); // Eject + insert_record(table, 0x1008ff2d, 0x1000000b07); // ScreenSaver + insert_record(table, 0x1008ff2f, 0x1100010082); // Sleep + insert_record(table, 0x1008ff30, 0x1000000c02); // Favorites + insert_record(table, 0x1008ff31, 0x1000000d2e); // AudioPause + insert_record(table, 0x1008ff3e, 0x1000000d31); // AudioRewind + insert_record(table, 0x1008ff56, 0x1000000a01); // Close + insert_record(table, 0x1008ff57, 0x1000000402); // Copy + insert_record(table, 0x1008ff58, 0x1000000404); // Cut + insert_record(table, 0x1008ff61, 0x1000000605); // LogOff + insert_record(table, 0x1008ff68, 0x1000000a0a); // New + insert_record(table, 0x1008ff6b, 0x1000000a0b); // Open + insert_record(table, 0x1008ff6d, 0x1000000408); // Paste + insert_record(table, 0x1008ff6e, 0x1000000b0d); // Phone + insert_record(table, 0x1008ff72, 0x1000000a03); // Reply + insert_record(table, 0x1008ff77, 0x1000000a0d); // Save + insert_record(table, 0x1008ff7b, 0x1000000a04); // Send + insert_record(table, 0x1008ff7c, 0x1000000a0e); // Spell + insert_record(table, 0x1008ff8b, 0x100000050d); // ZoomIn + insert_record(table, 0x1008ff8c, 0x100000050e); // ZoomOut + insert_record(table, 0x1008ff90, 0x1000000a02); // MailForward + insert_record(table, 0x1008ff97, 0x1000000d2c); // AudioForward + insert_record(table, 0x1008ffa7, 0x1100000014); // Suspend } void initialize_modifier_bit_to_checked_keys(GHashTable* table) { FlKeyEmbedderCheckedKey* data; - uint64_t* physical_keys; data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_SHIFT_MASK), data); - data->primary_logical_key = 0x3000000010d; // shiftLeft - data->primary_physical_key = 0x0000700e1; // shiftLeft + data->primary_logical_key = 0x3000000010d; // shiftLeft + data->primary_physical_key = 0x0000700e1; // shiftLeft data->secondary_physical_key = 0x0000700e5; // shiftRight data->is_caps_lock = false; data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_CONTROL_MASK), data); - data->primary_logical_key = 0x30000000105; // controlLeft - data->primary_physical_key = 0x0000700e0; // controlLeft + data->primary_logical_key = 0x30000000105; // controlLeft + data->primary_physical_key = 0x0000700e0; // controlLeft data->secondary_physical_key = 0x0000700e4; // controlRight data->is_caps_lock = false; data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_MOD1_MASK), data); - data->primary_logical_key = 0x30000000102; // altLeft - data->primary_physical_key = 0x0000700e2; // altLeft + data->primary_logical_key = 0x30000000102; // altLeft + data->primary_physical_key = 0x0000700e2; // altLeft data->secondary_physical_key = 0x0000700e6; // altRight data->is_caps_lock = false; data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_MOD4_MASK), data); - data->primary_logical_key = 0x30000000109; // metaLeft - data->primary_physical_key = 0x0000700e3; // metaLeft + data->primary_logical_key = 0x30000000109; // metaLeft + data->primary_physical_key = 0x0000700e3; // metaLeft data->secondary_physical_key = 0x0000700e7; // metaRight data->is_caps_lock = false; } void initialize_lock_bit_to_checked_keys(GHashTable* table) { FlKeyEmbedderCheckedKey* data; - uint64_t* physical_keys; data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_LOCK_MASK), data); From 592632126f127f734b2e236e66689b5c60e6bea2 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 26 Apr 2021 04:57:36 -0700 Subject: [PATCH 047/126] format --- shell/platform/linux/key_mapping.cc | 284 ++++++++++++++-------------- 1 file changed, 142 insertions(+), 142 deletions(-) diff --git a/shell/platform/linux/key_mapping.cc b/shell/platform/linux/key_mapping.cc index 177b8367a22d4..5f984fde3a325 100644 --- a/shell/platform/linux/key_mapping.cc +++ b/shell/platform/linux/key_mapping.cc @@ -14,7 +14,7 @@ // flutter/flutter@dev/tools/gen_keycodes/bin/gen_keycodes.dart and should not // be edited directly. // -// Edit the template dev/tools/gen_keycodes/data/gtk_keyboard_map_cc.tmpl +// Edit the template dev/tools/gen_keycodes/data/gtk_key_mapping_cc.tmpl // instead. See dev/tools/gen_keycodes/README.md for more information. // Insert a new entry into a hashtable from uint64 to uint64. @@ -245,69 +245,69 @@ void initialize_xkb_to_physical_key(GHashTable* table) { } void initialize_gtk_keyval_to_logical_key(GHashTable* table) { - insert_record(table, 0x000000a5, 0x1100070089); // yen - insert_record(table, 0x0000fd06, 0x1000000405); // 3270_EraseEOF - insert_record(table, 0x0000fd0e, 0x1000000503); // 3270_Attn - insert_record(table, 0x0000fd15, 0x1000000402); // 3270_Copy - insert_record(table, 0x0000fd16, 0x1000000d2f); // 3270_Play - insert_record(table, 0x0000fd1b, 0x1000000406); // 3270_ExSelect - insert_record(table, 0x0000fd1d, 0x1000000608); // 3270_PrintScreen - insert_record(table, 0x0000fd1e, 0x100000000d); // 3270_Enter + insert_record(table, 0x000000a5, 0x01100070089); // yen + insert_record(table, 0x0000fd06, 0x01000000405); // 3270_EraseEOF + insert_record(table, 0x0000fd0e, 0x01000000503); // 3270_Attn + insert_record(table, 0x0000fd15, 0x01000000402); // 3270_Copy + insert_record(table, 0x0000fd16, 0x01000000d2f); // 3270_Play + insert_record(table, 0x0000fd1b, 0x01000000406); // 3270_ExSelect + insert_record(table, 0x0000fd1d, 0x01000000608); // 3270_PrintScreen + insert_record(table, 0x0000fd1e, 0x0100000000d); // 3270_Enter insert_record(table, 0x0000fe03, 0x40000000102); // ISO_Level3_Shift - insert_record(table, 0x0000fe08, 0x1000000709); // ISO_Next_Group - insert_record(table, 0x0000fe0a, 0x100000070a); // ISO_Prev_Group - insert_record(table, 0x0000fe0c, 0x1000000707); // ISO_First_Group - insert_record(table, 0x0000fe0e, 0x1000000708); // ISO_Last_Group - insert_record(table, 0x0000fe20, 0x1000000009); // ISO_Left_Tab - insert_record(table, 0x0000fe34, 0x100000000d); // ISO_Enter - insert_record(table, 0x0000ff08, 0x1000000008); // BackSpace - insert_record(table, 0x0000ff09, 0x1000000009); // Tab - insert_record(table, 0x0000ff0b, 0x1000000401); // Clear - insert_record(table, 0x0000ff0d, 0x100000000d); // Return - insert_record(table, 0x0000ff13, 0x1000000509); // Pause - insert_record(table, 0x0000ff14, 0x100000010c); // Scroll_Lock - insert_record(table, 0x0000ff1b, 0x100000001b); // Escape - insert_record(table, 0x0000ff21, 0x1000000719); // Kanji - insert_record(table, 0x0000ff24, 0x100000071b); // Romaji - insert_record(table, 0x0000ff25, 0x1000000716); // Hiragana - insert_record(table, 0x0000ff26, 0x100000071a); // Katakana - insert_record(table, 0x0000ff27, 0x1000000717); // Hiragana_Katakana - insert_record(table, 0x0000ff28, 0x100000071c); // Zenkaku - insert_record(table, 0x0000ff29, 0x1000000715); // Hankaku - insert_record(table, 0x0000ff2a, 0x100000071d); // Zenkaku_Hankaku - insert_record(table, 0x0000ff2f, 0x1000000714); // Eisu_Shift - insert_record(table, 0x0000ff31, 0x1000000711); // Hangul - insert_record(table, 0x0000ff34, 0x1000000712); // Hangul_Hanja - insert_record(table, 0x0000ff37, 0x1000000703); // Codeinput - insert_record(table, 0x0000ff3c, 0x1000000710); // SingleCandidate - insert_record(table, 0x0000ff3e, 0x100000070e); // PreviousCandidate - insert_record(table, 0x0000ff50, 0x1000000306); // Home - insert_record(table, 0x0000ff51, 0x1000000302); // Left - insert_record(table, 0x0000ff52, 0x1000000304); // Up - insert_record(table, 0x0000ff53, 0x1000000303); // Right - insert_record(table, 0x0000ff54, 0x1000000301); // Down - insert_record(table, 0x0000ff55, 0x1000000308); // Page_Up - insert_record(table, 0x0000ff56, 0x1000000307); // Page_Down - insert_record(table, 0x0000ff57, 0x1000000305); // End - insert_record(table, 0x0000ff60, 0x100000050c); // Select - insert_record(table, 0x0000ff61, 0x1000000a0c); // Print - insert_record(table, 0x0000ff62, 0x1000000506); // Execute - insert_record(table, 0x0000ff63, 0x1000000407); // Insert - insert_record(table, 0x0000ff65, 0x100000040a); // Undo - insert_record(table, 0x0000ff66, 0x1000000409); // Redo - insert_record(table, 0x0000ff67, 0x1000000505); // Menu - insert_record(table, 0x0000ff68, 0x1000000507); // Find - insert_record(table, 0x0000ff69, 0x1000000504); // Cancel - insert_record(table, 0x0000ff6a, 0x1000000508); // Help - insert_record(table, 0x0000ff7e, 0x100000070b); // Mode_switch - insert_record(table, 0x0000ff7f, 0x100000010a); // Num_Lock - insert_record(table, 0x0000ff80, 0x0000000020); // KP_Space - insert_record(table, 0x0000ff89, 0x1000000009); // KP_Tab + insert_record(table, 0x0000fe08, 0x01000000709); // ISO_Next_Group + insert_record(table, 0x0000fe0a, 0x0100000070a); // ISO_Prev_Group + insert_record(table, 0x0000fe0c, 0x01000000707); // ISO_First_Group + insert_record(table, 0x0000fe0e, 0x01000000708); // ISO_Last_Group + insert_record(table, 0x0000fe20, 0x01000000009); // ISO_Left_Tab + insert_record(table, 0x0000fe34, 0x0100000000d); // ISO_Enter + insert_record(table, 0x0000ff08, 0x01000000008); // BackSpace + insert_record(table, 0x0000ff09, 0x01000000009); // Tab + insert_record(table, 0x0000ff0b, 0x01000000401); // Clear + insert_record(table, 0x0000ff0d, 0x0100000000d); // Return + insert_record(table, 0x0000ff13, 0x01000000509); // Pause + insert_record(table, 0x0000ff14, 0x0100000010c); // Scroll_Lock + insert_record(table, 0x0000ff1b, 0x0100000001b); // Escape + insert_record(table, 0x0000ff21, 0x01000000719); // Kanji + insert_record(table, 0x0000ff24, 0x0100000071b); // Romaji + insert_record(table, 0x0000ff25, 0x01000000716); // Hiragana + insert_record(table, 0x0000ff26, 0x0100000071a); // Katakana + insert_record(table, 0x0000ff27, 0x01000000717); // Hiragana_Katakana + insert_record(table, 0x0000ff28, 0x0100000071c); // Zenkaku + insert_record(table, 0x0000ff29, 0x01000000715); // Hankaku + insert_record(table, 0x0000ff2a, 0x0100000071d); // Zenkaku_Hankaku + insert_record(table, 0x0000ff2f, 0x01000000714); // Eisu_Shift + insert_record(table, 0x0000ff31, 0x01000000711); // Hangul + insert_record(table, 0x0000ff34, 0x01000000712); // Hangul_Hanja + insert_record(table, 0x0000ff37, 0x01000000703); // Codeinput + insert_record(table, 0x0000ff3c, 0x01000000710); // SingleCandidate + insert_record(table, 0x0000ff3e, 0x0100000070e); // PreviousCandidate + insert_record(table, 0x0000ff50, 0x01000000306); // Home + insert_record(table, 0x0000ff51, 0x01000000302); // Left + insert_record(table, 0x0000ff52, 0x01000000304); // Up + insert_record(table, 0x0000ff53, 0x01000000303); // Right + insert_record(table, 0x0000ff54, 0x01000000301); // Down + insert_record(table, 0x0000ff55, 0x01000000308); // Page_Up + insert_record(table, 0x0000ff56, 0x01000000307); // Page_Down + insert_record(table, 0x0000ff57, 0x01000000305); // End + insert_record(table, 0x0000ff60, 0x0100000050c); // Select + insert_record(table, 0x0000ff61, 0x01000000a0c); // Print + insert_record(table, 0x0000ff62, 0x01000000506); // Execute + insert_record(table, 0x0000ff63, 0x01000000407); // Insert + insert_record(table, 0x0000ff65, 0x0100000040a); // Undo + insert_record(table, 0x0000ff66, 0x01000000409); // Redo + insert_record(table, 0x0000ff67, 0x01000000505); // Menu + insert_record(table, 0x0000ff68, 0x01000000507); // Find + insert_record(table, 0x0000ff69, 0x01000000504); // Cancel + insert_record(table, 0x0000ff6a, 0x01000000508); // Help + insert_record(table, 0x0000ff7e, 0x0100000070b); // Mode_switch + insert_record(table, 0x0000ff7f, 0x0100000010a); // Num_Lock + insert_record(table, 0x0000ff80, 0x00000000020); // KP_Space + insert_record(table, 0x0000ff89, 0x01000000009); // KP_Tab insert_record(table, 0x0000ff8d, 0x5000000000d); // KP_Enter - insert_record(table, 0x0000ff91, 0x1000000801); // KP_F1 - insert_record(table, 0x0000ff92, 0x1000000802); // KP_F2 - insert_record(table, 0x0000ff93, 0x1000000803); // KP_F3 - insert_record(table, 0x0000ff94, 0x1000000804); // KP_F4 + insert_record(table, 0x0000ff91, 0x01000000801); // KP_F1 + insert_record(table, 0x0000ff92, 0x01000000802); // KP_F2 + insert_record(table, 0x0000ff93, 0x01000000803); // KP_F3 + insert_record(table, 0x0000ff94, 0x01000000804); // KP_F4 insert_record(table, 0x0000ff95, 0x50000000037); // KP_Home insert_record(table, 0x0000ff96, 0x50000000034); // KP_Left insert_record(table, 0x0000ff97, 0x50000000038); // KP_Up @@ -321,7 +321,7 @@ void initialize_gtk_keyval_to_logical_key(GHashTable* table) { insert_record(table, 0x0000ffaa, 0x5000000002a); // KP_Multiply insert_record(table, 0x0000ffab, 0x5000000002b); // KP_Add insert_record(table, 0x0000ffad, 0x5000000002d); // KP_Subtract - insert_record(table, 0x0000ffae, 0x000000002e); // KP_Decimal + insert_record(table, 0x0000ffae, 0x0000000002e); // KP_Decimal insert_record(table, 0x0000ffaf, 0x5000000002f); // KP_Divide insert_record(table, 0x0000ffb0, 0x50000000030); // KP_0 insert_record(table, 0x0000ffb1, 0x50000000031); // KP_1 @@ -334,88 +334,88 @@ void initialize_gtk_keyval_to_logical_key(GHashTable* table) { insert_record(table, 0x0000ffb8, 0x50000000038); // KP_8 insert_record(table, 0x0000ffb9, 0x50000000039); // KP_9 insert_record(table, 0x0000ffbd, 0x5000000003d); // KP_Equal - insert_record(table, 0x0000ffbe, 0x1000000801); // F1 - insert_record(table, 0x0000ffbf, 0x1000000802); // F2 - insert_record(table, 0x0000ffc0, 0x1000000803); // F3 - insert_record(table, 0x0000ffc1, 0x1000000804); // F4 - insert_record(table, 0x0000ffc2, 0x1000000805); // F5 - insert_record(table, 0x0000ffc3, 0x1000000806); // F6 - insert_record(table, 0x0000ffc4, 0x1000000807); // F7 - insert_record(table, 0x0000ffc5, 0x1000000808); // F8 - insert_record(table, 0x0000ffc6, 0x1000000809); // F9 - insert_record(table, 0x0000ffc7, 0x100000080a); // F10 - insert_record(table, 0x0000ffc8, 0x100000080b); // F11 - insert_record(table, 0x0000ffc9, 0x100000080c); // F12 - insert_record(table, 0x0000ffca, 0x100000080d); // F13 - insert_record(table, 0x0000ffcb, 0x100000080e); // F14 - insert_record(table, 0x0000ffcc, 0x100000080f); // F15 - insert_record(table, 0x0000ffcd, 0x1000000810); // F16 - insert_record(table, 0x0000ffce, 0x1000000811); // F17 - insert_record(table, 0x0000ffcf, 0x1000000812); // F18 - insert_record(table, 0x0000ffd0, 0x1000000813); // F19 - insert_record(table, 0x0000ffd1, 0x1000000814); // F20 - insert_record(table, 0x0000ffd2, 0x1000000815); // F21 - insert_record(table, 0x0000ffd3, 0x1000000816); // F22 - insert_record(table, 0x0000ffd4, 0x1000000817); // F23 - insert_record(table, 0x0000ffd5, 0x1000000818); // F24 + insert_record(table, 0x0000ffbe, 0x01000000801); // F1 + insert_record(table, 0x0000ffbf, 0x01000000802); // F2 + insert_record(table, 0x0000ffc0, 0x01000000803); // F3 + insert_record(table, 0x0000ffc1, 0x01000000804); // F4 + insert_record(table, 0x0000ffc2, 0x01000000805); // F5 + insert_record(table, 0x0000ffc3, 0x01000000806); // F6 + insert_record(table, 0x0000ffc4, 0x01000000807); // F7 + insert_record(table, 0x0000ffc5, 0x01000000808); // F8 + insert_record(table, 0x0000ffc6, 0x01000000809); // F9 + insert_record(table, 0x0000ffc7, 0x0100000080a); // F10 + insert_record(table, 0x0000ffc8, 0x0100000080b); // F11 + insert_record(table, 0x0000ffc9, 0x0100000080c); // F12 + insert_record(table, 0x0000ffca, 0x0100000080d); // F13 + insert_record(table, 0x0000ffcb, 0x0100000080e); // F14 + insert_record(table, 0x0000ffcc, 0x0100000080f); // F15 + insert_record(table, 0x0000ffcd, 0x01000000810); // F16 + insert_record(table, 0x0000ffce, 0x01000000811); // F17 + insert_record(table, 0x0000ffcf, 0x01000000812); // F18 + insert_record(table, 0x0000ffd0, 0x01000000813); // F19 + insert_record(table, 0x0000ffd1, 0x01000000814); // F20 + insert_record(table, 0x0000ffd2, 0x01000000815); // F21 + insert_record(table, 0x0000ffd3, 0x01000000816); // F22 + insert_record(table, 0x0000ffd4, 0x01000000817); // F23 + insert_record(table, 0x0000ffd5, 0x01000000818); // F24 insert_record(table, 0x0000ffe1, 0x3000000010d); // Shift_L insert_record(table, 0x0000ffe2, 0x4000000010d); // Shift_R insert_record(table, 0x0000ffe3, 0x30000000105); // Control_L insert_record(table, 0x0000ffe4, 0x40000000105); // Control_R - insert_record(table, 0x0000ffe5, 0x1000000104); // Caps_Lock + insert_record(table, 0x0000ffe5, 0x01000000104); // Caps_Lock insert_record(table, 0x0000ffe7, 0x30000000109); // Meta_L insert_record(table, 0x0000ffe8, 0x40000000109); // Meta_R insert_record(table, 0x0000ffe9, 0x30000000102); // Alt_L insert_record(table, 0x0000ffea, 0x40000000102); // Alt_R - insert_record(table, 0x0000ffeb, 0x100000010e); // Super_L - insert_record(table, 0x0000ffec, 0x100000010e); // Super_R - insert_record(table, 0x0000ffed, 0x1000000108); // Hyper_L - insert_record(table, 0x0000ffee, 0x1000000108); // Hyper_R - insert_record(table, 0x0000ffff, 0x100000007f); // Delete - insert_record(table, 0x1008ff02, 0x1000000602); // MonBrightnessUp - insert_record(table, 0x1008ff03, 0x1000000601); // MonBrightnessDown - insert_record(table, 0x1008ff10, 0x100000060a); // Standby - insert_record(table, 0x1008ff11, 0x1000000a0f); // AudioLowerVolume - insert_record(table, 0x1008ff12, 0x1000000a11); // AudioMute - insert_record(table, 0x1008ff13, 0x1000000a10); // AudioRaiseVolume - insert_record(table, 0x1008ff14, 0x1000000d2f); // AudioPlay - insert_record(table, 0x1008ff15, 0x1000000a07); // AudioStop - insert_record(table, 0x1008ff16, 0x1000000a09); // AudioPrev - insert_record(table, 0x1008ff17, 0x1000000a08); // AudioNext - insert_record(table, 0x1008ff18, 0x1000000c04); // HomePage - insert_record(table, 0x1008ff19, 0x1000000b03); // Mail - insert_record(table, 0x1008ff1b, 0x1000000c06); // Search - insert_record(table, 0x1008ff1c, 0x1000000d30); // AudioRecord - insert_record(table, 0x1008ff20, 0x1000000b02); // Calendar - insert_record(table, 0x1008ff26, 0x1000000c01); // Back - insert_record(table, 0x1008ff27, 0x1000000c03); // Forward - insert_record(table, 0x1008ff28, 0x1000000c07); // Stop - insert_record(table, 0x1008ff29, 0x1000000c05); // Refresh - insert_record(table, 0x1008ff2a, 0x1000000607); // PowerOff - insert_record(table, 0x1008ff2b, 0x100000060b); // WakeUp - insert_record(table, 0x1008ff2c, 0x1000000604); // Eject - insert_record(table, 0x1008ff2d, 0x1000000b07); // ScreenSaver - insert_record(table, 0x1008ff2f, 0x1100010082); // Sleep - insert_record(table, 0x1008ff30, 0x1000000c02); // Favorites - insert_record(table, 0x1008ff31, 0x1000000d2e); // AudioPause - insert_record(table, 0x1008ff3e, 0x1000000d31); // AudioRewind - insert_record(table, 0x1008ff56, 0x1000000a01); // Close - insert_record(table, 0x1008ff57, 0x1000000402); // Copy - insert_record(table, 0x1008ff58, 0x1000000404); // Cut - insert_record(table, 0x1008ff61, 0x1000000605); // LogOff - insert_record(table, 0x1008ff68, 0x1000000a0a); // New - insert_record(table, 0x1008ff6b, 0x1000000a0b); // Open - insert_record(table, 0x1008ff6d, 0x1000000408); // Paste - insert_record(table, 0x1008ff6e, 0x1000000b0d); // Phone - insert_record(table, 0x1008ff72, 0x1000000a03); // Reply - insert_record(table, 0x1008ff77, 0x1000000a0d); // Save - insert_record(table, 0x1008ff7b, 0x1000000a04); // Send - insert_record(table, 0x1008ff7c, 0x1000000a0e); // Spell - insert_record(table, 0x1008ff8b, 0x100000050d); // ZoomIn - insert_record(table, 0x1008ff8c, 0x100000050e); // ZoomOut - insert_record(table, 0x1008ff90, 0x1000000a02); // MailForward - insert_record(table, 0x1008ff97, 0x1000000d2c); // AudioForward - insert_record(table, 0x1008ffa7, 0x1100000014); // Suspend + insert_record(table, 0x0000ffeb, 0x0100000010e); // Super_L + insert_record(table, 0x0000ffec, 0x0100000010e); // Super_R + insert_record(table, 0x0000ffed, 0x01000000108); // Hyper_L + insert_record(table, 0x0000ffee, 0x01000000108); // Hyper_R + insert_record(table, 0x0000ffff, 0x0100000007f); // Delete + insert_record(table, 0x1008ff02, 0x01000000602); // MonBrightnessUp + insert_record(table, 0x1008ff03, 0x01000000601); // MonBrightnessDown + insert_record(table, 0x1008ff10, 0x0100000060a); // Standby + insert_record(table, 0x1008ff11, 0x01000000a0f); // AudioLowerVolume + insert_record(table, 0x1008ff12, 0x01000000a11); // AudioMute + insert_record(table, 0x1008ff13, 0x01000000a10); // AudioRaiseVolume + insert_record(table, 0x1008ff14, 0x01000000d2f); // AudioPlay + insert_record(table, 0x1008ff15, 0x01000000a07); // AudioStop + insert_record(table, 0x1008ff16, 0x01000000a09); // AudioPrev + insert_record(table, 0x1008ff17, 0x01000000a08); // AudioNext + insert_record(table, 0x1008ff18, 0x01000000c04); // HomePage + insert_record(table, 0x1008ff19, 0x01000000b03); // Mail + insert_record(table, 0x1008ff1b, 0x01000000c06); // Search + insert_record(table, 0x1008ff1c, 0x01000000d30); // AudioRecord + insert_record(table, 0x1008ff20, 0x01000000b02); // Calendar + insert_record(table, 0x1008ff26, 0x01000000c01); // Back + insert_record(table, 0x1008ff27, 0x01000000c03); // Forward + insert_record(table, 0x1008ff28, 0x01000000c07); // Stop + insert_record(table, 0x1008ff29, 0x01000000c05); // Refresh + insert_record(table, 0x1008ff2a, 0x01000000607); // PowerOff + insert_record(table, 0x1008ff2b, 0x0100000060b); // WakeUp + insert_record(table, 0x1008ff2c, 0x01000000604); // Eject + insert_record(table, 0x1008ff2d, 0x01000000b07); // ScreenSaver + insert_record(table, 0x1008ff2f, 0x01100010082); // Sleep + insert_record(table, 0x1008ff30, 0x01000000c02); // Favorites + insert_record(table, 0x1008ff31, 0x01000000d2e); // AudioPause + insert_record(table, 0x1008ff3e, 0x01000000d31); // AudioRewind + insert_record(table, 0x1008ff56, 0x01000000a01); // Close + insert_record(table, 0x1008ff57, 0x01000000402); // Copy + insert_record(table, 0x1008ff58, 0x01000000404); // Cut + insert_record(table, 0x1008ff61, 0x01000000605); // LogOff + insert_record(table, 0x1008ff68, 0x01000000a0a); // New + insert_record(table, 0x1008ff6b, 0x01000000a0b); // Open + insert_record(table, 0x1008ff6d, 0x01000000408); // Paste + insert_record(table, 0x1008ff6e, 0x01000000b0d); // Phone + insert_record(table, 0x1008ff72, 0x01000000a03); // Reply + insert_record(table, 0x1008ff77, 0x01000000a0d); // Save + insert_record(table, 0x1008ff7b, 0x01000000a04); // Send + insert_record(table, 0x1008ff7c, 0x01000000a0e); // Spell + insert_record(table, 0x1008ff8b, 0x0100000050d); // ZoomIn + insert_record(table, 0x1008ff8c, 0x0100000050e); // ZoomOut + insert_record(table, 0x1008ff90, 0x01000000a02); // MailForward + insert_record(table, 0x1008ff97, 0x01000000d2c); // AudioForward + insert_record(table, 0x1008ffa7, 0x01100000014); // Suspend } void initialize_modifier_bit_to_checked_keys(GHashTable* table) { @@ -450,18 +450,18 @@ void initialize_modifier_bit_to_checked_keys(GHashTable* table) { data->is_caps_lock = false; } -void initialize_lock_bit_to_checked_keys(GHashTable* table) { +void initialize_lock_mode_bit_to_checked_keys(GHashTable* table) { FlKeyEmbedderCheckedKey* data; data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_LOCK_MASK), data); - data->primary_logical_key = 0x1000000104; // capsLock - data->primary_physical_key = 0x000070039; // capsLock + data->primary_logical_key = 0x01000000104; // capsLock + data->primary_physical_key = 0x000070039; // capsLock data->is_caps_lock = true; data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_MOD2_MASK), data); - data->primary_logical_key = 0x100000010a; // numLock - data->primary_physical_key = 0x000070053; // numLock + data->primary_logical_key = 0x0100000010a; // numLock + data->primary_physical_key = 0x000070053; // numLock data->is_caps_lock = false; } From 2ad57dddb05e4aed033d710136fc52112ba4a97b Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 26 Apr 2021 06:17:34 -0700 Subject: [PATCH 048/126] Docs --- .../linux/fl_key_channel_responder.cc | 82 ++++--- .../linux/fl_key_embedder_responder.cc | 213 ++++++++++-------- shell/platform/linux/fl_keyboard_manager.cc | 211 +++++++++-------- shell/platform/linux/key_mapping.cc | 2 +- 4 files changed, 293 insertions(+), 215 deletions(-) diff --git a/shell/platform/linux/fl_key_channel_responder.cc b/shell/platform/linux/fl_key_channel_responder.cc index 1b2c123fa766e..019aba26e8820 100644 --- a/shell/platform/linux/fl_key_channel_responder.cc +++ b/shell/platform/linux/fl_key_channel_responder.cc @@ -24,37 +24,13 @@ static constexpr char kUnicodeScalarValuesKey[] = "unicodeScalarValues"; static constexpr char kGtkToolkit[] = "gtk"; static constexpr char kLinuxKeymap[] = "linux"; -// Definition of the FlKeyChannelResponder GObject class. - -struct _FlKeyChannelResponder { - GObject parent_instance; - - FlBasicMessageChannel* channel; - - FlKeyChannelResponderMock* mock; -}; - -static void fl_key_channel_responder_iface_init(FlKeyResponderInterface* iface); - -G_DEFINE_TYPE_WITH_CODE( - FlKeyChannelResponder, - fl_key_channel_responder, - G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE(FL_TYPE_KEY_RESPONDER, - fl_key_channel_responder_iface_init)) +/* Declare and define FlKeyChannelUserData */ -static void fl_key_channel_responder_handle_event( - FlKeyResponder* responder, - GdkEventKey* event, - FlKeyResponderAsyncCallback callback, - gpointer user_data); - -static void fl_key_channel_responder_iface_init( - FlKeyResponderInterface* iface) { - iface->handle_event = fl_key_channel_responder_handle_event; -} - -// Declare and define a private class to hold response data from the framework. +/** + * FlKeyChannelUserData: + * The user_data used when #FlKeyChannelResponder sends message through the + * channel. + */ G_DECLARE_FINAL_TYPE(FlKeyChannelUserData, fl_key_channel_user_data, FL, @@ -64,8 +40,11 @@ G_DECLARE_FINAL_TYPE(FlKeyChannelUserData, struct _FlKeyChannelUserData { GObject parent_instance; + // The current responder. FlKeyChannelResponder* responder; + // The callback provided by the caller #FlKeyboardManager. FlKeyResponderAsyncCallback callback; + // The user_data provided by the caller #FlKeyboardManager. gpointer user_data; }; @@ -93,9 +72,9 @@ static void fl_key_channel_user_data_class_init( // Instance initialization method for FlKeyChannelUserData private class. static void fl_key_channel_user_data_init(FlKeyChannelUserData* self) {} -// Creates a new FlKeyChannelUserData private class with a responder that -// created the request, a unique ID for tracking, and optional user data. Will -// keep a weak pointer to the responder. +// Creates a new FlKeyChannelUserData private class with all information. +// +// The callback and the user_data might be nullptr. static FlKeyChannelUserData* fl_key_channel_user_data_new( FlKeyChannelResponder* responder, FlKeyResponderAsyncCallback callback, @@ -113,8 +92,41 @@ static FlKeyChannelUserData* fl_key_channel_user_data_new( return self; } -// Handles a response from the framework to a key event sent to the framework -// earlier. +/* Define FlKeyChannelResponder */ + +// Definition of the FlKeyChannelResponder GObject class. +struct _FlKeyChannelResponder { + GObject parent_instance; + + FlBasicMessageChannel* channel; + + FlKeyChannelResponderMock* mock; +}; + +static void fl_key_channel_responder_iface_init(FlKeyResponderInterface* iface); + +G_DEFINE_TYPE_WITH_CODE( + FlKeyChannelResponder, + fl_key_channel_responder, + G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE(FL_TYPE_KEY_RESPONDER, + fl_key_channel_responder_iface_init)) + +static void fl_key_channel_responder_handle_event( + FlKeyResponder* responder, + GdkEventKey* event, + FlKeyResponderAsyncCallback callback, + gpointer user_data); + +static void fl_key_channel_responder_iface_init( + FlKeyResponderInterface* iface) { + iface->handle_event = fl_key_channel_responder_handle_event; +} + +/* Implement FlKeyChannelResponder */ + +// Handles a response from the method channel to a key event sent to the +// framework earlier. static void handle_response(GObject* object, GAsyncResult* result, gpointer user_data) { diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index 69066f475c2b4..69297c1ce8cad 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -12,19 +12,57 @@ #include "flutter/shell/platform/linux/fl_key_embedder_responder_private.h" #include "flutter/shell/platform/linux/key_mapping.h" -namespace { +// The code prefix for unrecognized keys that are unique to Gtk, generated from +// platform-specific codes. +constexpr uint64_t kGtkKeyIdPlane = 0x00600000000; -const uint64_t kAutogeneratedMask = 0x10000000000; +constexpr uint64_t kMicrosecondsPerMillisecond = 1000; -/** - * The code prefix for keys from Linux which do not have a Unicode - * representation. - */ -constexpr uint64_t kLinuxKeyIdPlane = 0x00600000000; +static uint64_t lookup_hash_table(GHashTable* table, uint64_t key) { + return gpointer_to_uint64( + g_hash_table_lookup(table, uint64_to_gpointer(key))); +} -constexpr uint64_t kMicrosecondsPerMillisecond = 1000; +static uint64_t event_to_physical_key(const GdkEventKey* event, + GHashTable* table) { + uint64_t record = lookup_hash_table(table, event->hardware_keycode); + if (record != 0) { + return record; + } + return kGtkKeyIdPlane | event->hardware_keycode; +} + +static uint64_t to_lower(uint64_t n) { + constexpr uint64_t lower_a = 0x61; + constexpr uint64_t upper_a = 0x41; + constexpr uint64_t upper_z = 0x5a; + + constexpr uint64_t lower_a_grave = 0xe0; + constexpr uint64_t upper_a_grave = 0xc0; + constexpr uint64_t upper_thorn = 0xde; + constexpr uint64_t division = 0xf7; + + // ASCII range. + if (n >= upper_a && n <= upper_z) { + return n - upper_a + lower_a; + } -// Declare and define a private class to hold response data from the framework. + // EASCII range. + if (n >= upper_a_grave && n <= upper_thorn && n != division) { + return n - upper_a_grave + lower_a_grave; + } + + return n; +} + +/* Define FlKeyEmbedderUserData */ + +/** + * FlKeyEmbedderUserData: + * The user_data used when #FlKeyEmbedderResponder sends message through the + * embedder.SendKeyEvent API. + */ +#define FL_TYPE_EMBEDDER_USER_DATA fl_key_embedder_user_data_get_type() G_DECLARE_FINAL_TYPE(FlKeyEmbedderUserData, fl_key_embedder_user_data, FL, @@ -39,10 +77,17 @@ struct _FlKeyEmbedderUserData { gpointer user_data; }; -// Definition for FlKeyEmbedderUserData private class. G_DEFINE_TYPE(FlKeyEmbedderUserData, fl_key_embedder_user_data, G_TYPE_OBJECT) -// Dispose method for FlKeyEmbedderUserData private class. +static void fl_key_embedder_user_data_dispose(GObject* object); + +static void fl_key_embedder_user_data_class_init( + FlKeyEmbedderUserDataClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_key_embedder_user_data_dispose; +} + +static void fl_key_embedder_user_data_init(FlKeyEmbedderUserData* self) {} + static void fl_key_embedder_user_data_dispose(GObject* object) { g_return_if_fail(FL_IS_KEY_EMBEDDER_USER_DATA(object)); FlKeyEmbedderUserData* self = FL_KEY_EMBEDDER_USER_DATA(object); @@ -54,24 +99,15 @@ static void fl_key_embedder_user_data_dispose(GObject* object) { } } -// Class initialization method for FlKeyEmbedderUserData private class. -static void fl_key_embedder_user_data_class_init( - FlKeyEmbedderUserDataClass* klass) { - G_OBJECT_CLASS(klass)->dispose = fl_key_embedder_user_data_dispose; -} - -// Instance initialization method for FlKeyEmbedderUserData private class. -static void fl_key_embedder_user_data_init(FlKeyEmbedderUserData* self) {} - -// Creates a new FlKeyEmbedderUserData private class with a responder that -// created the request, a unique ID for tracking, and optional user data. Will -// keep a weak pointer to the responder. +// Creates a new FlKeyChannelUserData private class with all information. +// +// The callback and the user_data might be nullptr. static FlKeyEmbedderUserData* fl_key_embedder_user_data_new( FlKeyEmbedderResponder* responder, FlKeyResponderAsyncCallback callback, gpointer user_data) { FlKeyEmbedderUserData* self = FL_KEY_EMBEDDER_USER_DATA( - g_object_new(fl_key_embedder_user_data_get_type(), nullptr)); + g_object_new(FL_TYPE_EMBEDDER_USER_DATA, nullptr)); self->responder = responder; // Add a weak pointer so we can know if the key event responder disappeared @@ -83,37 +119,67 @@ static FlKeyEmbedderUserData* fl_key_embedder_user_data_new( return self; } -} // namespace +/* Define FlKeyEmbedderResponder */ struct _FlKeyEmbedderResponder { GObject parent_instance; + // A weak pointer to the engine the responder is attached to. FlEngine* engine; - // Stores pressed keys, mapping their Flutter physical key to Flutter logical - // key. + // Internal record for states of whether a key is pressed. // - // Both keys and values are directly stored uint64s. + // It is a map from Flutter physical key to Flutter logical key. Both keys + // and values are directly stored uint64s. This table is freed by the + // responder. GHashTable* pressing_records; + // Internal record for states of whether a lock mode is enabled. + // + // It is a bit mask composed of GTK mode bits. guint lock_records; - // A static map from XKB to Flutter's physical key code + // A static map from XKB code to Flutter's physical key code. + // + // Both keys and values are directly stored uint64s. This table is freed by + // the responder. GHashTable* xkb_to_physical_key; // A static map from GTK keyval to Flutter's logical key code + // + // Both keys and values are directly stored uint64s. This table is freed by + // the responder. GHashTable* keyval_to_logical_key; + // A static map from GTK modifier bits to #FlKeyEmbedderCheckedKey to + // configure the modifier keys that needs to be tracked and kept synchronous + // on. + // + // The keys are directly stored guints. The values must be freed with g_free. + // This table is freed by the responder. GHashTable* modifier_bit_to_checked_keys; + // A static map from GTK modifier bits to #FlKeyEmbedderCheckedKey to + // configure the lock mode bits that needs to be tracked and kept synchronous + // on. + // + // The keys are directly stored guints. The values must be freed with g_free. + // This table is freed by the responder. GHashTable* lock_bit_to_checked_keys; + // A static map generated by reverse mapping lock_bit_to_checked_keys. + // + // It is a map from primary physical keys to lock bits. Both keys and values + // are directly stored uint64s. This table is freed by the responder. GHashTable* physical_key_to_lock_bit; }; static void fl_key_embedder_responder_iface_init( FlKeyResponderInterface* iface); +static void fl_key_embedder_responder_dispose(GObject* object); +#define FL_TYPE_EMBEDDER_RESPONDER_USER_DATA \ + fl_key_embedder_responder_get_type() G_DEFINE_TYPE_WITH_CODE( FlKeyEmbedderResponder, fl_key_embedder_responder, @@ -132,6 +198,15 @@ static void fl_key_embedder_responder_iface_init( iface->handle_event = fl_key_embedder_responder_handle_event; } +// Initializes the FlKeyEmbedderResponder class methods. +static void fl_key_embedder_responder_class_init( + FlKeyEmbedderResponderClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_key_embedder_responder_dispose; +} + +// Initializes an FlKeyEmbedderResponder instance. +static void fl_key_embedder_responder_init(FlKeyEmbedderResponder* self) {} + // Disposes of an FlKeyEmbedderResponder instance. static void fl_key_embedder_responder_dispose(GObject* object) { FlKeyEmbedderResponder* self = FL_KEY_EMBEDDER_RESPONDER(object); @@ -145,15 +220,6 @@ static void fl_key_embedder_responder_dispose(GObject* object) { G_OBJECT_CLASS(fl_key_embedder_responder_parent_class)->dispose(object); } -// Initializes the FlKeyEmbedderResponder class methods. -static void fl_key_embedder_responder_class_init( - FlKeyEmbedderResponderClass* klass) { - G_OBJECT_CLASS(klass)->dispose = fl_key_embedder_responder_dispose; -} - -// Initializes an FlKeyEmbedderResponder instance. -static void fl_key_embedder_responder_init(FlKeyEmbedderResponder* self) {} - static void initialize_physical_key_to_lock_bit_loop_body(gpointer lock_bit, gpointer value, gpointer user_data) { @@ -174,7 +240,7 @@ FlKeyEmbedderResponder* fl_key_embedder_responder_new(FlEngine* engine) { g_return_val_if_fail(FL_IS_ENGINE(engine), nullptr); FlKeyEmbedderResponder* self = FL_KEY_EMBEDDER_RESPONDER( - g_object_new(fl_key_embedder_responder_get_type(), nullptr)); + g_object_new(FL_TYPE_EMBEDDER_RESPONDER_USER_DATA, nullptr)); self->engine = engine; // Add a weak pointer so we can know if the key event responder disappeared @@ -208,41 +274,7 @@ FlKeyEmbedderResponder* fl_key_embedder_responder_new(FlEngine* engine) { return self; } -static uint64_t lookup_hash_table(GHashTable* table, uint64_t key) { - return gpointer_to_uint64( - g_hash_table_lookup(table, uint64_to_gpointer(key))); -} - -static uint64_t event_to_physical_key(const GdkEventKey* event, - GHashTable* table) { - uint64_t record = lookup_hash_table(table, event->hardware_keycode); - if (record != 0) { - return record; - } - // Auto-generate key - return kAutogeneratedMask | kLinuxKeyIdPlane | event->hardware_keycode; -} - -static uint64_t to_lower(uint64_t n) { - constexpr uint64_t lower_a = 0x61; - constexpr uint64_t upper_a = 0x41; - constexpr uint64_t upper_z = 0x5a; - - constexpr uint64_t lower_a_grave = 0xe0; - constexpr uint64_t upper_a_grave = 0xc0; - constexpr uint64_t upper_thorn = 0xde; - constexpr uint64_t division = 0xf7; - - if (n >= upper_a && n <= upper_z) { - return n - upper_a + lower_a; - } - - if (n >= upper_a_grave && n <= upper_thorn && n != division) { - return n - upper_a_grave + lower_a_grave; - } - - return n; -} +/* Implement FlKeyEmbedderUserData */ static uint64_t event_to_logical_key(const GdkEventKey* event, GHashTable* table) { @@ -256,7 +288,7 @@ static uint64_t event_to_logical_key(const GdkEventKey* event, return to_lower(keyval); } // Auto-generate key - return kAutogeneratedMask | kLinuxKeyIdPlane | keyval; + return kGtkKeyIdPlane | keyval; } static uint64_t event_to_timestamp(const GdkEventKey* event) { @@ -277,7 +309,7 @@ static char* event_to_character(const GdkEventKey* event) { return result; } -// Handles a response from the framework to a key event sent to the framework +// Handles a response from the embedder API to a key event sent to the framework // earlier. static void handle_response(bool handled, gpointer user_data) { g_autoptr(FlKeyEmbedderUserData) data = FL_KEY_EMBEDDER_USER_DATA(user_data); @@ -295,6 +327,7 @@ static void handle_response(bool handled, gpointer user_data) { data->callback(handled, data->user_data); } +// Sends a synthesized event to the engine with no demand for callback. static void synthesize_simple_event(FlKeyEmbedderResponder* self, FlutterKeyEventType type, uint64_t physical, @@ -312,20 +345,25 @@ static void synthesize_simple_event(FlKeyEmbedderResponder* self, } namespace { + +// Context variables for the foreach call used to synchronize pressing states +// and lock states. typedef struct { FlKeyEmbedderResponder* self; guint state; uint64_t event_physical_key; bool is_down; double timestamp; -} SyncPressedStatesLoopContext; +} SyncStateLoopContext; + } // namespace +// The loop body to synchronize pressing states. static void synchronize_pressed_states_loop_body(gpointer key, gpointer value, gpointer user_data) { - SyncPressedStatesLoopContext* context = - reinterpret_cast(user_data); + SyncStateLoopContext* context = + reinterpret_cast(user_data); FlKeyEmbedderCheckedKey* checked_key = reinterpret_cast(value); @@ -462,11 +500,12 @@ static void possibly_update_lock_bit(FlKeyEmbedderResponder* self, } } +// The loop body to synchronize lock states. static void synchronize_lock_states_loop_body(gpointer key, gpointer value, gpointer user_data) { - SyncPressedStatesLoopContext* context = - reinterpret_cast(user_data); + SyncStateLoopContext* context = + reinterpret_cast(user_data); FlKeyEmbedderCheckedKey* checked_key = reinterpret_cast(value); @@ -545,8 +584,6 @@ static void synchronize_lock_states_loop_body(gpointer key, } } -static int _text_idx = 0; - // Sends a key event to the framework. static void fl_key_embedder_responder_handle_event( FlKeyResponder* responder, @@ -554,7 +591,6 @@ static void fl_key_embedder_responder_handle_event( FlKeyResponderAsyncCallback callback, gpointer user_data) { FlKeyEmbedderResponder* self = FL_KEY_EMBEDDER_RESPONDER(responder); - _text_idx += 1; g_return_if_fail(event != nullptr); g_return_if_fail(callback != nullptr); @@ -568,14 +604,14 @@ static void fl_key_embedder_responder_handle_event( printf( "#%7s keyval 0x%x keycode 0x%x state 0x%x ismod %d snd %d grp %d " - "time %d [%d] curLock %x PhK %lx\n", + "time %d curLock %x PhK %lx\n", event->type == GDK_KEY_PRESS ? "PRESS" : "RELEASE", event->keyval, event->hardware_keycode, event->state, event->is_modifier, - event->send_event, event->group, event->time, _text_idx, - self->lock_records, physical_key); + event->send_event, event->group, event->time, self->lock_records, + physical_key); fflush(stdout); - SyncPressedStatesLoopContext sync_pressed_state_context; + SyncStateLoopContext sync_pressed_state_context; sync_pressed_state_context.self = self; sync_pressed_state_context.state = event->state; sync_pressed_state_context.timestamp = timestamp; @@ -638,5 +674,4 @@ static void fl_key_embedder_responder_handle_event( fl_engine_send_key_event(self->engine, &out_event, handle_response, response_data); - fflush(stdout); } diff --git a/shell/platform/linux/fl_keyboard_manager.cc b/shell/platform/linux/fl_keyboard_manager.cc index cb7b7019e4ae1..aff6804911210 100644 --- a/shell/platform/linux/fl_keyboard_manager.cc +++ b/shell/platform/linux/fl_keyboard_manager.cc @@ -6,73 +6,16 @@ #include -// Declare and define a private class to hold response data from the framework. -#define FL_TYPE_KEYBOARD_MANAGER_USER_DATA \ - fl_keyboard_manager_user_data_get_type() -G_DECLARE_FINAL_TYPE(FlKeyboardManagerUserData, - fl_keyboard_manager_user_data, - FL, - KEYBOARD_MANAGER_USER_DATA, - GObject); - -struct _FlKeyboardManagerUserData { - GObject parent_instance; - - FlKeyboardManager* manager; - uint64_t sequence_id; -}; - -namespace { -typedef struct { - GdkEventKey* event; - FlKeyboardManagerUserData* user_data; -} DispatchPendingToResponderForeachData; -} // namespace - -// Definition for FlKeyboardManagerUserData private class. -G_DEFINE_TYPE(FlKeyboardManagerUserData, - fl_keyboard_manager_user_data, - G_TYPE_OBJECT) - -// Dispose method for FlKeyboardManagerUserData private class. -static void fl_keyboard_manager_user_data_dispose(GObject* object) { - g_return_if_fail(FL_IS_KEYBOARD_MANAGER_USER_DATA(object)); - FlKeyboardManagerUserData* self = FL_KEYBOARD_MANAGER_USER_DATA(object); - if (self->manager != nullptr) { - g_object_remove_weak_pointer(G_OBJECT(self->manager), - reinterpret_cast(&(self->manager))); - self->manager = nullptr; - } -} - -// Class initialization method for FlKeyboardManagerUserData private class. -static void fl_keyboard_manager_user_data_class_init( - FlKeyboardManagerUserDataClass* klass) { - G_OBJECT_CLASS(klass)->dispose = fl_keyboard_manager_user_data_dispose; -} - -// Instance initialization method for FlKeyboardManagerUserData private class. -static void fl_keyboard_manager_user_data_init( - FlKeyboardManagerUserData* self) {} - -// Creates a new FlKeyboardManagerUserData private class with a responder that -// created the request, a unique ID for tracking, and optional user data. Will -// keep a weak pointer to the responder. -FlKeyboardManagerUserData* fl_keyboard_manager_user_data_new( - FlKeyboardManager* manager, - uint64_t sequence_id) { - FlKeyboardManagerUserData* self = FL_KEYBOARD_MANAGER_USER_DATA( - g_object_new(fl_keyboard_manager_user_data_get_type(), nullptr)); - - self->manager = manager; - // Add a weak pointer so we can know if the key event responder disappeared - // while the framework was responding. - g_object_add_weak_pointer(G_OBJECT(manager), - reinterpret_cast(&(self->manager))); - self->sequence_id = sequence_id; - return self; -} - +/* Declare and define FlKeyboardPendingEvent */ + +/** + * FlKeyboardPendingEvent: + * A record for events that have been received by the manager, but + * dispatched to other objects, whose results have yet to return. + * + * This object is used by both the "pending_responds" list and the + * "pending_redispatches" list. + */ G_DECLARE_FINAL_TYPE(FlKeyboardPendingEvent, fl_keyboard_pending_event, FL, @@ -82,9 +25,14 @@ G_DECLARE_FINAL_TYPE(FlKeyboardPendingEvent, struct _FlKeyboardPendingEvent { GObject parent_instance; + // A clone of the target event. + // + // This is freed by #FlKeyboardPendingEvent. GdkEventKey* event; // Self-incrementing ID attached to an event sent to the framework. + // + // Used to identify pending responds. uint64_t sequence_id; // The number of responders that haven't replied. size_t unreplied; @@ -98,7 +46,6 @@ struct _FlKeyboardPendingEvent { G_DEFINE_TYPE(FlKeyboardPendingEvent, fl_keyboard_pending_event, G_TYPE_OBJECT) -// Dispose method for FlKeyboardPendingEvent. static void fl_keyboard_pending_event_dispose(GObject* object) { // Redundant, but added so that we don't get a warning about unused function // for FL_IS_KEYBOARD_PENDING_EVENT. @@ -109,13 +56,11 @@ static void fl_keyboard_pending_event_dispose(GObject* object) { G_OBJECT_CLASS(fl_keyboard_pending_event_parent_class)->dispose(object); } -// Class Initialization method for FlKeyboardPendingEvent class. static void fl_keyboard_pending_event_class_init( FlKeyboardPendingEventClass* klass) { G_OBJECT_CLASS(klass)->dispose = fl_keyboard_pending_event_dispose; } -// Initialization for FlKeyboardPendingEvent instances. static void fl_keyboard_pending_event_init(FlKeyboardPendingEvent* self) {} // Calculates a unique ID for a given GdkEventKey object to use for @@ -130,6 +75,8 @@ static uint64_t fl_keyboard_manager_get_event_hash(GdkEventKey* event) { (static_cast(event->hardware_keycode) & 0xffff) << 48; } +// Create a new FlKeyboardPendingEvent by providing the target event, +// the sequence ID, and the number of responders that will reply. FlKeyboardPendingEvent* fl_keyboard_pending_event_new(GdkEventKey* event, uint64_t sequence_id, size_t to_reply) { @@ -148,17 +95,93 @@ FlKeyboardPendingEvent* fl_keyboard_pending_event_new(GdkEventKey* event, self->unreplied = to_reply; self->any_handled = false; self->hash = fl_keyboard_manager_get_event_hash(event); - // FlKeyboardPendingEvent* self2 = FL_KEYBOARD_PENDING_EVENT(self); return self2; } +/* Declare and define FlKeyboardManagerUserData */ + +/** + * FlKeyEmbedderUserData: + * The user_data used when #FlKeyboardManagerUserData sends event to + * responders. + */ +#define FL_TYPE_KEYBOARD_MANAGER_USER_DATA \ + fl_keyboard_manager_user_data_get_type() +G_DECLARE_FINAL_TYPE(FlKeyboardManagerUserData, + fl_keyboard_manager_user_data, + FL, + KEYBOARD_MANAGER_USER_DATA, + GObject); + +struct _FlKeyboardManagerUserData { + GObject parent_instance; + + // A weak reference to the owner manager. + FlKeyboardManager* manager; + uint64_t sequence_id; +}; + +namespace { + +// Context variables for the foreach call used to dispatch events to responders. +typedef struct { + GdkEventKey* event; + FlKeyboardManagerUserData* user_data; +} DispatchToResponderLoopContext; + +} // namespace + +G_DEFINE_TYPE(FlKeyboardManagerUserData, + fl_keyboard_manager_user_data, + G_TYPE_OBJECT) + +static void fl_keyboard_manager_user_data_dispose(GObject* object) { + g_return_if_fail(FL_IS_KEYBOARD_MANAGER_USER_DATA(object)); + FlKeyboardManagerUserData* self = FL_KEYBOARD_MANAGER_USER_DATA(object); + if (self->manager != nullptr) { + g_object_remove_weak_pointer(G_OBJECT(self->manager), + reinterpret_cast(&(self->manager))); + self->manager = nullptr; + } +} + +static void fl_keyboard_manager_user_data_class_init( + FlKeyboardManagerUserDataClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_keyboard_manager_user_data_dispose; +} + +static void fl_keyboard_manager_user_data_init( + FlKeyboardManagerUserData* self) {} + +// Creates a new FlKeyboardManagerUserData private class with all information. +FlKeyboardManagerUserData* fl_keyboard_manager_user_data_new( + FlKeyboardManager* manager, + uint64_t sequence_id) { + FlKeyboardManagerUserData* self = FL_KEYBOARD_MANAGER_USER_DATA( + g_object_new(fl_keyboard_manager_user_data_get_type(), nullptr)); + + self->manager = manager; + // Add a weak pointer so we can know if the key event responder disappeared + // while the framework was responding. + g_object_add_weak_pointer(G_OBJECT(manager), + reinterpret_cast(&(self->manager))); + self->sequence_id = sequence_id; + return self; +} + +/* Define FlKeyboardManager */ + struct _FlKeyboardManager { GObject parent_instance; + // The callback that unhandled events should be redispatched through. FlKeyboardManagerRedispatcher redispatch_callback; - // A text plugin. Automatially released on dispose. + // A text plugin. + // + // Released by the manager on dispose. FlTextInputPlugin* text_input_plugin; + // An array of #FlKeyResponder. Elements are added with // #fl_keyboard_manager_add_responder immediately after initialization and are // automatically released on dispose. @@ -168,16 +191,25 @@ struct _FlKeyboardManager { // release the elements unless it is transferring them to // pending_redispatches. GPtrArray* pending_responds; + // An array of #FlKeyboardPendingEvent. FlKeyboardManager must manually // release the elements. GPtrArray* pending_redispatches; + // The last sequence ID used. Increased by 1 by every use. uint64_t last_sequence_id; }; G_DEFINE_TYPE(FlKeyboardManager, fl_keyboard_manager, G_TYPE_OBJECT); -// Disposes of an FlKeyboardManager instance. +static void fl_keyboard_manager_dispose(GObject* object); + +static void fl_keyboard_manager_class_init(FlKeyboardManagerClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_keyboard_manager_dispose; +} + +static void fl_keyboard_manager_init(FlKeyboardManager* self) {} + static void fl_keyboard_manager_dispose(GObject* object) { FlKeyboardManager* self = FL_KEYBOARD_MANAGER(object); @@ -192,14 +224,9 @@ static void fl_keyboard_manager_dispose(GObject* object) { G_OBJECT_CLASS(fl_keyboard_manager_parent_class)->dispose(object); } -// Initializes the FlKeyboardManager class methods. -static void fl_keyboard_manager_class_init(FlKeyboardManagerClass* klass) { - G_OBJECT_CLASS(klass)->dispose = fl_keyboard_manager_dispose; -} - -static void fl_keyboard_manager_init(FlKeyboardManager* self) {} +/* Implement FlKeyboardManager */ -// Compare a #FlKeyboardPendingEvent with the given sequence_id. The #needle +// Compare a #FlKeyboardPendingEvent with the given sequence_id. The needle // should be a pointer to uint64_t sequence_id. static gboolean compare_pending_by_sequence_id( gconstpointer pending, @@ -217,6 +244,10 @@ static gboolean compare_pending_by_hash(gconstpointer pending, return static_cast(pending)->hash == hash; } +// Try to remove a pending event from `pending_redispatches` with the target +// hash. +// +// Returns true if the event is found and removed. static bool fl_keyboard_manager_remove_redispatched(FlKeyboardManager* self, uint64_t hash) { guint result_index; @@ -234,6 +265,7 @@ static bool fl_keyboard_manager_remove_redispatched(FlKeyboardManager* self, } } +// The callback used by a responder after the event was dispatched. static void responder_handle_event_callback(bool handled, gpointer user_data_ptr) { g_return_if_fail(FL_IS_KEYBOARD_MANAGER_USER_DATA(user_data_ptr)); @@ -306,15 +338,15 @@ void fl_keyboard_manager_add_responder(FlKeyboardManager* self, g_ptr_array_add(self->responder_list, responder); } -static void dispatch_pending_to_responder(gpointer responder_data, - gpointer foreach_data_ptr) { - DispatchPendingToResponderForeachData* foreach_data = - reinterpret_cast( - foreach_data_ptr); +// The loop body to dispatch an event to a responder. +static void dispatch_to_responder(gpointer responder_data, + gpointer foreach_data_ptr) { + DispatchToResponderLoopContext* context = + reinterpret_cast(foreach_data_ptr); FlKeyResponder* responder = FL_KEY_RESPONDER(responder_data); - fl_key_responder_handle_event(responder, foreach_data->event, + fl_key_responder_handle_event(responder, context->event, responder_handle_event_callback, - foreach_data->user_data); + context->user_data); } gboolean fl_keyboard_manager_handle_event(FlKeyboardManager* self, @@ -333,12 +365,11 @@ gboolean fl_keyboard_manager_handle_event(FlKeyboardManager* self, g_ptr_array_add(self->pending_responds, pending); FlKeyboardManagerUserData* user_data = fl_keyboard_manager_user_data_new(self, pending->sequence_id); - DispatchPendingToResponderForeachData data{ + DispatchToResponderLoopContext data{ .event = event, .user_data = user_data, }; - g_ptr_array_foreach(self->responder_list, dispatch_pending_to_responder, - &data); + g_ptr_array_foreach(self->responder_list, dispatch_to_responder, &data); return TRUE; } diff --git a/shell/platform/linux/key_mapping.cc b/shell/platform/linux/key_mapping.cc index 5f984fde3a325..6906306e97571 100644 --- a/shell/platform/linux/key_mapping.cc +++ b/shell/platform/linux/key_mapping.cc @@ -450,7 +450,7 @@ void initialize_modifier_bit_to_checked_keys(GHashTable* table) { data->is_caps_lock = false; } -void initialize_lock_mode_bit_to_checked_keys(GHashTable* table) { +void initialize_lock_bit_to_checked_keys(GHashTable* table) { FlKeyEmbedderCheckedKey* data; data = g_new(FlKeyEmbedderCheckedKey, 1); From 31370ee5e9f4fd764810d510041664795f54a504 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 26 Apr 2021 06:40:35 -0700 Subject: [PATCH 049/126] Doc --- .../linux/fl_key_embedder_responder.cc | 77 +++++++++---------- 1 file changed, 38 insertions(+), 39 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index 69297c1ce8cad..d321e2badf0ff 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -419,19 +419,29 @@ static void synchronize_pressed_states_loop_body(gpointer key, } } -// Find the first stage # greater than `start` that is equivalent to `target` in -// a cycle of 4. +// Update the pressing record. // -// That is, if `target` is less than `start`, return target + 4. -static int cycle_stage_to_after(int target, int start) { - g_return_val_if_fail(target >= -4 && target < 4, target); - g_return_val_if_fail(start >= 0 && start < 4, target); - constexpr int kNumStages = 4; - return target >= start ? target : target + kNumStages; +// If `logical_key` is 0, the record will be set as "released". Otherwise, +// the record will be set as "pressed" with this logical key. +static void update_pressing_state(FlKeyEmbedderResponder* self, + uint64_t physical_key, + uint64_t logical_key) { + if (logical_key != 0) { + g_return_if_fail(lookup_hash_table(self->pressing_records, physical_key) == + 0); + g_hash_table_insert(self->pressing_records, + uint64_to_gpointer(physical_key), + uint64_to_gpointer(logical_key)); + } else { + g_return_if_fail(lookup_hash_table(self->pressing_records, physical_key) != + 0); + g_hash_table_remove(self->pressing_records, + uint64_to_gpointer(physical_key)); + } } -// Find the stage # before the event (of the 4 stages as documented in -// `synchronize_lock_states_loop_body`) by the current record. +// Find the stage # by the current record, which should be the recorded stage before the +// event. static int find_stage_by_record(bool is_down, bool is_enabled) { constexpr int stage_by_record_index[] = { 0, // is_down: 0, is_enabled: 0 @@ -442,6 +452,8 @@ static int find_stage_by_record(bool is_down, bool is_enabled) { return stage_by_record_index[(is_down << 1) + is_enabled]; } +// Find the stage # by an event for the target key, which should be inferred +// stage before the event. static int find_stage_by_self_event(int stage_by_record, bool is_down_event, bool is_state_on, @@ -457,6 +469,8 @@ static int find_stage_by_self_event(int stage_by_record, return stage_by_record; } +// Find the stage # by an event for a non-target key, which should be inferred +// stage during the event. static int find_stage_by_others_event(int stage_by_record, bool is_state_on) { g_return_val_if_fail(stage_by_record >= 0 && stage_by_record < 4, stage_by_record); @@ -469,23 +483,6 @@ static int find_stage_by_others_event(int stage_by_record, bool is_state_on) { return stage_by_record; } -static void update_pressing_state(FlKeyEmbedderResponder* self, - uint64_t physical_key, - uint64_t logical_key) { - if (logical_key != 0) { - g_return_if_fail(lookup_hash_table(self->pressing_records, physical_key) == - 0); - g_hash_table_insert(self->pressing_records, - uint64_to_gpointer(physical_key), - uint64_to_gpointer(logical_key)); - } else { - g_return_if_fail(lookup_hash_table(self->pressing_records, physical_key) != - 0); - g_hash_table_remove(self->pressing_records, - uint64_to_gpointer(physical_key)); - } -} - static void possibly_update_lock_bit(FlKeyEmbedderResponder* self, uint64_t physical_key, bool is_down) { @@ -521,15 +518,15 @@ static void synchronize_lock_states_loop_body(gpointer key, // the definition of each stage (TruePressed and TrueEnabled), the event of // the lock key between every 2 stages (SelfType and SelfState), and the event // of other keys at each stage (OthersState). Notice that SelfState uses - // different rule for CapsLock. + // different rule for CapsLock from for other keys. // - // # [0] [1] [2] [3] - // TruePressed: Released Pressed Released Pressed - // TrueEnabled: Disabled Enabled Enabled Disabled - // SelfType: Down Up Down Up - // SelfState(Caps): 1 1 0 1 - // SelfState(Etc): 0 1 1 1 - // OthersState: 0 1 1 1 + // # [0] [1] [2] [3] + // TruePressed: Released Pressed Released Pressed + // TrueEnabled: Disabled Enabled Enabled Disabled + // SelfType: Down Up Down Up + // SelfState(Caps): 1 1 0 1 + // SelfState(Etc): 0 1 1 1 + // OthersState: 0 1 1 1 // // Except for stage 0, we can't derive the exact stage just from event // information. Choose the stage that requires the minimal synthesization. @@ -552,10 +549,12 @@ static void synchronize_lock_states_loop_body(gpointer key, checked_key->is_caps_lock) : find_stage_by_others_event(stage_by_record, enabled_by_state); - // If the event is for the target key, then the last stage transition should - // be handled by the main event logic instead of synthesization. - const int destination_stage = - cycle_stage_to_after(stage_by_event, stage_by_record); + // The destination stage is equal to stage_by_event but shifted cyclically to + // be no less than stage_by_record. + constexpr int kNumStages = 4; + const int destination_stage = stage_by_event >= stage_by_record + ? stage_by_event + : stage_by_event + kNumStages; printf("SynLock: stage by recrd %d\n", stage_by_record); printf("SynLock: stage by event %d\n", stage_by_event); From f34c5469801ebfcca5ca294976209173a3625c0b Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 27 Apr 2021 04:10:49 -0700 Subject: [PATCH 050/126] Add inference --- .../linux/fl_key_embedder_responder.cc | 71 +++++-- .../linux/fl_key_embedder_responder_test.cc | 196 ++++++++++++++++-- shell/platform/linux/key_mapping.cc | 12 +- 3 files changed, 242 insertions(+), 37 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index d321e2badf0ff..7caabb45a5c9a 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -121,6 +121,16 @@ static FlKeyEmbedderUserData* fl_key_embedder_user_data_new( /* Define FlKeyEmbedderResponder */ +namespace { + +typedef enum { + kStateLogicUndecided, + kStateLogicNormal, + kStateLogicReversed, +} StateLogicInferrence; + +} + struct _FlKeyEmbedderResponder { GObject parent_instance; @@ -139,6 +149,8 @@ struct _FlKeyEmbedderResponder { // It is a bit mask composed of GTK mode bits. guint lock_records; + StateLogicInferrence caps_lock_state_logic_inferrence; + // A static map from XKB code to Flutter's physical key code. // // Both keys and values are directly stored uint64s. This table is freed by @@ -250,6 +262,7 @@ FlKeyEmbedderResponder* fl_key_embedder_responder_new(FlEngine* engine) { self->pressing_records = g_hash_table_new(g_direct_hash, g_direct_equal); self->lock_records = 0; + self->caps_lock_state_logic_inferrence = kStateLogicUndecided; self->xkb_to_physical_key = g_hash_table_new(g_direct_hash, g_direct_equal); initialize_xkb_to_physical_key(self->xkb_to_physical_key); @@ -440,8 +453,8 @@ static void update_pressing_state(FlKeyEmbedderResponder* self, } } -// Find the stage # by the current record, which should be the recorded stage before the -// event. +// Find the stage # by the current record, which should be the recorded stage +// before the event. static int find_stage_by_record(bool is_down, bool is_enabled) { constexpr int stage_by_record_index[] = { 0, // is_down: 0, is_enabled: 0 @@ -457,14 +470,12 @@ static int find_stage_by_record(bool is_down, bool is_enabled) { static int find_stage_by_self_event(int stage_by_record, bool is_down_event, bool is_state_on, - bool is_caps_lock) { - g_return_val_if_fail(stage_by_record >= 0 && stage_by_record < 4, - stage_by_record); + bool reverse_state_logic) { if (!is_state_on) { - return is_caps_lock ? 2 : 0; + return reverse_state_logic ? 2 : 0; } if (is_down_event) { - return is_caps_lock ? 0 : 2; + return reverse_state_logic ? 0 : 2; } return stage_by_record; } @@ -497,7 +508,33 @@ static void possibly_update_lock_bit(FlKeyEmbedderResponder* self, } } +static void update_caps_lock_state_logic_inferrence( + FlKeyEmbedderResponder* self, + bool is_down_event, + bool enabled_by_state, + int stage_by_record) { + if (self->caps_lock_state_logic_inferrence != kStateLogicUndecided) { + return; + } + if (!is_down_event) { + return; + } + const int stage_by_event = find_stage_by_self_event( + stage_by_record, is_down_event, enabled_by_state, false); + if ((stage_by_event == 0 && stage_by_record == 2) || + (stage_by_event == 2 && stage_by_record == 0)) { + self->caps_lock_state_logic_inferrence = kStateLogicReversed; + } else { + self->caps_lock_state_logic_inferrence = kStateLogicNormal; + } + printf("Infer: byEvent %d byRecord %d result reversed %d\n", stage_by_event, + stage_by_record, + self->caps_lock_state_logic_inferrence == kStateLogicReversed); +} + // The loop body to synchronize lock states. +// +// This function might modify self->caps_lock_state_logic_inferrence. static void synchronize_lock_states_loop_body(gpointer key, gpointer value, gpointer user_data) { @@ -517,15 +554,15 @@ static void synchronize_lock_states_loop_body(gpointer key, // A lock mode key can be at any of a 4-stage cycle. The following table lists // the definition of each stage (TruePressed and TrueEnabled), the event of // the lock key between every 2 stages (SelfType and SelfState), and the event - // of other keys at each stage (OthersState). Notice that SelfState uses - // different rule for CapsLock from for other keys. + // of other keys at each stage (OthersState). Notice that on certain platforms + // SelfState uses a reversed rule for certain keys (SelfState(rvsd)). // // # [0] [1] [2] [3] // TruePressed: Released Pressed Released Pressed // TrueEnabled: Disabled Enabled Enabled Disabled // SelfType: Down Up Down Up - // SelfState(Caps): 1 1 0 1 - // SelfState(Etc): 0 1 1 1 + // SelfState: 0 1 1 1 + // SelfState(rvsd): 1 1 0 1 // OthersState: 0 1 1 1 // // Except for stage 0, we can't derive the exact stage just from event @@ -542,11 +579,19 @@ static void synchronize_lock_states_loop_body(gpointer key, const bool enabled_by_state = (context->state & modifier_bit) != 0; const bool is_self_event = physical_key == context->event_physical_key; + if (is_self_event && checked_key->is_caps_lock) { + update_caps_lock_state_logic_inferrence(self, context->is_down, + enabled_by_state, stage_by_record); + g_return_if_fail(self->caps_lock_state_logic_inferrence != + kStateLogicUndecided); + } + const bool reverse_state_logic = + checked_key->is_caps_lock && + self->caps_lock_state_logic_inferrence == kStateLogicReversed; const int stage_by_event = is_self_event ? find_stage_by_self_event(stage_by_record, context->is_down, - enabled_by_state, - checked_key->is_caps_lock) + enabled_by_state, reverse_state_logic) : find_stage_by_others_event(stage_by_record, enabled_by_state); // The destination stage is equal to stage_by_event but shifted cyclically to diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index 8b9e58f379fa8..e7b6a63016da5 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -529,10 +529,28 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { FlKeyEmbedderCallRecord* record; - // Press key A (stage 0) + // Press CapsLock (stage 0 -> 1) fl_key_responder_handle_event( responder, - key_event_new(101, kPress, GDK_KEY_a, kKeyCodeKeyA, 0, kIsNotModifier), + key_event_new(101, kPress, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x0, + kIsModifier), + verify_response_handled, &user_data); + + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->physical, kPhysicalKeyCapsLock); + EXPECT_EQ(record->event->logical, kLogicalKeyCapsLock); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + // Press key A (stage 1) + fl_key_responder_handle_event( + responder, + key_event_new(102, kPress, GDK_KEY_A, kKeyCodeKeyA, 0x2, kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -540,22 +558,22 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); EXPECT_EQ(record->event->physical, kPhysicalKeyA); EXPECT_EQ(record->event->logical, kLogicalKeyA); - EXPECT_STREQ(record->event->character, "a"); + EXPECT_STREQ(record->event->character, "A"); EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); g_ptr_array_clear(g_call_records); - // Press CapsLock (stage 0 -> 1) + // Release CapsLock (stage 1 -> 2) fl_key_responder_handle_event( responder, - key_event_new(102, kPress, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x2, - kIsNotModifier), + key_event_new(103, kRelease, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x2, + kIsModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); - EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); EXPECT_EQ(record->event->physical, kPhysicalKeyCapsLock); EXPECT_EQ(record->event->logical, kLogicalKeyCapsLock); EXPECT_STREQ(record->event->character, nullptr); @@ -564,7 +582,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { invoke_record_callback_and_verify(record, TRUE, &user_data); g_ptr_array_clear(g_call_records); - // Release key A (stage 1) + // Release key A (stage 2) fl_key_responder_handle_event( responder, key_event_new(104, kRelease, GDK_KEY_A, kKeyCodeKeyA, 0x2, @@ -582,16 +600,16 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { invoke_record_callback_and_verify(record, TRUE, &user_data); g_ptr_array_clear(g_call_records); - // Release CapsLock (stage 1 -> 2) + // Press CapsLock (stage 2 -> 3) fl_key_responder_handle_event( responder, - key_event_new(103, kRelease, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x2, + key_event_new(105, kPress, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x2, kIsModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); - EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); EXPECT_EQ(record->event->physical, kPhysicalKeyCapsLock); EXPECT_EQ(record->event->logical, kLogicalKeyCapsLock); EXPECT_STREQ(record->event->character, nullptr); @@ -600,10 +618,10 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { invoke_record_callback_and_verify(record, TRUE, &user_data); g_ptr_array_clear(g_call_records); - // Press key A (stage 2) + // Press key A (stage 3) fl_key_responder_handle_event( responder, - key_event_new(101, kPress, GDK_KEY_A, kKeyCodeKeyA, 0x2, kIsNotModifier), + key_event_new(106, kPress, GDK_KEY_A, kKeyCodeKeyA, 0x2, kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -611,19 +629,89 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); EXPECT_EQ(record->event->physical, kPhysicalKeyA); EXPECT_EQ(record->event->logical, kLogicalKeyA); - EXPECT_STREQ(record->event->character, "A"); // TODO + EXPECT_STREQ(record->event->character, "A"); EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); g_ptr_array_clear(g_call_records); - // Press CapsLock (stage 2 -> 3) + // Release CapsLock (stage 3 -> 0) fl_key_responder_handle_event( responder, - key_event_new(102, kPress, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x00, + key_event_new(107, kRelease, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x2, + kIsModifier), + verify_response_handled, &user_data); + + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); + EXPECT_EQ(record->event->physical, kPhysicalKeyCapsLock); + EXPECT_EQ(record->event->logical, kLogicalKeyCapsLock); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + // Release key A (stage 0) + fl_key_responder_handle_event( + responder, + key_event_new(108, kRelease, GDK_KEY_a, kKeyCodeKeyA, 0x0, kIsNotModifier), verify_response_handled, &user_data); + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); + EXPECT_EQ(record->event->physical, kPhysicalKeyA); + EXPECT_EQ(record->event->logical, kLogicalKeyA); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + clear_g_call_records(); +} + +// Press or release letter key between presses/releases of CapsLock, on +// a platform with reversed logic. +// +// This happens when using a Chrome remote desktop on MacOS. +TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { + EXPECT_EQ(g_call_records, nullptr); + g_call_records = g_ptr_array_new_with_free_func(g_object_unref); + g_autoptr(FlEngine) engine = make_mock_engine_with_records(); + g_autoptr(FlKeyResponder) responder = + FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); + int user_data = 123; // Arbitrary user data + + FlKeyEmbedderCallRecord* record; + + // Press key A (stage 0) + fl_key_responder_handle_event( + responder, + key_event_new(101, kPress, GDK_KEY_a, kKeyCodeKeyA, 0x0, kIsNotModifier), + verify_response_handled, &user_data); + + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->physical, kPhysicalKeyA); + EXPECT_EQ(record->event->logical, kLogicalKeyA); + EXPECT_STREQ(record->event->character, "a"); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + // Press CapsLock (stage 0 -> 1) + fl_key_responder_handle_event( + responder, + key_event_new(102, kPress, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x2, + kIsModifier), + verify_response_handled, &user_data); + EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); @@ -635,7 +723,25 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { invoke_record_callback_and_verify(record, TRUE, &user_data); g_ptr_array_clear(g_call_records); - // Release key A (stage 3) + // Release CapsLock (stage 1 -> 2) + fl_key_responder_handle_event( + responder, + key_event_new(103, kRelease, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x2, + kIsModifier), + verify_response_handled, &user_data); + + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); + EXPECT_EQ(record->event->physical, kPhysicalKeyCapsLock); + EXPECT_EQ(record->event->logical, kLogicalKeyCapsLock); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + // Release key A (stage 2) fl_key_responder_handle_event( responder, key_event_new(104, kRelease, GDK_KEY_A, kKeyCodeKeyA, 0x2, @@ -653,10 +759,46 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { invoke_record_callback_and_verify(record, TRUE, &user_data); g_ptr_array_clear(g_call_records); + // Press key A (stage 2) + fl_key_responder_handle_event( + responder, + key_event_new(105, kPress, GDK_KEY_A, kKeyCodeKeyA, 0x2, + kIsNotModifier), + verify_response_handled, &user_data); + + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->physical, kPhysicalKeyA); + EXPECT_EQ(record->event->logical, kLogicalKeyA); + EXPECT_STREQ(record->event->character, "A"); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + // Press CapsLock (stage 2 -> 3) + fl_key_responder_handle_event( + responder, + key_event_new(106, kPress, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x0, + kIsModifier), + verify_response_handled, &user_data); + + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->physical, kPhysicalKeyCapsLock); + EXPECT_EQ(record->event->logical, kLogicalKeyCapsLock); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + // Release CapsLock (stage 3 -> 0) fl_key_responder_handle_event( responder, - key_event_new(103, kRelease, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x2, + key_event_new(107, kRelease, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x2, kIsModifier), verify_response_handled, &user_data); @@ -671,6 +813,24 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { invoke_record_callback_and_verify(record, TRUE, &user_data); g_ptr_array_clear(g_call_records); + // Release key A (stage 0) + fl_key_responder_handle_event( + responder, + key_event_new(108, kRelease, GDK_KEY_a, kKeyCodeKeyA, 0x0, + kIsNotModifier), + verify_response_handled, &user_data); + + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); + EXPECT_EQ(record->event->physical, kPhysicalKeyA); + EXPECT_EQ(record->event->logical, kLogicalKeyA); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + clear_g_call_records(); } diff --git a/shell/platform/linux/key_mapping.cc b/shell/platform/linux/key_mapping.cc index 6906306e97571..cf45eec6c2e2b 100644 --- a/shell/platform/linux/key_mapping.cc +++ b/shell/platform/linux/key_mapping.cc @@ -423,31 +423,31 @@ void initialize_modifier_bit_to_checked_keys(GHashTable* table) { data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_SHIFT_MASK), data); + data->is_caps_lock = false; data->primary_logical_key = 0x3000000010d; // shiftLeft data->primary_physical_key = 0x0000700e1; // shiftLeft data->secondary_physical_key = 0x0000700e5; // shiftRight - data->is_caps_lock = false; data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_CONTROL_MASK), data); + data->is_caps_lock = false; data->primary_logical_key = 0x30000000105; // controlLeft data->primary_physical_key = 0x0000700e0; // controlLeft data->secondary_physical_key = 0x0000700e4; // controlRight - data->is_caps_lock = false; data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_MOD1_MASK), data); + data->is_caps_lock = false; data->primary_logical_key = 0x30000000102; // altLeft data->primary_physical_key = 0x0000700e2; // altLeft data->secondary_physical_key = 0x0000700e6; // altRight - data->is_caps_lock = false; data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_MOD4_MASK), data); + data->is_caps_lock = false; data->primary_logical_key = 0x30000000109; // metaLeft data->primary_physical_key = 0x0000700e3; // metaLeft data->secondary_physical_key = 0x0000700e7; // metaRight - data->is_caps_lock = false; } void initialize_lock_bit_to_checked_keys(GHashTable* table) { @@ -455,13 +455,13 @@ void initialize_lock_bit_to_checked_keys(GHashTable* table) { data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_LOCK_MASK), data); + data->is_caps_lock = true; data->primary_logical_key = 0x01000000104; // capsLock data->primary_physical_key = 0x000070039; // capsLock - data->is_caps_lock = true; data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_MOD2_MASK), data); + data->is_caps_lock = false; data->primary_logical_key = 0x0100000010a; // numLock data->primary_physical_key = 0x000070053; // numLock - data->is_caps_lock = false; } From 012390193e3416a8fe8b519f5c10cbdadcfdd95b Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 27 Apr 2021 04:25:25 -0700 Subject: [PATCH 051/126] Remove prints --- .../linux/fl_key_embedder_responder.cc | 27 ------------------- 1 file changed, 27 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index 7caabb45a5c9a..f851270b6207f 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -387,8 +387,6 @@ static void synchronize_pressed_states_loop_body(gpointer key, checked_key->secondary_physical_key, }; const guint length = checked_key->secondary_physical_key == 0 ? 1 : 2; - // printf("Syn: 1 state %x bit %x curPhy %lx\n", context->state, modifier_bit, - // context->event_physical_key); const bool pressed_by_state = (context->state & modifier_bit) != 0; bool pressed_by_record = false; @@ -404,13 +402,9 @@ static void synchronize_pressed_states_loop_body(gpointer key, (pressed_logical_key != 0) ^ (physical_key == context->event_physical_key); - // printf("Syn: 2 phy %lx record %lx adju %d\n", physical_key, - // pressed_logical_key, adjusted_this_key_pressed); if (adjusted_this_key_pressed) { pressed_by_record = true; if (!pressed_by_state) { - // printf("Syn: 3 SYN: phy %lx log %lx currPh %lx\n", physical_key, - // pressed_logical_key, context->event_physical_key); g_return_if_fail(physical_key != context->event_physical_key); synthesize_simple_event(self, kFlutterKeyEventTypeUp, physical_key, pressed_logical_key, context->timestamp); @@ -423,7 +417,6 @@ static void synchronize_pressed_states_loop_body(gpointer key, uint64_t physical_key = checked_key->primary_physical_key; g_return_if_fail(physical_key != context->event_physical_key); uint64_t logical_key = checked_key->primary_logical_key; - // printf("Syn: 4 SYN: phy %lx log %lx\n", physical_key, logical_key); synthesize_simple_event(self, kFlutterKeyEventTypeDown, physical_key, logical_key, context->timestamp); g_hash_table_insert(self->pressing_records, @@ -502,7 +495,6 @@ static void possibly_update_lock_bit(FlKeyEmbedderResponder* self, } const guint mode_bit = GPOINTER_TO_UINT(g_hash_table_lookup( self->physical_key_to_lock_bit, uint64_to_gpointer(physical_key))); - // printf("Mode bit for PhK %lx is %x\n", physical_key, mode_bit); if (mode_bit != 0) { self->lock_records ^= mode_bit; } @@ -527,9 +519,6 @@ static void update_caps_lock_state_logic_inferrence( } else { self->caps_lock_state_logic_inferrence = kStateLogicNormal; } - printf("Infer: byEvent %d byRecord %d result reversed %d\n", stage_by_event, - stage_by_record, - self->caps_lock_state_logic_inferrence == kStateLogicReversed); } // The loop body to synchronize lock states. @@ -548,8 +537,6 @@ static void synchronize_lock_states_loop_body(gpointer key, const uint64_t logical_key = checked_key->primary_logical_key; const uint64_t physical_key = checked_key->primary_physical_key; - printf("Syn: 1 state %x bit %x curPhy %lx\n", context->state, modifier_bit, - context->event_physical_key); // A lock mode key can be at any of a 4-stage cycle. The following table lists // the definition of each stage (TruePressed and TrueEnabled), the event of @@ -601,9 +588,6 @@ static void synchronize_lock_states_loop_body(gpointer key, ? stage_by_event : stage_by_event + kNumStages; - printf("SynLock: stage by recrd %d\n", stage_by_record); - printf("SynLock: stage by event %d\n", stage_by_event); - printf("SynLock: stage by dest %d\n", destination_stage); g_return_if_fail(stage_by_record <= destination_stage); if (stage_by_record == destination_stage) { return; @@ -613,7 +597,6 @@ static void synchronize_lock_states_loop_body(gpointer key, if (current_stage == 9) { return; } - printf("SynLock: syn for stage %d\n", current_stage); const int standard_current_stage = current_stage >= 4 ? current_stage - 4 : current_stage; @@ -646,15 +629,6 @@ static void fl_key_embedder_responder_handle_event( const double timestamp = event_to_timestamp(event); const bool is_down_event = event->type == GDK_KEY_PRESS; - printf( - "#%7s keyval 0x%x keycode 0x%x state 0x%x ismod %d snd %d grp %d " - "time %d curLock %x PhK %lx\n", - event->type == GDK_KEY_PRESS ? "PRESS" : "RELEASE", event->keyval, - event->hardware_keycode, event->state, event->is_modifier, - event->send_event, event->group, event->time, self->lock_records, - physical_key); - fflush(stdout); - SyncStateLoopContext sync_pressed_state_context; sync_pressed_state_context.self = self; sync_pressed_state_context.state = event->state; @@ -668,7 +642,6 @@ static void fl_key_embedder_responder_handle_event( &sync_pressed_state_context); // Construct the real event - // printf("Real event\n"); const uint64_t last_logical_record = lookup_hash_table(self->pressing_records, physical_key); From 8797e50755d093108f0b3107aa6ea650e554e637 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 27 Apr 2021 04:44:15 -0700 Subject: [PATCH 052/126] Doc for infer --- .../linux/fl_key_embedder_responder.cc | 55 ++++++++++++++----- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index f851270b6207f..cda5ce8dc350e 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -149,6 +149,10 @@ struct _FlKeyEmbedderResponder { // It is a bit mask composed of GTK mode bits. guint lock_records; + // The inferred mode indicating whether the CapsLock state logic is reversed + // on this platform. + // + // For more information, see #update_caps_lock_state_logic_inferrence. StateLogicInferrence caps_lock_state_logic_inferrence; // A static map from XKB code to Flutter's physical key code. @@ -427,8 +431,9 @@ static void synchronize_pressed_states_loop_body(gpointer key, // Update the pressing record. // -// If `logical_key` is 0, the record will be set as "released". Otherwise, -// the record will be set as "pressed" with this logical key. +// If `logical_key` is 0, the record will be set as "released". Otherwise, the +// record will be set as "pressed" with this logical key. This function asserts +// that the key is pressed if the caller asked to release, and vice versa. static void update_pressing_state(FlKeyEmbedderResponder* self, uint64_t physical_key, uint64_t logical_key) { @@ -446,6 +451,23 @@ static void update_pressing_state(FlKeyEmbedderResponder* self, } } +// Update the lock record. +// +// If `is_down` is false, this function is a no-op. Otherwise, this function +// finds the lock bit corresponding to `physical_key`, and flips its bit. +static void possibly_update_lock_bit(FlKeyEmbedderResponder* self, + uint64_t physical_key, + bool is_down) { + if (!is_down) { + return; + } + const guint mode_bit = GPOINTER_TO_UINT(g_hash_table_lookup( + self->physical_key_to_lock_bit, uint64_to_gpointer(physical_key))); + if (mode_bit != 0) { + self->lock_records ^= mode_bit; + } +} + // Find the stage # by the current record, which should be the recorded stage // before the event. static int find_stage_by_record(bool is_down, bool is_enabled) { @@ -487,19 +509,22 @@ static int find_stage_by_others_event(int stage_by_record, bool is_state_on) { return stage_by_record; } -static void possibly_update_lock_bit(FlKeyEmbedderResponder* self, - uint64_t physical_key, - bool is_down) { - if (!is_down) { - return; - } - const guint mode_bit = GPOINTER_TO_UINT(g_hash_table_lookup( - self->physical_key_to_lock_bit, uint64_to_gpointer(physical_key))); - if (mode_bit != 0) { - self->lock_records ^= mode_bit; - } -} - +// Infer caps_lock_state_logic_inferrence if applicable. +// +// In most cases, when a lock key is pressed or released, its event has the +// key's state as 0-1-1-1 for the 4 stages (as documented in +// #synchronize_lock_states_loop_body) respectively. But in very rare cases it +// produces 1-1-0-1, which we call "reversed state logic". This is observed +// when using Chrome Remote Desktop on macOS. +// +// To detect whether the current platform is normal or reversed, this function +// is called on the first down event of CapsLock before calculating stages. +// This function then store the inferred mode as +// self->caps_lock_state_logic_inferrence. +// +// Note that this does not help if the same app session is used alternatively +// between a reversed platform and a normal platform. But this is the best we +// can do. static void update_caps_lock_state_logic_inferrence( FlKeyEmbedderResponder* self, bool is_down_event, From b936ce397a9dcc07994794474d716954f8422c8f Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 27 Apr 2021 05:02:53 -0700 Subject: [PATCH 053/126] Lincenses --- ci/licenses_golden/licenses_flutter | 18 +- .../linux/fl_key_embedder_responder_test.cc | 3 +- shell/platform/linux/fl_key_event_plugin.cc | 432 ------------------ shell/platform/linux/fl_key_event_plugin.h | 89 ---- .../linux/fl_key_event_plugin_private.h | 40 -- .../linux/fl_key_event_plugin_test.cc | 364 --------------- shell/platform/linux/key_mapping.cc | 2 +- 7 files changed, 16 insertions(+), 932 deletions(-) delete mode 100644 shell/platform/linux/fl_key_event_plugin.cc delete mode 100644 shell/platform/linux/fl_key_event_plugin.h delete mode 100644 shell/platform/linux/fl_key_event_plugin_private.h delete mode 100644 shell/platform/linux/fl_key_event_plugin_test.cc diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 4c361acfe9452..361ca0a9ecfc5 100755 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1435,10 +1435,18 @@ FILE: ../../../flutter/shell/platform/linux/fl_json_message_codec.cc FILE: ../../../flutter/shell/platform/linux/fl_json_message_codec_test.cc FILE: ../../../flutter/shell/platform/linux/fl_json_method_codec.cc FILE: ../../../flutter/shell/platform/linux/fl_json_method_codec_test.cc -FILE: ../../../flutter/shell/platform/linux/fl_key_event_plugin.cc -FILE: ../../../flutter/shell/platform/linux/fl_key_event_plugin.h -FILE: ../../../flutter/shell/platform/linux/fl_key_event_plugin_private.h -FILE: ../../../flutter/shell/platform/linux/fl_key_event_plugin_test.cc +FILE: ../../../flutter/shell/platform/linux/fl_key_channel_responder_test.cc +FILE: ../../../flutter/shell/platform/linux/fl_key_channel_responder.cc +FILE: ../../../flutter/shell/platform/linux/fl_key_channel_responder.h +FILE: ../../../flutter/shell/platform/linux/fl_key_embedder_responder_private.h +FILE: ../../../flutter/shell/platform/linux/fl_key_embedder_responder_test.cc +FILE: ../../../flutter/shell/platform/linux/fl_key_embedder_responder.cc +FILE: ../../../flutter/shell/platform/linux/fl_key_embedder_responder.h +FILE: ../../../flutter/shell/platform/linux/fl_key_responder.cc +FILE: ../../../flutter/shell/platform/linux/fl_key_responder.h +FILE: ../../../flutter/shell/platform/linux/fl_keyboard_manager_test.cc +FILE: ../../../flutter/shell/platform/linux/fl_keyboard_manager.cc +FILE: ../../../flutter/shell/platform/linux/fl_keyboard_manager.h FILE: ../../../flutter/shell/platform/linux/fl_message_codec.cc FILE: ../../../flutter/shell/platform/linux/fl_message_codec_test.cc FILE: ../../../flutter/shell/platform/linux/fl_method_call.cc @@ -1481,6 +1489,8 @@ FILE: ../../../flutter/shell/platform/linux/fl_view.cc FILE: ../../../flutter/shell/platform/linux/fl_view_accessible.cc FILE: ../../../flutter/shell/platform/linux/fl_view_accessible.h FILE: ../../../flutter/shell/platform/linux/fl_view_private.h +FILE: ../../../flutter/shell/platform/linux/key_mapping.cc +FILE: ../../../flutter/shell/platform/linux/key_mapping.h FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_basic_message_channel.h FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_binary_codec.h FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index e7b6a63016da5..1b07521d2cce0 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -762,8 +762,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { // Press key A (stage 2) fl_key_responder_handle_event( responder, - key_event_new(105, kPress, GDK_KEY_A, kKeyCodeKeyA, 0x2, - kIsNotModifier), + key_event_new(105, kPress, GDK_KEY_A, kKeyCodeKeyA, 0x2, kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); diff --git a/shell/platform/linux/fl_key_event_plugin.cc b/shell/platform/linux/fl_key_event_plugin.cc deleted file mode 100644 index 1cabc6a1658e4..0000000000000 --- a/shell/platform/linux/fl_key_event_plugin.cc +++ /dev/null @@ -1,432 +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_key_event_plugin.h" -#include "flutter/shell/platform/linux/fl_key_event_plugin_private.h" - -#include -#include - -#include "flutter/shell/platform/linux/fl_text_input_plugin.h" -#include "flutter/shell/platform/linux/public/flutter_linux/fl_basic_message_channel.h" -#include "flutter/shell/platform/linux/public/flutter_linux/fl_json_message_codec.h" - -static constexpr char kChannelName[] = "flutter/keyevent"; -static constexpr char kTypeKey[] = "type"; -static constexpr char kTypeValueUp[] = "keyup"; -static constexpr char kTypeValueDown[] = "keydown"; -static constexpr char kKeymapKey[] = "keymap"; -static constexpr char kKeyCodeKey[] = "keyCode"; -static constexpr char kScanCodeKey[] = "scanCode"; -static constexpr char kModifiersKey[] = "modifiers"; -static constexpr char kToolkitKey[] = "toolkit"; -static constexpr char kUnicodeScalarValuesKey[] = "unicodeScalarValues"; - -static constexpr char kGtkToolkit[] = "gtk"; -static constexpr char kLinuxKeymap[] = "linux"; - -static constexpr uint64_t kMaxPendingEvents = 1000; - -// Definition of the FlKeyEventPlugin GObject class. - -struct _FlKeyEventPlugin { - GObject parent_instance; - - FlBasicMessageChannel* channel = nullptr; - FlTextInputPlugin* text_input_plugin = nullptr; - FlKeyEventPluginCallback response_callback = nullptr; - GPtrArray* pending_events; -}; - -G_DEFINE_TYPE(FlKeyEventPlugin, fl_key_event_plugin, G_TYPE_OBJECT) - -// Declare and define a private pair object to bind the id and the event -// together. - -G_DECLARE_FINAL_TYPE(FlKeyEventPair, - fl_key_event_pair, - FL, - KEY_EVENT_PAIR, - GObject); - -struct _FlKeyEventPair { - GObject parent_instance; - - uint64_t id; - GdkEventKey* event; -}; - -G_DEFINE_TYPE(FlKeyEventPair, fl_key_event_pair, G_TYPE_OBJECT) - -// Dispose method for FlKeyEventPair. -static void fl_key_event_pair_dispose(GObject* object) { - // Redundant, but added so that we don't get a warning about unused function - // for FL_IS_KEY_EVENT_PAIR. - g_return_if_fail(FL_IS_KEY_EVENT_PAIR(object)); - - FlKeyEventPair* self = FL_KEY_EVENT_PAIR(object); - g_clear_pointer(&self->event, gdk_event_free); - G_OBJECT_CLASS(fl_key_event_pair_parent_class)->dispose(object); -} - -// Class Initialization method for FlKeyEventPair class. -static void fl_key_event_pair_class_init(FlKeyEventPairClass* klass) { - G_OBJECT_CLASS(klass)->dispose = fl_key_event_pair_dispose; -} - -// Initialization for FlKeyEventPair instances. -static void fl_key_event_pair_init(FlKeyEventPair* self) {} - -// Creates a new FlKeyEventPair instance, given a unique ID, and an event struct -// to keep. -FlKeyEventPair* fl_key_event_pair_new(uint64_t id, GdkEventKey* event) { - FlKeyEventPair* self = - FL_KEY_EVENT_PAIR(g_object_new(fl_key_event_pair_get_type(), nullptr)); - - // Copy the event to preserve refcounts for referenced values (mainly the - // window). - GdkEventKey* event_copy = reinterpret_cast( - gdk_event_copy(reinterpret_cast(event))); - self->id = id; - self->event = event_copy; - return self; -} - -// Declare and define a private class to hold response data from the framework. -G_DECLARE_FINAL_TYPE(FlKeyEventResponseData, - fl_key_event_response_data, - FL, - KEY_EVENT_RESPONSE_DATA, - GObject); - -struct _FlKeyEventResponseData { - GObject parent_instance; - - FlKeyEventPlugin* plugin; - uint64_t id; - gpointer user_data; -}; - -// Definition for FlKeyEventResponseData private class. -G_DEFINE_TYPE(FlKeyEventResponseData, fl_key_event_response_data, G_TYPE_OBJECT) - -// Dispose method for FlKeyEventResponseData private class. -static void fl_key_event_response_data_dispose(GObject* object) { - g_return_if_fail(FL_IS_KEY_EVENT_RESPONSE_DATA(object)); - FlKeyEventResponseData* self = FL_KEY_EVENT_RESPONSE_DATA(object); - if (self->plugin != nullptr) { - g_object_remove_weak_pointer(G_OBJECT(self->plugin), - reinterpret_cast(&(self->plugin))); - self->plugin = nullptr; - } -} - -// Class initialization method for FlKeyEventResponseData private class. -static void fl_key_event_response_data_class_init( - FlKeyEventResponseDataClass* klass) { - G_OBJECT_CLASS(klass)->dispose = fl_key_event_response_data_dispose; -} - -// Instance initialization method for FlKeyEventResponseData private class. -static void fl_key_event_response_data_init(FlKeyEventResponseData* self) {} - -// Creates a new FlKeyEventResponseData private class with a plugin that created -// the request, a unique ID for tracking, and optional user data. -// Will keep a weak pointer to the plugin. -FlKeyEventResponseData* fl_key_event_response_data_new(FlKeyEventPlugin* plugin, - uint64_t id, - gpointer user_data) { - FlKeyEventResponseData* self = FL_KEY_EVENT_RESPONSE_DATA( - g_object_new(fl_key_event_response_data_get_type(), nullptr)); - - self->plugin = plugin; - // Add a weak pointer so we can know if the key event plugin disappeared - // while the framework was responding. - g_object_add_weak_pointer(G_OBJECT(plugin), - reinterpret_cast(&(self->plugin))); - self->id = id; - self->user_data = user_data; - return self; -} - -// Calculates a unique ID for a given GdkEventKey object to use for -// identification of responses from the framework. -uint64_t fl_key_event_plugin_get_event_id(GdkEventKey* event) { - // Combine the event timestamp, the type of event, and the hardware keycode - // (scan code) of the event to come up with a unique id for this event that - // can be derived solely from the event data itself, so that we can identify - // whether or not we have seen this event already. - return (event->time & 0xffffffff) | - (static_cast(event->type) & 0xffff) << 32 | - (static_cast(event->hardware_keycode) & 0xffff) << 48; -} - -// Finds an event in the event queue that was sent to the framework by its ID. -GdkEventKey* fl_key_event_plugin_find_pending_event(FlKeyEventPlugin* self, - uint64_t id) { - for (guint i = 0; i < self->pending_events->len; ++i) { - if (FL_KEY_EVENT_PAIR(g_ptr_array_index(self->pending_events, i))->id == - id) { - return FL_KEY_EVENT_PAIR(g_ptr_array_index(self->pending_events, i)) - ->event; - } - } - return nullptr; -} - -// Removes an event from the pending event queue. -static void remove_pending_event(FlKeyEventPlugin* self, uint64_t id) { - for (guint i = 0; i < self->pending_events->len; ++i) { - if (FL_KEY_EVENT_PAIR(g_ptr_array_index(self->pending_events, i))->id == - id) { - g_ptr_array_remove_index(self->pending_events, i); - return; - } - } - g_warning("Tried to remove pending event with id %" PRIu64 - ", but the event was not found.", - id); -} - -// Adds an GdkEventKey to the pending event queue, with a unique ID, and the -// plugin that added it. -static void add_pending_event(FlKeyEventPlugin* self, - uint64_t id, - GdkEventKey* event) { - if (self->pending_events->len > kMaxPendingEvents) { - g_warning( - "There are %d keyboard events that have not yet received a " - "response from the framework. Are responses being sent?", - self->pending_events->len); - } - g_ptr_array_add(self->pending_events, fl_key_event_pair_new(id, event)); -} - -// Handles a response from the framework to a key event sent to the framework -// earlier. -static void handle_response(GObject* object, - GAsyncResult* result, - gpointer user_data) { - g_autoptr(FlKeyEventResponseData) data = - FL_KEY_EVENT_RESPONSE_DATA(user_data); - - // Will also return if the weak pointer has been destroyed. - if (data->plugin == nullptr) { - return; - } - - FlKeyEventPlugin* self = data->plugin; - - g_autoptr(GError) error = nullptr; - FlBasicMessageChannel* messageChannel = FL_BASIC_MESSAGE_CHANNEL(object); - FlValue* message = - fl_basic_message_channel_send_finish(messageChannel, result, &error); - if (error != nullptr) { - g_warning("Unable to retrieve framework response: %s", error->message); - return; - } - g_autoptr(FlValue) handled_value = fl_value_lookup_string(message, "handled"); - bool handled = FALSE; - if (handled_value != nullptr) { - GdkEventKey* event = fl_key_event_plugin_find_pending_event(self, data->id); - if (event == nullptr) { - g_warning("Event response for event id %" PRIu64 - " received, but pending event was not found.", - data->id); - } else { - handled = fl_value_get_bool(handled_value); - if (!handled) { - if (self->text_input_plugin != nullptr) { - // Propagate the event to the text input plugin. - handled = fl_text_input_plugin_filter_keypress( - self->text_input_plugin, event); - } - // Dispatch the event to other GTK windows if the text input plugin - // didn't handle it. We keep track of the event id so we can recognize - // the event when our window receives it again and not respond to it. If - // the response callback is set, then use that instead. - if (!handled && self->response_callback == nullptr) { - gdk_event_put(reinterpret_cast(event)); - } - } - } - } - - if (handled) { - // Because the event was handled, we no longer need to track it. Unhandled - // events will be removed when the event is re-dispatched to the window. - remove_pending_event(self, data->id); - } - - if (self->response_callback != nullptr) { - self->response_callback(object, message, handled, data->user_data); - } -} - -// Disposes of an FlKeyEventPlugin instance. -static void fl_key_event_plugin_dispose(GObject* object) { - FlKeyEventPlugin* self = FL_KEY_EVENT_PLUGIN(object); - - g_clear_object(&self->channel); - if (self->text_input_plugin != nullptr) { - g_object_remove_weak_pointer( - G_OBJECT(self->text_input_plugin), - reinterpret_cast(&(self->text_input_plugin))); - self->text_input_plugin = nullptr; - } - g_ptr_array_free(self->pending_events, TRUE); - - G_OBJECT_CLASS(fl_key_event_plugin_parent_class)->dispose(object); -} - -// Initializes the FlKeyEventPlugin class methods. -static void fl_key_event_plugin_class_init(FlKeyEventPluginClass* klass) { - G_OBJECT_CLASS(klass)->dispose = fl_key_event_plugin_dispose; -} - -// Initializes an FlKeyEventPlugin instance. -static void fl_key_event_plugin_init(FlKeyEventPlugin* self) {} - -// Creates a new FlKeyEventPlugin instance, with a messenger used to send -// messages to the framework, an FlTextInputPlugin used to handle key events -// that the framework doesn't handle. Mainly for testing purposes, it also takes -// an optional callback to call when a response is received, and an optional -// channel name to use when sending messages. -FlKeyEventPlugin* fl_key_event_plugin_new( - FlBinaryMessenger* messenger, - FlTextInputPlugin* text_input_plugin, - FlKeyEventPluginCallback response_callback, - const char* channel_name) { - g_return_val_if_fail(FL_IS_BINARY_MESSENGER(messenger), nullptr); - g_return_val_if_fail(FL_IS_TEXT_INPUT_PLUGIN(text_input_plugin), nullptr); - - FlKeyEventPlugin* self = FL_KEY_EVENT_PLUGIN( - g_object_new(fl_key_event_plugin_get_type(), nullptr)); - - g_autoptr(FlJsonMessageCodec) codec = fl_json_message_codec_new(); - self->channel = fl_basic_message_channel_new( - messenger, channel_name == nullptr ? kChannelName : channel_name, - FL_MESSAGE_CODEC(codec)); - self->response_callback = response_callback; - // Add a weak pointer so we know if the text input plugin goes away. - g_object_add_weak_pointer( - G_OBJECT(text_input_plugin), - reinterpret_cast(&(self->text_input_plugin))); - self->text_input_plugin = text_input_plugin; - - self->pending_events = g_ptr_array_new_with_free_func(g_object_unref); - return self; -} - -// Sends a key event to the framework. -bool fl_key_event_plugin_send_key_event(FlKeyEventPlugin* self, - GdkEventKey* event, - gpointer user_data) { - g_return_val_if_fail(FL_IS_KEY_EVENT_PLUGIN(self), FALSE); - g_return_val_if_fail(event != nullptr, FALSE); - - // Get an ID for the event, so we can match them up when we get a response - // from the framework. Use the event time, type, and hardware keycode as a - // unique ID, since they are part of the event structure that we can look up - // when we receive a random event that may or may not have been - // tracked/produced by this code. - uint64_t id = fl_key_event_plugin_get_event_id(event); - if (self->pending_events->len != 0 && - fl_key_event_plugin_find_pending_event(self, id) != nullptr) { - // If the event is in the queue of pending events we've seen, then we know - // that this is a re-dispatched event, and we shouldn't respond to it, but - // we should remove it from tracking. - remove_pending_event(self, id); - return FALSE; - } - - const gchar* type; - switch (event->type) { - case GDK_KEY_PRESS: - type = kTypeValueDown; - break; - case GDK_KEY_RELEASE: - type = kTypeValueUp; - break; - default: - return FALSE; - } - - int64_t scan_code = event->hardware_keycode; - int64_t unicodeScalarValues = gdk_keyval_to_unicode(event->keyval); - - // For most modifier keys, GTK keeps track of the "pressed" state of the - // modifier keys. Flutter uses this information to keep modifier keys from - // being "stuck" when a key-up event is lost because it happens after the app - // loses focus. - // - // For Lock keys (ShiftLock, CapsLock, NumLock), however, GTK keeps track of - // the state of the locks themselves, not the "pressed" state of the key. - // - // Since Flutter expects the "pressed" state of the modifier keys, the lock - // state for these keys is discarded here, and it is substituted for the - // pressed state of the key. - // - // This code has the flaw that if a key event is missed due to the app losing - // focus, then this state will still think the key is pressed when it isn't, - // but that is no worse than for "regular" keys until we implement the - // sync/cancel events on app focus changes. - // - // This is necessary to do here instead of in the framework because Flutter - // does modifier key syncing in the framework, and will turn on/off these keys - // as being "pressed" whenever the lock is on, which breaks a lot of - // interactions (for example, if shift-lock is on, tab traversal is broken). - // - // TODO(gspencergoog): get rid of this tracked state when we are tracking the - // state of all keys and sending sync/cancel events when focus is gained/lost. - - // Remove lock states from state mask. - guint state = event->state & ~(GDK_LOCK_MASK | GDK_MOD2_MASK); - - static bool shift_lock_pressed = FALSE; - static bool caps_lock_pressed = FALSE; - static bool num_lock_pressed = FALSE; - switch (event->keyval) { - case GDK_KEY_Num_Lock: - num_lock_pressed = event->type == GDK_KEY_PRESS; - break; - case GDK_KEY_Caps_Lock: - caps_lock_pressed = event->type == GDK_KEY_PRESS; - break; - case GDK_KEY_Shift_Lock: - shift_lock_pressed = event->type == GDK_KEY_PRESS; - break; - } - - // Add back in the state matching the actual pressed state of the lock keys, - // not the lock states. - state |= (shift_lock_pressed || caps_lock_pressed) ? GDK_LOCK_MASK : 0x0; - state |= num_lock_pressed ? GDK_MOD2_MASK : 0x0; - - g_autoptr(FlValue) message = fl_value_new_map(); - fl_value_set_string_take(message, kTypeKey, fl_value_new_string(type)); - fl_value_set_string_take(message, kKeymapKey, - fl_value_new_string(kLinuxKeymap)); - fl_value_set_string_take(message, kScanCodeKey, fl_value_new_int(scan_code)); - fl_value_set_string_take(message, kToolkitKey, - fl_value_new_string(kGtkToolkit)); - fl_value_set_string_take(message, kKeyCodeKey, - fl_value_new_int(event->keyval)); - fl_value_set_string_take(message, kModifiersKey, fl_value_new_int(state)); - if (unicodeScalarValues != 0) { - fl_value_set_string_take(message, kUnicodeScalarValuesKey, - fl_value_new_int(unicodeScalarValues)); - } - - // Track the event as pending a response from the framework. - add_pending_event(self, id, event); - FlKeyEventResponseData* data = - fl_key_event_response_data_new(self, id, user_data); - // Send the message off to the framework for handling (or not). - fl_basic_message_channel_send(self->channel, message, nullptr, - handle_response, data); - // Return true before we know what the framework will do, because if it - // doesn't handle the key, we'll re-dispatch it later. - return TRUE; -} diff --git a/shell/platform/linux/fl_key_event_plugin.h b/shell/platform/linux/fl_key_event_plugin.h deleted file mode 100644 index 18ee36a8a99d3..0000000000000 --- a/shell/platform/linux/fl_key_event_plugin.h +++ /dev/null @@ -1,89 +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_KEY_EVENT_PLUGIN_H_ -#define FLUTTER_SHELL_PLATFORM_LINUX_FL_KEY_EVENT_PLUGIN_H_ - -#include "flutter/shell/platform/linux/fl_text_input_plugin.h" -#include "flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h" -#include "flutter/shell/platform/linux/public/flutter_linux/fl_value.h" - -#include - -G_BEGIN_DECLS - -G_DECLARE_FINAL_TYPE(FlKeyEventPlugin, - fl_key_event_plugin, - FL, - KEY_EVENT_PLUGIN, - GObject); - -/** - * FlKeyEventPlugin: - * - * #FlKeyEventPlugin is a plugin that implements the shell side - * of SystemChannels.keyEvent from the Flutter services library. - */ - -/** - * FlKeyEventPluginCallback: - * @source_object: (nullable): the object the key event was started with. - * @message: the message returned from the framework. - * @handled: a boolean indicating whether the key event was handled in the - * framework. - * @user_data: user data passed to the callback. - * - * Type definition for a function that will be called when a key event is - * received from the engine. - **/ -typedef void (*FlKeyEventPluginCallback)(GObject* source_object, - FlValue* message, - gboolean handled, - gpointer user_data); - -/** - * fl_key_event_plugin_new: - * @messenger: an #FlBinaryMessenger. - * @response_callback: the callback to call when a response is received. If not - * given (nullptr), then the default response callback is - * used. Typically used for tests to receive event - * information. If specified, unhandled events will not be - * re-dispatched. - * @text_input_plugin: The #FlTextInputPlugin to send key events to if the - * framework doesn't handle them. - * @channel_name: the name of the channel to send key events to the framework - * on. If not given (nullptr), then the standard key event - * channel name is used. Typically used for tests to send on a - * test channel. - * - * Creates a new plugin that implements SystemChannels.keyEvent from the - * Flutter services library. - * - * Returns: a new #FlKeyEventPlugin. - */ -FlKeyEventPlugin* fl_key_event_plugin_new( - FlBinaryMessenger* messenger, - FlTextInputPlugin* text_input_plugin, - FlKeyEventPluginCallback response_callback = nullptr, - const char* channel_name = nullptr); - -/** - * fl_key_event_plugin_send_key_event: - * @plugin: an #FlKeyEventPlugin. - * @event: a #GdkEventKey. - * @user_data: a pointer to user data to send to the response callback via the - * messenger. - * - * @returns %TRUE if this key event should be considered handled and - * event propagation stopped. - * - * Sends a key event to Flutter. - */ -bool fl_key_event_plugin_send_key_event(FlKeyEventPlugin* plugin, - GdkEventKey* event, - gpointer user_data = nullptr); - -G_END_DECLS - -#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_KEY_EVENT_PLUGIN_H_ diff --git a/shell/platform/linux/fl_key_event_plugin_private.h b/shell/platform/linux/fl_key_event_plugin_private.h deleted file mode 100644 index 0fb5b3e1d80cf..0000000000000 --- a/shell/platform/linux/fl_key_event_plugin_private.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_KEY_EVENT_PLUGIN_PRIVATE_H_ -#define FLUTTER_SHELL_PLATFORM_LINUX_FL_KEY_EVENT_PLUGIN_PRIVATE_H_ - -#include "flutter/shell/platform/linux/fl_key_event_plugin.h" - -#include - -G_BEGIN_DECLS - -/** - * fl_key_event_plugin_get_event_id: - * @event: a GDK key event (GdkEventKey). - * - * Calculates an internal key ID for a given event. Used to look up pending - * events using fl_key_event_plugin_find_pending_event. - * - * Returns: a 64-bit ID representing this GDK key event. - */ -uint64_t fl_key_event_plugin_get_event_id(GdkEventKey* event); - -/** - * fl_key_event_plugin_get_event_id: - * @id: a 64-bit id representing a GDK key event (GdkEventKey). Calculated - * using #fl_key_event_plugin_get_event_id. - * - * Looks up an event that is waiting for a response from the framework. - * - * Returns: the GDK key event requested, or nullptr if the event doesn't exist - * in the queue. - */ -GdkEventKey* fl_key_event_plugin_find_pending_event(FlKeyEventPlugin* self, - uint64_t id); - -G_END_DECLS - -#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_KEY_EVENT_PLUGIN_PRIVATE_H_ diff --git a/shell/platform/linux/fl_key_event_plugin_test.cc b/shell/platform/linux/fl_key_event_plugin_test.cc deleted file mode 100644 index dc8c112f79964..0000000000000 --- a/shell/platform/linux/fl_key_event_plugin_test.cc +++ /dev/null @@ -1,364 +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_key_event_plugin.h" -#include "flutter/shell/platform/linux/fl_key_event_plugin_private.h" - -#include "gtest/gtest.h" - -#include "flutter/shell/platform/linux/fl_binary_messenger_private.h" -#include "flutter/shell/platform/linux/fl_engine_private.h" -#include "flutter/shell/platform/linux/testing/fl_test.h" -#include "flutter/shell/platform/linux/testing/mock_text_input_plugin.h" - -static const char* expected_value = nullptr; -static gboolean expected_handled = FALSE; -static uint64_t expected_id = 0; -static FlKeyEventPlugin* expected_self = nullptr; - -// Called when the message response is received in the send_key_event test. -static void echo_response_cb(GObject* object, - FlValue* message, - gboolean handled, - gpointer user_data) { - EXPECT_NE(message, nullptr); - EXPECT_EQ(fl_value_get_type(message), FL_VALUE_TYPE_MAP); - EXPECT_STREQ(fl_value_to_string(message), expected_value); - EXPECT_EQ(handled, expected_handled); - if (expected_self != nullptr) { - if (handled) { - EXPECT_EQ( - fl_key_event_plugin_find_pending_event(expected_self, expected_id), - nullptr); - } else { - EXPECT_NE( - fl_key_event_plugin_find_pending_event(expected_self, expected_id), - nullptr); - } - } - - g_main_loop_quit(static_cast(user_data)); -} - -static gboolean handle_keypress(FlTextInputPlugin* plugin, GdkEventKey* event) { - return TRUE; -} - -static gboolean ignore_keypress(FlTextInputPlugin* plugin, GdkEventKey* event) { - return FALSE; -} - -// Test sending a letter "A"; -TEST(FlKeyEventPluginTest, SendKeyEvent) { - g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); - - g_autoptr(FlEngine) engine = make_mock_engine(); - FlBinaryMessenger* messenger = fl_binary_messenger_new(engine); - g_autoptr(FlTextInputPlugin) text_input_plugin = - FL_TEXT_INPUT_PLUGIN(fl_mock_text_input_plugin_new(handle_keypress)); - g_autoptr(FlKeyEventPlugin) plugin = fl_key_event_plugin_new( - messenger, text_input_plugin, echo_response_cb, "test/echo"); - - char string[] = "A"; - GdkEventKey key_event = GdkEventKey{ - GDK_KEY_PRESS, // event type - nullptr, // window (not needed) - FALSE, // event was sent explicitly - 12345, // time - 0x0, // modifier state - GDK_KEY_A, // key code - 1, // length of string representation - reinterpret_cast(&string[0]), // string representation - 0x04, // scan code - 0, // keyboard group - 0, // is a modifier - }; - - expected_value = - "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, keyCode: 65, " - "modifiers: 0, unicodeScalarValues: 65}"; - expected_handled = FALSE; - fl_key_event_plugin_send_key_event(plugin, &key_event, loop); - - // Blocks here until echo_response_cb is called. - g_main_loop_run(loop); - EXPECT_NE(fl_key_event_plugin_find_pending_event( - plugin, fl_key_event_plugin_get_event_id(&key_event)), - nullptr); - - key_event = GdkEventKey{ - GDK_KEY_RELEASE, // event type - nullptr, // window (not needed) - FALSE, // event was sent explicitly - 23456, // time - 0x0, // modifier state - GDK_KEY_A, // key code - 1, // length of string representation - reinterpret_cast(&string[0]), // string representation - 0x04, // scan code - 0, // keyboard group - 0, // is a modifier - }; - - expected_value = - "{type: keyup, keymap: linux, scanCode: 4, toolkit: gtk, keyCode: 65, " - "modifiers: 0, unicodeScalarValues: 65}"; - expected_handled = FALSE; - bool handled = fl_key_event_plugin_send_key_event(plugin, &key_event, loop); - EXPECT_TRUE(handled); - - // Blocks here until echo_response_cb is called. - g_main_loop_run(loop); - EXPECT_NE(fl_key_event_plugin_find_pending_event( - plugin, fl_key_event_plugin_get_event_id(&key_event)), - nullptr); -} - -void test_lock_event(guint key_code, - const char* down_expected, - const char* up_expected) { - g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); - - g_autoptr(FlEngine) engine = make_mock_engine(); - FlBinaryMessenger* messenger = fl_binary_messenger_new(engine); - g_autoptr(FlTextInputPlugin) text_input_plugin = - FL_TEXT_INPUT_PLUGIN(fl_mock_text_input_plugin_new(handle_keypress)); - g_autoptr(FlKeyEventPlugin) plugin = fl_key_event_plugin_new( - messenger, text_input_plugin, echo_response_cb, "test/echo"); - - GdkEventKey key_event = GdkEventKey{ - GDK_KEY_PRESS, // event type - nullptr, // window (not needed) - FALSE, // event was sent explicitly - 12345, // time - 0x10, // modifier state - key_code, // key code - 1, // length of string representation - nullptr, // string representation - 0x04, // scan code - 0, // keyboard group - 0, // is a modifier - }; - - expected_value = down_expected; - expected_handled = FALSE; - bool handled = fl_key_event_plugin_send_key_event(plugin, &key_event, loop); - EXPECT_TRUE(handled); - - // Blocks here until echo_response_cb is called. - g_main_loop_run(loop); - EXPECT_NE(fl_key_event_plugin_find_pending_event( - plugin, fl_key_event_plugin_get_event_id(&key_event)), - nullptr); - - key_event.type = GDK_KEY_RELEASE; - key_event.time++; - - expected_value = up_expected; - expected_handled = FALSE; - fl_key_event_plugin_send_key_event(plugin, &key_event, loop); - - // Blocks here until echo_response_cb is called. - g_main_loop_run(loop); - EXPECT_NE(fl_key_event_plugin_find_pending_event( - plugin, fl_key_event_plugin_get_event_id(&key_event)), - nullptr); -} - -// Test sending a "NumLock" keypress. -TEST(FlKeyEventPluginTest, SendNumLockKeyEvent) { - test_lock_event(GDK_KEY_Num_Lock, - "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, " - "keyCode: 65407, modifiers: 16}", - "{type: keyup, keymap: linux, scanCode: 4, toolkit: gtk, " - "keyCode: 65407, modifiers: 0}"); -} - -// Test sending a "CapsLock" keypress. -TEST(FlKeyEventPluginTest, SendCapsLockKeyEvent) { - test_lock_event(GDK_KEY_Caps_Lock, - "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, " - "keyCode: 65509, modifiers: 2}", - "{type: keyup, keymap: linux, scanCode: 4, toolkit: gtk, " - "keyCode: 65509, modifiers: 0}"); -} - -// Test sending a "ShiftLock" keypress. -TEST(FlKeyEventPluginTest, SendShiftLockKeyEvent) { - test_lock_event(GDK_KEY_Shift_Lock, - "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, " - "keyCode: 65510, modifiers: 2}", - "{type: keyup, keymap: linux, scanCode: 4, toolkit: gtk, " - "keyCode: 65510, modifiers: 0}"); -} - -TEST(FlKeyEventPluginTest, TestKeyEventHandledByFramework) { - g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); - - g_autoptr(FlEngine) engine = make_mock_engine(); - FlBinaryMessenger* messenger = fl_binary_messenger_new(engine); - g_autoptr(FlTextInputPlugin) text_input_plugin = - FL_TEXT_INPUT_PLUGIN(fl_mock_text_input_plugin_new(handle_keypress)); - g_autoptr(FlKeyEventPlugin) plugin = fl_key_event_plugin_new( - messenger, text_input_plugin, echo_response_cb, "test/key-event-handled"); - - GdkEventKey key_event = GdkEventKey{ - GDK_KEY_PRESS, // event type - nullptr, // window (not needed) - FALSE, // event was sent explicitly - 12345, // time - 0x10, // modifier state - GDK_KEY_A, // key code - 1, // length of string representation - nullptr, // string representation - 0x04, // scan code - 0, // keyboard group - 0, // is a modifier - }; - - expected_value = "{handled: true}"; - expected_handled = TRUE; - bool handled = fl_key_event_plugin_send_key_event(plugin, &key_event, loop); - // Should always be true, because the event was delayed. - EXPECT_TRUE(handled); - - // Blocks here until echo_response_cb is called. - g_main_loop_run(loop); - EXPECT_EQ(fl_key_event_plugin_find_pending_event( - plugin, fl_key_event_plugin_get_event_id(&key_event)), - nullptr); -} - -TEST(FlKeyEventPluginTest, TestKeyEventHandledByTextInputPlugin) { - g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); - - g_autoptr(FlEngine) engine = make_mock_engine(); - FlBinaryMessenger* messenger = fl_binary_messenger_new(engine); - g_autoptr(FlTextInputPlugin) text_input_plugin = - FL_TEXT_INPUT_PLUGIN(fl_mock_text_input_plugin_new(handle_keypress)); - g_autoptr(FlKeyEventPlugin) plugin = - fl_key_event_plugin_new(messenger, text_input_plugin, echo_response_cb, - "test/key-event-not-handled"); - - GdkEventKey key_event = GdkEventKey{ - GDK_KEY_PRESS, // event type - nullptr, // window (not needed) - FALSE, // event was sent explicitly - 12345, // time - 0x10, // modifier state - GDK_KEY_A, // key code - 1, // length of string representation - nullptr, // string representation - 0x04, // scan code - 0, // keyboard group - 0, // is a modifier - }; - - expected_value = "{handled: false}"; - expected_handled = TRUE; - bool handled = fl_key_event_plugin_send_key_event(plugin, &key_event, loop); - // Should always be true, because the event was delayed. - EXPECT_TRUE(handled); - - // Blocks here until echo_response_cb is called. - g_main_loop_run(loop); - EXPECT_EQ(fl_key_event_plugin_find_pending_event( - plugin, fl_key_event_plugin_get_event_id(&key_event)), - nullptr); -} - -TEST(FlKeyEventPluginTest, TestKeyEventNotHandledByTextInputPlugin) { - g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); - - g_autoptr(FlEngine) engine = make_mock_engine(); - FlBinaryMessenger* messenger = fl_binary_messenger_new(engine); - g_autoptr(FlTextInputPlugin) text_input_plugin = - FL_TEXT_INPUT_PLUGIN(fl_mock_text_input_plugin_new(ignore_keypress)); - g_autoptr(FlKeyEventPlugin) plugin = - fl_key_event_plugin_new(messenger, text_input_plugin, echo_response_cb, - "test/key-event-not-handled"); - - GdkEventKey key_event = GdkEventKey{ - GDK_KEY_PRESS, // event type - nullptr, // window (not needed) - FALSE, // event was sent explicitly - 12345, // time - 0x10, // modifier state - GDK_KEY_A, // key code - 1, // length of string representation - nullptr, // string representation - 0x04, // scan code - 0, // keyboard group - 0, // is a modifier - }; - - expected_value = "{handled: false}"; - expected_handled = FALSE; - bool handled = fl_key_event_plugin_send_key_event(plugin, &key_event, loop); - // Should always be true, because the event was delayed. - EXPECT_TRUE(handled); - - // Blocks here until echo_response_cb is called. - g_main_loop_run(loop); - EXPECT_NE(fl_key_event_plugin_find_pending_event( - plugin, fl_key_event_plugin_get_event_id(&key_event)), - nullptr); -} - -TEST(FlKeyEventPluginTest, TestKeyEventResponseOutOfOrderFromFramework) { - g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); - - g_autoptr(FlEngine) engine = make_mock_engine(); - FlBinaryMessenger* messenger = fl_binary_messenger_new(engine); - g_autoptr(FlTextInputPlugin) text_input_plugin = - FL_TEXT_INPUT_PLUGIN(fl_mock_text_input_plugin_new(handle_keypress)); - g_autoptr(FlKeyEventPlugin) plugin = fl_key_event_plugin_new( - messenger, text_input_plugin, echo_response_cb, "test/key-event-delayed"); - - GdkEventKey key_event = GdkEventKey{ - GDK_KEY_PRESS, // event type - nullptr, // window (not needed) - FALSE, // event was sent explicitly - 12345, // time - 0x10, // modifier state - GDK_KEY_A, // key code - 1, // length of string representation - nullptr, // string representation - 0x04, // scan code - 0, // keyboard group - 0, // is a modifier - }; - - expected_value = "{handled: true}"; - expected_handled = TRUE; - expected_self = plugin; - uint64_t event_id_a = fl_key_event_plugin_get_event_id(&key_event); - expected_id = event_id_a; - bool handled = fl_key_event_plugin_send_key_event(plugin, &key_event, loop); - // Should always be true, because the event was delayed. - EXPECT_TRUE(handled); - EXPECT_EQ(fl_key_event_plugin_find_pending_event(plugin, event_id_a)->keyval, - static_cast(GDK_KEY_A)); - - // Send a second key event that will be out of order. - key_event.keyval = GDK_KEY_B; - key_event.hardware_keycode = 0x05; - uint64_t event_id_b = fl_key_event_plugin_get_event_id(&key_event); - expected_id = event_id_b; - handled = fl_key_event_plugin_send_key_event(plugin, &key_event, loop); - EXPECT_TRUE(handled); - EXPECT_EQ(fl_key_event_plugin_find_pending_event(plugin, event_id_b)->keyval, - static_cast(GDK_KEY_B)); - - // Blocks here until echo_response_cb is called. - g_main_loop_run(loop); - - // Make sure they both were removed - EXPECT_EQ(fl_key_event_plugin_find_pending_event(plugin, event_id_a), - nullptr); - EXPECT_EQ(fl_key_event_plugin_find_pending_event(plugin, event_id_b), - nullptr); - expected_self = nullptr; - expected_id = 0; -} diff --git a/shell/platform/linux/key_mapping.cc b/shell/platform/linux/key_mapping.cc index cf45eec6c2e2b..2ea41e99783ee 100644 --- a/shell/platform/linux/key_mapping.cc +++ b/shell/platform/linux/key_mapping.cc @@ -1,4 +1,4 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. +// 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. From c29307a40f3090f626940143f3afa954b5ba0062 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 4 May 2021 09:59:50 -0700 Subject: [PATCH 054/126] MOD mask --- shell/platform/linux/key_mapping.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/platform/linux/key_mapping.cc b/shell/platform/linux/key_mapping.cc index 2ea41e99783ee..c74dca0927dc2 100644 --- a/shell/platform/linux/key_mapping.cc +++ b/shell/platform/linux/key_mapping.cc @@ -443,7 +443,7 @@ void initialize_modifier_bit_to_checked_keys(GHashTable* table) { data->secondary_physical_key = 0x0000700e6; // altRight data = g_new(FlKeyEmbedderCheckedKey, 1); - g_hash_table_insert(table, GUINT_TO_POINTER(GDK_MOD4_MASK), data); + g_hash_table_insert(table, GUINT_TO_POINTER(GDK_META_MASK), data); data->is_caps_lock = false; data->primary_logical_key = 0x30000000109; // metaLeft data->primary_physical_key = 0x0000700e3; // metaLeft From 00d010dfa2500395e60908f86d8083bc62d46a9a Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 4 May 2021 10:01:47 -0700 Subject: [PATCH 055/126] license --- ci/licenses_golden/licenses_flutter | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 37cef257d3d8a..56b94ed8e3ef2 100755 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1442,18 +1442,18 @@ FILE: ../../../flutter/shell/platform/linux/fl_json_message_codec.cc FILE: ../../../flutter/shell/platform/linux/fl_json_message_codec_test.cc FILE: ../../../flutter/shell/platform/linux/fl_json_method_codec.cc FILE: ../../../flutter/shell/platform/linux/fl_json_method_codec_test.cc -FILE: ../../../flutter/shell/platform/linux/fl_key_channel_responder_test.cc FILE: ../../../flutter/shell/platform/linux/fl_key_channel_responder.cc FILE: ../../../flutter/shell/platform/linux/fl_key_channel_responder.h -FILE: ../../../flutter/shell/platform/linux/fl_key_embedder_responder_private.h -FILE: ../../../flutter/shell/platform/linux/fl_key_embedder_responder_test.cc +FILE: ../../../flutter/shell/platform/linux/fl_key_channel_responder_test.cc FILE: ../../../flutter/shell/platform/linux/fl_key_embedder_responder.cc FILE: ../../../flutter/shell/platform/linux/fl_key_embedder_responder.h +FILE: ../../../flutter/shell/platform/linux/fl_key_embedder_responder_private.h +FILE: ../../../flutter/shell/platform/linux/fl_key_embedder_responder_test.cc FILE: ../../../flutter/shell/platform/linux/fl_key_responder.cc FILE: ../../../flutter/shell/platform/linux/fl_key_responder.h -FILE: ../../../flutter/shell/platform/linux/fl_keyboard_manager_test.cc 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_message_codec.cc FILE: ../../../flutter/shell/platform/linux/fl_message_codec_test.cc FILE: ../../../flutter/shell/platform/linux/fl_method_call.cc From 177c63f20ab067bf078d632e563c295648896f7e Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 4 May 2021 10:03:42 -0700 Subject: [PATCH 056/126] Fix build --- shell/platform/linux/BUILD.gn | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/shell/platform/linux/BUILD.gn b/shell/platform/linux/BUILD.gn index 315a08693e5f6..4e9fbc2b85587 100644 --- a/shell/platform/linux/BUILD.gn +++ b/shell/platform/linux/BUILD.gn @@ -102,10 +102,10 @@ source_set("flutter_linux_sources") { "fl_gl_area.cc", "fl_json_message_codec.cc", "fl_json_method_codec.cc", - "fl_keyboard_manager.cc", - "fl_key_responder.cc", "fl_key_channel_responder.cc", "fl_key_embedder_responder.cc", + "fl_key_responder.cc", + "fl_keyboard_manager.cc", "fl_message_codec.cc", "fl_method_call.cc", "fl_method_channel.cc", @@ -173,9 +173,9 @@ executable("flutter_linux_unittests") { "fl_event_channel_test.cc", "fl_json_message_codec_test.cc", "fl_json_method_codec_test.cc", - "fl_keyboard_manager_test.cc", "fl_key_channel_responder_test.cc", "fl_key_embedder_responder_test.cc", + "fl_keyboard_manager_test.cc", "fl_message_codec_test.cc", "fl_method_channel_test.cc", "fl_method_codec_test.cc", From ba29bd87d6937a4406031f60813becf7f3031288 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Thu, 6 May 2021 04:31:20 -0700 Subject: [PATCH 057/126] Review --- .../Source/FlutterChannelKeyResponder.h | 2 +- .../Source/FlutterEmbedderKeyResponder.h | 2 +- .../linux/fl_key_channel_responder.cc | 4 +- .../platform/linux/fl_key_channel_responder.h | 7 +++- .../linux/fl_key_embedder_responder.cc | 38 +++++++++++-------- .../linux/fl_key_embedder_responder.h | 2 +- .../windows/keyboard_key_channel_handler.h | 2 +- .../windows/keyboard_key_embedder_handler.h | 2 +- 8 files changed, 35 insertions(+), 24 deletions(-) diff --git a/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponder.h b/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponder.h index b40492a3550fb..911695e7adaa8 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponder.h +++ b/shell/platform/darwin/macos/framework/Source/FlutterChannelKeyResponder.h @@ -12,7 +12,7 @@ * A primary responder of |FlutterKeyboardManager| that handles events by * sending the raw information through the method channel. * - * This class corresponds to the RawKeyboard API in the framework. + * This class communicates with the RawKeyboard API in the framework. */ @interface FlutterChannelKeyResponder : NSObject diff --git a/shell/platform/darwin/macos/framework/Source/FlutterEmbedderKeyResponder.h b/shell/platform/darwin/macos/framework/Source/FlutterEmbedderKeyResponder.h index 5cd68954d0df9..ab2b1c107d785 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterEmbedderKeyResponder.h +++ b/shell/platform/darwin/macos/framework/Source/FlutterEmbedderKeyResponder.h @@ -19,7 +19,7 @@ typedef void (^FlutterSendEmbedderKeyEvent)(const FlutterKeyEvent& /* event */, * A primary responder of |FlutterKeyboardManager| that handles events by * sending the converted events through the embedder API. * - * This class corresponds to the HardwareKeyboard API in the framework. + * This class communicates with the HardwareKeyboard API in the framework. */ @interface FlutterEmbedderKeyResponder : NSObject diff --git a/shell/platform/linux/fl_key_channel_responder.cc b/shell/platform/linux/fl_key_channel_responder.cc index 019aba26e8820..f6b693c3be627 100644 --- a/shell/platform/linux/fl_key_channel_responder.cc +++ b/shell/platform/linux/fl_key_channel_responder.cc @@ -220,7 +220,7 @@ static void fl_key_channel_responder_handle_event( } int64_t scan_code = event->hardware_keycode; - int64_t unicodeScalarValues = gdk_keyval_to_unicode(event->keyval); + int64_t unicode_scarlar_values = gdk_keyval_to_unicode(event->keyval); // For most modifier keys, GTK keeps track of the "pressed" state of the // modifier keys. Flutter uses this information to keep modifier keys from @@ -280,7 +280,7 @@ static void fl_key_channel_responder_handle_event( fl_value_set_string_take(message, kKeyCodeKey, fl_value_new_int(event->keyval)); fl_value_set_string_take(message, kModifiersKey, fl_value_new_int(state)); - if (unicodeScalarValues != 0) { + if (unicode_scarlar_values != 0) { fl_value_set_string_take(message, kUnicodeScalarValuesKey, fl_value_new_int(unicodeScalarValues)); } diff --git a/shell/platform/linux/fl_key_channel_responder.h b/shell/platform/linux/fl_key_channel_responder.h index 3f0a1cda652d8..a1c5196c51fde 100644 --- a/shell/platform/linux/fl_key_channel_responder.h +++ b/shell/platform/linux/fl_key_channel_responder.h @@ -17,16 +17,19 @@ typedef FlValue* (*FlValueConverter)(FlValue*); /** * FlKeyChannelResponderMock: * - * Options to mock several functionalities. Only used in unittests. + * Allows mocking of FlKeyChannelResponder methods and values. Only used in unittests. */ typedef struct _FlKeyChannelResponderMock { /** * FlKeyChannelResponderMock::value_converter: + * If #value_converter is not nullptr, then this function is applied to the reply + * of the message, whose return value is taken as the message reply. */ FlValueConverter value_converter; /** * FlKeyChannelResponderMock::channel_name: + * Mocks the channel name to send the message. */ const char* channel_name; } FlKeyChannelResponderMock; @@ -46,7 +49,7 @@ G_DECLARE_FINAL_TYPE(FlKeyChannelResponder, * A #FlKeyResponder that handles events by sending the raw event data * in JSON through the message channel. * - * This class corresponds to the RawKeyboard API in the framework. + * This class communicates with the RawKeyboard API in the framework. */ /** diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index cda5ce8dc350e..545010022915e 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -236,6 +236,10 @@ static void fl_key_embedder_responder_dispose(GObject* object) { G_OBJECT_CLASS(fl_key_embedder_responder_parent_class)->dispose(object); } +// Fill in #physical_key_to_lock_bit by associating a physical key with +// its corresponding modifier bit. +// +// This is used as the body of a loop over #lock_bit_to_checked_keys. static void initialize_physical_key_to_lock_bit_loop_body(gpointer lock_bit, gpointer value, gpointer user_data) { @@ -247,11 +251,7 @@ static void initialize_physical_key_to_lock_bit_loop_body(gpointer lock_bit, GUINT_TO_POINTER(lock_bit)); } -// Creates a new FlKeyEmbedderResponder instance, with a messenger used to send -// messages to the framework, an FlTextInputPlugin used to handle key events -// that the framework doesn't handle. Mainly for testing purposes, it also takes -// an optional callback to call when a response is received, and an optional -// embedder name to use when sending messages. +// Creates a new FlKeyEmbedderResponder instance with an engine. FlKeyEmbedderResponder* fl_key_embedder_responder_new(FlEngine* engine) { g_return_val_if_fail(FL_IS_ENGINE(engine), nullptr); @@ -375,7 +375,10 @@ typedef struct { } // namespace -// The loop body to synchronize pressing states. +// Synchronizes the pressing state of a key to its state from the event by +// synthesizing events. +// +// This is used as the body of a loop over #modifier_bit_to_checked_keys. static void synchronize_pressed_states_loop_body(gpointer key, gpointer value, gpointer user_data) { @@ -402,14 +405,17 @@ static void synchronize_pressed_states_loop_body(gpointer key, lookup_hash_table(self->pressing_records, physical_key); // If this event is an event of the key, then the state will be flipped but // haven't reflected on the state. Flip it manually here. - const bool adjusted_this_key_pressed = - (pressed_logical_key != 0) ^ - (physical_key == context->event_physical_key); - if (adjusted_this_key_pressed) { + const bool this_key_is_event_key = physical_key + == context->event_physical_key; + const bool this_key_pressed_before_event = pressed_logical_key != 0; + const bool this_key_pressed_after_event = this_key_pressed_before_event + ^ this_key_is_event_key; + + if (this_key_pressed_after_event) { pressed_by_record = true; if (!pressed_by_state) { - g_return_if_fail(physical_key != context->event_physical_key); + g_return_if_fail(!this_key_is_event_key); synthesize_simple_event(self, kFlutterKeyEventTypeUp, physical_key, pressed_logical_key, context->timestamp); g_hash_table_remove(self->pressing_records, @@ -546,9 +552,12 @@ static void update_caps_lock_state_logic_inferrence( } } -// The loop body to synchronize lock states. +// Synchronizes the lock state of a key to its state from the event by +// synthesizing events. +// +// This is used as the body of a loop over #lock_bit_to_checked_keys. // -// This function might modify self->caps_lock_state_logic_inferrence. +// This function might modify #caps_lock_state_logic_inferrence. static void synchronize_lock_states_loop_body(gpointer key, gpointer value, gpointer user_data) { @@ -623,8 +632,7 @@ static void synchronize_lock_states_loop_body(gpointer key, return; } - const int standard_current_stage = - current_stage >= 4 ? current_stage - 4 : current_stage; + const int standard_current_stage = current_stage % kNumStages; const bool is_down_event = standard_current_stage == 0 || standard_current_stage == 2; FlutterKeyEventType type = diff --git a/shell/platform/linux/fl_key_embedder_responder.h b/shell/platform/linux/fl_key_embedder_responder.h index 7e2ede7aff347..e9ac6d5125a20 100644 --- a/shell/platform/linux/fl_key_embedder_responder.h +++ b/shell/platform/linux/fl_key_embedder_responder.h @@ -29,7 +29,7 @@ G_DECLARE_FINAL_TYPE(FlKeyEmbedderResponder, * A #FlKeyResponder that handles events by sending the converted events * through the embedder API. * - * This class corresponds to the HardwareKeyboard API in the framework. + * This class communicates with the HardwareKeyboard API in the framework. */ /** diff --git a/shell/platform/windows/keyboard_key_channel_handler.h b/shell/platform/windows/keyboard_key_channel_handler.h index ff9aa1a8cf4b6..57ade1e4e8513 100644 --- a/shell/platform/windows/keyboard_key_channel_handler.h +++ b/shell/platform/windows/keyboard_key_channel_handler.h @@ -19,7 +19,7 @@ namespace flutter { // A delegate of |KeyboardKeyHandler| that handles events by sending the // raw information through the method channel. // -// This class corresponds to the RawKeyboard API in the framework. +// This class communicates with the RawKeyboard API in the framework. class KeyboardKeyChannelHandler : public KeyboardKeyHandler::KeyboardKeyHandlerDelegate { public: diff --git a/shell/platform/windows/keyboard_key_embedder_handler.h b/shell/platform/windows/keyboard_key_embedder_handler.h index edc90f207b3c4..0f557d7b3f89b 100644 --- a/shell/platform/windows/keyboard_key_embedder_handler.h +++ b/shell/platform/windows/keyboard_key_embedder_handler.h @@ -20,7 +20,7 @@ namespace {} // namespace // A delegate of |KeyboardKeyHandler| that handles events by sending // converted |FlutterKeyEvent|s through the embedder API. // -// This class corresponds to the HardwareKeyboard API in the framework. +// This class communicates with the HardwareKeyboard API in the framework. class KeyboardKeyEmbedderHandler : public KeyboardKeyHandler::KeyboardKeyHandlerDelegate { public: From 5bbab533e0a8b3e39838bfea4ce05170a5c16ff9 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Thu, 6 May 2021 04:49:16 -0700 Subject: [PATCH 058/126] Use logical --- .../linux/fl_key_embedder_responder.cc | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index 545010022915e..8d52823c54230 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -236,18 +236,18 @@ static void fl_key_embedder_responder_dispose(GObject* object) { G_OBJECT_CLASS(fl_key_embedder_responder_parent_class)->dispose(object); } -// Fill in #physical_key_to_lock_bit by associating a physical key with +// Fill in #physical_key_to_lock_bit by associating a logical key with // its corresponding modifier bit. // // This is used as the body of a loop over #lock_bit_to_checked_keys. -static void initialize_physical_key_to_lock_bit_loop_body(gpointer lock_bit, - gpointer value, - gpointer user_data) { +static void initialize_logical_key_to_lock_bit_loop_body(gpointer lock_bit, + gpointer value, + gpointer user_data) { FlKeyEmbedderCheckedKey* checked_key = reinterpret_cast(value); GHashTable* table = reinterpret_cast(user_data); g_hash_table_insert(table, - uint64_to_gpointer(checked_key->primary_physical_key), + uint64_to_gpointer(checked_key->primary_logical_key), GUINT_TO_POINTER(lock_bit)); } @@ -282,11 +282,11 @@ FlKeyEmbedderResponder* fl_key_embedder_responder_new(FlEngine* engine) { g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free); initialize_lock_bit_to_checked_keys(self->lock_bit_to_checked_keys); - self->physical_key_to_lock_bit = + self->logical_key_to_lock_bit = g_hash_table_new(g_direct_hash, g_direct_equal); g_hash_table_foreach(self->lock_bit_to_checked_keys, - initialize_physical_key_to_lock_bit_loop_body, - self->physical_key_to_lock_bit); + initialize_logical_key_to_lock_bit_loop_body, + self->logical_key_to_lock_bit); return self; } @@ -462,13 +462,13 @@ static void update_pressing_state(FlKeyEmbedderResponder* self, // If `is_down` is false, this function is a no-op. Otherwise, this function // finds the lock bit corresponding to `physical_key`, and flips its bit. static void possibly_update_lock_bit(FlKeyEmbedderResponder* self, - uint64_t physical_key, + uint64_t logical_key, bool is_down) { if (!is_down) { return; } const guint mode_bit = GPOINTER_TO_UINT(g_hash_table_lookup( - self->physical_key_to_lock_bit, uint64_to_gpointer(physical_key))); + self->logical_key_to_lock_bit, uint64_to_gpointer(logical_key))); if (mode_bit != 0) { self->lock_records ^= mode_bit; } @@ -638,7 +638,7 @@ static void synchronize_lock_states_loop_body(gpointer key, FlutterKeyEventType type = is_down_event ? kFlutterKeyEventTypeDown : kFlutterKeyEventTypeUp; update_pressing_state(self, physical_key, is_down_event ? logical_key : 0); - possibly_update_lock_bit(self, physical_key, is_down_event); + possibly_update_lock_bit(self, logical_key, is_down_event); synthesize_simple_event(self, type, physical_key, logical_key, context->timestamp); } From c4f42978b0efcf13164abedd3bd66fed27891610 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Thu, 6 May 2021 05:16:02 -0700 Subject: [PATCH 059/126] ATP --- shell/platform/linux/fl_key_channel_responder.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/platform/linux/fl_key_channel_responder.cc b/shell/platform/linux/fl_key_channel_responder.cc index f6b693c3be627..d226d8ff45d0a 100644 --- a/shell/platform/linux/fl_key_channel_responder.cc +++ b/shell/platform/linux/fl_key_channel_responder.cc @@ -282,7 +282,7 @@ static void fl_key_channel_responder_handle_event( fl_value_set_string_take(message, kModifiersKey, fl_value_new_int(state)); if (unicode_scarlar_values != 0) { fl_value_set_string_take(message, kUnicodeScalarValuesKey, - fl_value_new_int(unicodeScalarValues)); + fl_value_new_int(unicode_scarlar_values)); } FlKeyChannelUserData* data = From 764cb715a792bcac9dce5e40e8ff22bacf601570 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Fri, 7 May 2021 02:38:01 -0700 Subject: [PATCH 060/126] Remapp synth --- .../linux/fl_key_embedder_responder.cc | 147 ++++++++++------ .../linux/fl_key_embedder_responder_test.cc | 160 +++++++++++++++++- 2 files changed, 256 insertions(+), 51 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index 8d52823c54230..9d699f5641405 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -18,6 +18,11 @@ constexpr uint64_t kGtkKeyIdPlane = 0x00600000000; constexpr uint64_t kMicrosecondsPerMillisecond = 1000; +// Look up a hash table that maps a uint64_t to a uint64_t. +// +// Returns 0 if not found. +// +// Both key and value should be directly hashed. static uint64_t lookup_hash_table(GHashTable* table, uint64_t key) { return gpointer_to_uint64( g_hash_table_lookup(table, uint64_to_gpointer(key))); @@ -149,8 +154,17 @@ struct _FlKeyEmbedderResponder { // It is a bit mask composed of GTK mode bits. guint lock_records; - // The inferred mode indicating whether the CapsLock state logic is reversed - // on this platform. + // Internal record for the last observed key mapping. + // + // It stores the physical key last seen during a key down event for a logical + // key. It is used to synthesize modifier keys and lock keys. + // + // It is a map from Flutter logical key to physical key. Both keys and + // values are directly stored uint64s. This table is freed by the responder. + GHashTable* mapping_records; + + // The inferred logic type indicating whether the CapsLock state logic is + // reversed on this platform. // // For more information, see #update_caps_lock_state_logic_inferrence. StateLogicInferrence caps_lock_state_logic_inferrence; @@ -265,6 +279,7 @@ FlKeyEmbedderResponder* fl_key_embedder_responder_new(FlEngine* engine) { reinterpret_cast(&(self->engine))); self->pressing_records = g_hash_table_new(g_direct_hash, g_direct_equal); + self->mapping_records = g_hash_table_new(g_direct_hash, g_direct_equal); self->lock_records = 0; self->caps_lock_state_logic_inferrence = kStateLogicUndecided; @@ -375,6 +390,28 @@ typedef struct { } // namespace +// Update the pressing record. +// +// If `logical_key` is 0, the record will be set as "released". Otherwise, the +// record will be set as "pressed" with this logical key. This function asserts +// that the key is pressed if the caller asked to release, and vice versa. +static void update_pressing_state(FlKeyEmbedderResponder* self, + uint64_t physical_key, + uint64_t logical_key) { + if (logical_key != 0) { + g_return_if_fail(lookup_hash_table(self->pressing_records, physical_key) == + 0); + g_hash_table_insert(self->pressing_records, + uint64_to_gpointer(physical_key), + uint64_to_gpointer(logical_key)); + } else { + g_return_if_fail(lookup_hash_table(self->pressing_records, physical_key) != + 0); + g_hash_table_remove(self->pressing_records, + uint64_to_gpointer(physical_key)); + } +} + // Synchronizes the pressing state of a key to its state from the event by // synthesizing events. // @@ -398,13 +435,12 @@ static void synchronize_pressed_states_loop_body(gpointer key, const bool pressed_by_state = (context->state & modifier_bit) != 0; bool pressed_by_record = false; + // If the modifier should not be pressed, release all keys. for (guint physical_key_idx = 0; physical_key_idx < length; physical_key_idx++) { const uint64_t physical_key = physical_keys[physical_key_idx]; const uint64_t pressed_logical_key = lookup_hash_table(self->pressing_records, physical_key); - // If this event is an event of the key, then the state will be flipped but - // haven't reflected on the state. Flip it manually here. const bool this_key_is_event_key = physical_key == context->event_physical_key; @@ -418,42 +454,29 @@ static void synchronize_pressed_states_loop_body(gpointer key, g_return_if_fail(!this_key_is_event_key); synthesize_simple_event(self, kFlutterKeyEventTypeUp, physical_key, pressed_logical_key, context->timestamp); - g_hash_table_remove(self->pressing_records, - uint64_to_gpointer(physical_key)); + update_pressing_state(self, physical_key, 0); } } } + // If the modifier should be pressed, press its primary key. if (pressed_by_state && !pressed_by_record) { - uint64_t physical_key = checked_key->primary_physical_key; + const uint64_t logical_key = checked_key->primary_logical_key; + const uint64_t record_physical_key = lookup_hash_table(self->mapping_records, + logical_key); + // The physical key is derived from past mapping record if possible. + // + // The event to be synthesized is a key down event. There might not have + // been a mapping record, in which case the hard-coded #primary_physical_key + // is used. + const uint64_t physical_key = record_physical_key != 0 ? record_physical_key : + checked_key->primary_physical_key; + if (record_physical_key == 0) { + update_mapping_record(self, physical_key, logical_key); + } g_return_if_fail(physical_key != context->event_physical_key); - uint64_t logical_key = checked_key->primary_logical_key; synthesize_simple_event(self, kFlutterKeyEventTypeDown, physical_key, logical_key, context->timestamp); - g_hash_table_insert(self->pressing_records, - uint64_to_gpointer(physical_key), - uint64_to_gpointer(logical_key)); - } -} - -// Update the pressing record. -// -// If `logical_key` is 0, the record will be set as "released". Otherwise, the -// record will be set as "pressed" with this logical key. This function asserts -// that the key is pressed if the caller asked to release, and vice versa. -static void update_pressing_state(FlKeyEmbedderResponder* self, - uint64_t physical_key, - uint64_t logical_key) { - if (logical_key != 0) { - g_return_if_fail(lookup_hash_table(self->pressing_records, physical_key) == - 0); - g_hash_table_insert(self->pressing_records, - uint64_to_gpointer(physical_key), - uint64_to_gpointer(logical_key)); - } else { - g_return_if_fail(lookup_hash_table(self->pressing_records, physical_key) != - 0); - g_hash_table_remove(self->pressing_records, - uint64_to_gpointer(physical_key)); + update_pressing_state(self, physical_key, logical_key); } } @@ -474,6 +497,14 @@ static void possibly_update_lock_bit(FlKeyEmbedderResponder* self, } } +static void update_mapping_record(FlKeyEmbedderResponder* self, + uint64_t physical_key, + uint64_t logical_key) { + g_hash_table_insert(self->mapping_records, + uint64_to_gpointer(logical_key), + uint64_to_gpointer(physical_key)); +} + // Find the stage # by the current record, which should be the recorded stage // before the event. static int find_stage_by_record(bool is_down, bool is_enabled) { @@ -515,22 +546,21 @@ static int find_stage_by_others_event(int stage_by_record, bool is_state_on) { return stage_by_record; } -// Infer caps_lock_state_logic_inferrence if applicable. +// Infer the logic type of CapsLock on the current platform if applicable. // // In most cases, when a lock key is pressed or released, its event has the // key's state as 0-1-1-1 for the 4 stages (as documented in // #synchronize_lock_states_loop_body) respectively. But in very rare cases it // produces 1-1-0-1, which we call "reversed state logic". This is observed -// when using Chrome Remote Desktop on macOS. +// when using Chrome Remote Desktop on macOS (likely a bug). // -// To detect whether the current platform is normal or reversed, this function -// is called on the first down event of CapsLock before calculating stages. -// This function then store the inferred mode as +// To detect whether the current platform behaves normally or reversed, this +// function is called on the first down event of CapsLock before calculating +// stages. This function then store the inferred mode as // self->caps_lock_state_logic_inferrence. // -// Note that this does not help if the same app session is used alternatively -// between a reversed platform and a normal platform. But this is the best we -// can do. +// This does not help if the same app session is used alternatively between a +// reversed platform and a normal platform. But this is the best we can do. static void update_caps_lock_state_logic_inferrence( FlKeyEmbedderResponder* self, bool is_down_event, @@ -570,13 +600,28 @@ static void synchronize_lock_states_loop_body(gpointer key, FlKeyEmbedderResponder* self = context->self; const uint64_t logical_key = checked_key->primary_logical_key; - const uint64_t physical_key = checked_key->primary_physical_key; + const uint64_t record_physical_key = lookup_hash_table(self->mapping_records, + logical_key); + // The physical key is derived from past mapping record if possible. + // + // If the event to be synthesized is a key up event, then there must have + // been a key down event before, which has updated the mapping record. + // If the event to be synthesized is a key down event, then there might + // not have been a mapping record, in which case the hard-coded + // #primary_physical_key is used. + const uint64_t physical_key = record_physical_key != 0 ? record_physical_key : + checked_key->primary_physical_key; + if (record_physical_key == 0) { + update_mapping_record(self, physical_key, logical_key); + } - // A lock mode key can be at any of a 4-stage cycle. The following table lists - // the definition of each stage (TruePressed and TrueEnabled), the event of - // the lock key between every 2 stages (SelfType and SelfState), and the event - // of other keys at each stage (OthersState). Notice that on certain platforms - // SelfState uses a reversed rule for certain keys (SelfState(rvsd)). + // A lock mode key can be at any of a 4-stage cycle, depending on whether it's + // pressed and enabled. The following table lists the definition of each + // stage (TruePressed and TrueEnabled), the event of the lock key between + // every 2 stages (SelfType and SelfState), and the event of other keys at + // each stage (OthersState). On certain platforms SelfState uses a reversed + // rule for certain keys (SelfState(rvsd), as documented in + // #update_caps_lock_state_logic_inferrence). // // # [0] [1] [2] [3] // TruePressed: Released Pressed Released Pressed @@ -586,8 +631,8 @@ static void synchronize_lock_states_loop_body(gpointer key, // SelfState(rvsd): 1 1 0 1 // OthersState: 0 1 1 1 // - // Except for stage 0, we can't derive the exact stage just from event - // information. Choose the stage that requires the minimal synthesization. + // When the exact stage can't be derived, choose the stage that requires the + // minimal synthesization. const uint64_t pressed_logical_key = lookup_hash_table(self->pressing_records, physical_key); @@ -662,6 +707,10 @@ static void fl_key_embedder_responder_handle_event( const double timestamp = event_to_timestamp(event); const bool is_down_event = event->type == GDK_KEY_PRESS; + if (is_down_event) { + update_mapping_record(self, physical_key, logical_key); + } + SyncStateLoopContext sync_pressed_state_context; sync_pressed_state_context.self = self; sync_pressed_state_context.state = event->state; diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index 1b07521d2cce0..d6a0e438fa405 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -23,6 +23,7 @@ constexpr guint16 kKeyCodeShiftRight = 0x3Eu; constexpr guint16 kKeyCodeNumpad1 = 0x57u; constexpr guint16 kKeyCodeNumLock = 0x4Du; constexpr guint16 kKeyCodeCapsLock = 0x42u; +constexpr guint16 kKeyCodeControlLeft = 0x25u; constexpr uint64_t kPhysicalKeyA = 0x00070004; constexpr uint64_t kPhysicalControlLeft = 0x000700e0; @@ -914,7 +915,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingState) { // A key down of control left is missed. guint state = GDK_CONTROL_MASK; - // Send a normal event + // Send a normal event (KeyA down) fl_key_responder_handle_event( responder, key_event_new(101, kPress, GDK_KEY_a, kKeyCodeKeyA, state, @@ -944,7 +945,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingState) { // A key up of control right is missed. state = 0; - // Release key A + // Send a normal event (KeyA up) fl_key_responder_handle_event( responder, key_event_new(102, kRelease, GDK_KEY_A, kKeyCodeKeyA, state, @@ -971,6 +972,59 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingState) { invoke_record_callback_and_verify(record, TRUE, &user_data); g_ptr_array_clear(g_call_records); + // Press physical CapsLock remapped to logical ControlLeft. + + guint state = GDK_CONTROL_MASK; + + fl_key_responder_handle_event( + responder, + key_event_new(101, kPress, GDK_KEY_Caps_Lock, kKeyCodeControlLeft, state, + kIsModifier), + verify_response_handled, &user_data); + + EXPECT_EQ(g_call_records->len, 2u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->timestamp, 101000); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->physical, kPhysicalCapsLock); + EXPECT_EQ(record->event->logical, kLogicalControlLeft); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + // The key up of the control left press is missed. + state = 0; + + // Send a normal event (KeyA down). + fl_key_responder_handle_event( + responder, + key_event_new(102, kRelease, GDK_KEY_A, kKeyCodeKeyA, state, + kIsNotModifier), + verify_response_handled, &user_data); + + // The synthesized event should have physical CapsLock and logical ControlLeft. + EXPECT_EQ(g_call_records->len, 2u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->timestamp, 102000); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); + EXPECT_EQ(record->event->physical, kPhysicalKeyCapsLock); + EXPECT_EQ(record->event->logical, kLogicalControlLeft); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, true); + + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 1)); + EXPECT_EQ(record->event->timestamp, 102000); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->physical, kPhysicalKeyA); + EXPECT_EQ(record->event->logical, kLogicalKeyA); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + clear_g_call_records(); } @@ -1076,6 +1130,108 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { clear_g_call_records(); } +// Test if missed lock keys can be detected and synthesized with state +// information upon events that are not for this modifier key. +TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEventsRemapped) { + EXPECT_EQ(g_call_records, nullptr); + g_call_records = g_ptr_array_new_with_free_func(g_object_unref); + g_autoptr(FlEngine) engine = make_mock_engine_with_records(); + g_autoptr(FlKeyResponder) responder = + FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); + int user_data = 123; // Arbitrary user data + + FlKeyEmbedderCallRecord* record; + + // The NumLock is desynchronized by being enabled. + guint state = GDK_MOD2_MASK; + + // Send a normal event + fl_key_responder_handle_event( + responder, + key_event_new(101, kPress, GDK_KEY_a, kKeyCodeKeyA, state, + kIsNotModifier), + verify_response_handled, &user_data); + + EXPECT_EQ(g_call_records->len, 2u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->timestamp, 101000); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); + EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, true); + + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 1)); + EXPECT_EQ(record->event->timestamp, 101000); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->physical, kPhysicalKeyA); + EXPECT_EQ(record->event->logical, kLogicalKeyA); + EXPECT_STREQ(record->event->character, "a"); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + // The NumLock is desynchronized by being disabled. + state = 0; + + // Release key A + fl_key_responder_handle_event( + responder, + key_event_new(102, kRelease, GDK_KEY_A, kKeyCodeKeyA, state, + kIsNotModifier), + verify_response_handled, &user_data); + + EXPECT_EQ(g_call_records->len, 4u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->timestamp, 102000); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); + EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); + EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, true); + + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 1)); + EXPECT_EQ(record->event->timestamp, 102000); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); + EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, true); + + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 2)); + EXPECT_EQ(record->event->timestamp, 102000); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); + EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); + EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, true); + + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 3)); + EXPECT_EQ(record->event->timestamp, 102000); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); + EXPECT_EQ(record->event->physical, kPhysicalKeyA); + EXPECT_EQ(record->event->logical, kLogicalKeyA); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + // Release NumLock. Since the previous event should have synthesized NumLock + // to be released, this should result in no events. + g_expected_handled = true; + fl_key_responder_handle_event( + responder, + key_event_new(103, kRelease, GDK_KEY_Num_Lock, kKeyCodeNumLock, state, + kIsModifier), + verify_response_handled, &user_data); + + EXPECT_EQ(g_call_records->len, 0u); + + clear_g_call_records(); +} + // Test if missed lock keys can be detected and synthesized with state // information upon events that are for this modifier key. TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) { From d045347378ecd8665a0efa268b5e56402cd15bfb Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Fri, 7 May 2021 02:49:11 -0700 Subject: [PATCH 061/126] Compile --- .../linux/fl_key_embedder_responder.cc | 55 +++---- .../linux/fl_key_embedder_responder_test.cc | 140 +++++++++--------- 2 files changed, 98 insertions(+), 97 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index 9d699f5641405..8c2d9e0b9ae53 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -201,7 +201,7 @@ struct _FlKeyEmbedderResponder { // // It is a map from primary physical keys to lock bits. Both keys and values // are directly stored uint64s. This table is freed by the responder. - GHashTable* physical_key_to_lock_bit; + GHashTable* logical_key_to_lock_bit; }; static void fl_key_embedder_responder_iface_init( @@ -250,7 +250,7 @@ static void fl_key_embedder_responder_dispose(GObject* object) { G_OBJECT_CLASS(fl_key_embedder_responder_parent_class)->dispose(object); } -// Fill in #physical_key_to_lock_bit by associating a logical key with +// Fill in #logical_key_to_lock_bit by associating a logical key with // its corresponding modifier bit. // // This is used as the body of a loop over #lock_bit_to_checked_keys. @@ -412,6 +412,31 @@ static void update_pressing_state(FlKeyEmbedderResponder* self, } } +// Update the lock record. +// +// If `is_down` is false, this function is a no-op. Otherwise, this function +// finds the lock bit corresponding to `physical_key`, and flips its bit. +static void possibly_update_lock_bit(FlKeyEmbedderResponder* self, + uint64_t logical_key, + bool is_down) { + if (!is_down) { + return; + } + const guint mode_bit = GPOINTER_TO_UINT(g_hash_table_lookup( + self->logical_key_to_lock_bit, uint64_to_gpointer(logical_key))); + if (mode_bit != 0) { + self->lock_records ^= mode_bit; + } +} + +static void update_mapping_record(FlKeyEmbedderResponder* self, + uint64_t physical_key, + uint64_t logical_key) { + g_hash_table_insert(self->mapping_records, + uint64_to_gpointer(logical_key), + uint64_to_gpointer(physical_key)); +} + // Synchronizes the pressing state of a key to its state from the event by // synthesizing events. // @@ -480,31 +505,6 @@ static void synchronize_pressed_states_loop_body(gpointer key, } } -// Update the lock record. -// -// If `is_down` is false, this function is a no-op. Otherwise, this function -// finds the lock bit corresponding to `physical_key`, and flips its bit. -static void possibly_update_lock_bit(FlKeyEmbedderResponder* self, - uint64_t logical_key, - bool is_down) { - if (!is_down) { - return; - } - const guint mode_bit = GPOINTER_TO_UINT(g_hash_table_lookup( - self->logical_key_to_lock_bit, uint64_to_gpointer(logical_key))); - if (mode_bit != 0) { - self->lock_records ^= mode_bit; - } -} - -static void update_mapping_record(FlKeyEmbedderResponder* self, - uint64_t physical_key, - uint64_t logical_key) { - g_hash_table_insert(self->mapping_records, - uint64_to_gpointer(logical_key), - uint64_to_gpointer(physical_key)); -} - // Find the stage # by the current record, which should be the recorded stage // before the event. static int find_stage_by_record(bool is_down, bool is_enabled) { @@ -696,6 +696,7 @@ static void fl_key_embedder_responder_handle_event( FlKeyResponderAsyncCallback callback, gpointer user_data) { FlKeyEmbedderResponder* self = FL_KEY_EMBEDDER_RESPONDER(responder); + printf("ev scan %hx\n", event->hardware_keycode);fflush(stdout); g_return_if_fail(event != nullptr); g_return_if_fail(callback != nullptr); diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index d6a0e438fa405..c3e1ee99c5a51 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -28,17 +28,17 @@ constexpr guint16 kKeyCodeControlLeft = 0x25u; constexpr uint64_t kPhysicalKeyA = 0x00070004; constexpr uint64_t kPhysicalControlLeft = 0x000700e0; constexpr uint64_t kPhysicalShiftRight = 0x000700E5; -constexpr uint64_t kPhysicalKeyNumpad1 = 0x00070059; -constexpr uint64_t kPhysicalKeyNumLock = 0x00070053; -constexpr uint64_t kPhysicalKeyCapsLock = 0x00070039; +constexpr uint64_t kPhysicalNumpad1 = 0x00070059; +constexpr uint64_t kPhysicalNumLock = 0x00070053; +constexpr uint64_t kPhysicalCapsLock = 0x00070039; constexpr uint64_t kLogicalKeyA = 0x00000061; constexpr uint64_t kLogicalKeyQ = 0x00000071; constexpr uint64_t kLogicalControlLeft = 0x30000000105; constexpr uint64_t kLogicalShiftRight = 0x4000000010D; -constexpr uint64_t kLogicalKeyNumpad1 = 0x50000000031; -constexpr uint64_t kLogicalKeyNumLock = 0x100000010A; -constexpr uint64_t kLogicalKeyCapsLock = 0x1000000104; +constexpr uint64_t kLogicalNumpad1 = 0x50000000031; +constexpr uint64_t kLogicalNumLock = 0x100000010A; +constexpr uint64_t kLogicalCapsLock = 0x1000000104; } // namespace static void g_ptr_array_clear(GPtrArray* array) { @@ -379,8 +379,8 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); - EXPECT_EQ(record->event->physical, kPhysicalKeyNumpad1); - EXPECT_EQ(record->event->logical, kLogicalKeyNumpad1); + EXPECT_EQ(record->event->physical, kPhysicalNumpad1); + EXPECT_EQ(record->event->logical, kLogicalNumpad1); EXPECT_STREQ(record->event->character, nullptr); // TODO EXPECT_EQ(record->event->synthesized, false); @@ -397,8 +397,8 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); - EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); - EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); + EXPECT_EQ(record->event->physical, kPhysicalNumLock); + EXPECT_EQ(record->event->logical, kLogicalNumLock); EXPECT_STREQ(record->event->character, nullptr); EXPECT_EQ(record->event->synthesized, false); @@ -415,8 +415,8 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); - EXPECT_EQ(record->event->physical, kPhysicalKeyNumpad1); - EXPECT_EQ(record->event->logical, kLogicalKeyNumpad1); + EXPECT_EQ(record->event->physical, kPhysicalNumpad1); + EXPECT_EQ(record->event->logical, kLogicalNumpad1); EXPECT_STREQ(record->event->character, nullptr); EXPECT_EQ(record->event->synthesized, false); @@ -433,8 +433,8 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); - EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); - EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); + EXPECT_EQ(record->event->physical, kPhysicalNumLock); + EXPECT_EQ(record->event->logical, kLogicalNumLock); EXPECT_STREQ(record->event->character, nullptr); EXPECT_EQ(record->event->synthesized, false); @@ -451,8 +451,8 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); - EXPECT_EQ(record->event->physical, kPhysicalKeyNumpad1); - EXPECT_EQ(record->event->logical, kLogicalKeyNumpad1); + EXPECT_EQ(record->event->physical, kPhysicalNumpad1); + EXPECT_EQ(record->event->logical, kLogicalNumpad1); EXPECT_STREQ(record->event->character, nullptr); // TODO EXPECT_EQ(record->event->synthesized, false); @@ -469,8 +469,8 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); - EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); - EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); + EXPECT_EQ(record->event->physical, kPhysicalNumLock); + EXPECT_EQ(record->event->logical, kLogicalNumLock); EXPECT_STREQ(record->event->character, nullptr); EXPECT_EQ(record->event->synthesized, false); @@ -487,8 +487,8 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); - EXPECT_EQ(record->event->physical, kPhysicalKeyNumpad1); - EXPECT_EQ(record->event->logical, kLogicalKeyNumpad1); + EXPECT_EQ(record->event->physical, kPhysicalNumpad1); + EXPECT_EQ(record->event->logical, kLogicalNumpad1); EXPECT_STREQ(record->event->character, nullptr); EXPECT_EQ(record->event->synthesized, false); @@ -505,8 +505,8 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); - EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); - EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); + EXPECT_EQ(record->event->physical, kPhysicalNumLock); + EXPECT_EQ(record->event->logical, kLogicalNumLock); EXPECT_STREQ(record->event->character, nullptr); EXPECT_EQ(record->event->synthesized, false); @@ -540,8 +540,8 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); - EXPECT_EQ(record->event->physical, kPhysicalKeyCapsLock); - EXPECT_EQ(record->event->logical, kLogicalKeyCapsLock); + EXPECT_EQ(record->event->physical, kPhysicalCapsLock); + EXPECT_EQ(record->event->logical, kLogicalCapsLock); EXPECT_STREQ(record->event->character, nullptr); EXPECT_EQ(record->event->synthesized, false); @@ -575,8 +575,8 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); - EXPECT_EQ(record->event->physical, kPhysicalKeyCapsLock); - EXPECT_EQ(record->event->logical, kLogicalKeyCapsLock); + EXPECT_EQ(record->event->physical, kPhysicalCapsLock); + EXPECT_EQ(record->event->logical, kLogicalCapsLock); EXPECT_STREQ(record->event->character, nullptr); EXPECT_EQ(record->event->synthesized, false); @@ -611,8 +611,8 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); - EXPECT_EQ(record->event->physical, kPhysicalKeyCapsLock); - EXPECT_EQ(record->event->logical, kLogicalKeyCapsLock); + EXPECT_EQ(record->event->physical, kPhysicalCapsLock); + EXPECT_EQ(record->event->logical, kLogicalCapsLock); EXPECT_STREQ(record->event->character, nullptr); EXPECT_EQ(record->event->synthesized, false); @@ -646,8 +646,8 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); - EXPECT_EQ(record->event->physical, kPhysicalKeyCapsLock); - EXPECT_EQ(record->event->logical, kLogicalKeyCapsLock); + EXPECT_EQ(record->event->physical, kPhysicalCapsLock); + EXPECT_EQ(record->event->logical, kLogicalCapsLock); EXPECT_STREQ(record->event->character, nullptr); EXPECT_EQ(record->event->synthesized, false); @@ -716,8 +716,8 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); - EXPECT_EQ(record->event->physical, kPhysicalKeyCapsLock); - EXPECT_EQ(record->event->logical, kLogicalKeyCapsLock); + EXPECT_EQ(record->event->physical, kPhysicalCapsLock); + EXPECT_EQ(record->event->logical, kLogicalCapsLock); EXPECT_STREQ(record->event->character, nullptr); EXPECT_EQ(record->event->synthesized, false); @@ -734,8 +734,8 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); - EXPECT_EQ(record->event->physical, kPhysicalKeyCapsLock); - EXPECT_EQ(record->event->logical, kLogicalKeyCapsLock); + EXPECT_EQ(record->event->physical, kPhysicalCapsLock); + EXPECT_EQ(record->event->logical, kLogicalCapsLock); EXPECT_STREQ(record->event->character, nullptr); EXPECT_EQ(record->event->synthesized, false); @@ -787,8 +787,8 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); - EXPECT_EQ(record->event->physical, kPhysicalKeyCapsLock); - EXPECT_EQ(record->event->logical, kLogicalKeyCapsLock); + EXPECT_EQ(record->event->physical, kPhysicalCapsLock); + EXPECT_EQ(record->event->logical, kLogicalCapsLock); EXPECT_STREQ(record->event->character, nullptr); EXPECT_EQ(record->event->synthesized, false); @@ -805,8 +805,8 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); - EXPECT_EQ(record->event->physical, kPhysicalKeyCapsLock); - EXPECT_EQ(record->event->logical, kLogicalKeyCapsLock); + EXPECT_EQ(record->event->physical, kPhysicalCapsLock); + EXPECT_EQ(record->event->logical, kLogicalCapsLock); EXPECT_STREQ(record->event->character, nullptr); EXPECT_EQ(record->event->synthesized, false); @@ -974,7 +974,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingState) { // Press physical CapsLock remapped to logical ControlLeft. - guint state = GDK_CONTROL_MASK; + state = GDK_CONTROL_MASK; fl_key_responder_handle_event( responder, @@ -1009,7 +1009,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingState) { record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); EXPECT_EQ(record->event->timestamp, 102000); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); - EXPECT_EQ(record->event->physical, kPhysicalKeyCapsLock); + EXPECT_EQ(record->event->physical, kPhysicalCapsLock); EXPECT_EQ(record->event->logical, kLogicalControlLeft); EXPECT_STREQ(record->event->character, nullptr); EXPECT_EQ(record->event->synthesized, true); @@ -1054,8 +1054,8 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); EXPECT_EQ(record->event->timestamp, 101000); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); - EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); - EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); + EXPECT_EQ(record->event->physical, kPhysicalNumLock); + EXPECT_EQ(record->event->logical, kLogicalNumLock); EXPECT_STREQ(record->event->character, nullptr); EXPECT_EQ(record->event->synthesized, true); @@ -1084,24 +1084,24 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); EXPECT_EQ(record->event->timestamp, 102000); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); - EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); - EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); + EXPECT_EQ(record->event->physical, kPhysicalNumLock); + EXPECT_EQ(record->event->logical, kLogicalNumLock); EXPECT_STREQ(record->event->character, nullptr); EXPECT_EQ(record->event->synthesized, true); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 1)); EXPECT_EQ(record->event->timestamp, 102000); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); - EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); - EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); + EXPECT_EQ(record->event->physical, kPhysicalNumLock); + EXPECT_EQ(record->event->logical, kLogicalNumLock); EXPECT_STREQ(record->event->character, nullptr); EXPECT_EQ(record->event->synthesized, true); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 2)); EXPECT_EQ(record->event->timestamp, 102000); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); - EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); - EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); + EXPECT_EQ(record->event->physical, kPhysicalNumLock); + EXPECT_EQ(record->event->logical, kLogicalNumLock); EXPECT_STREQ(record->event->character, nullptr); EXPECT_EQ(record->event->synthesized, true); @@ -1156,8 +1156,8 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEventsRemapped record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); EXPECT_EQ(record->event->timestamp, 101000); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); - EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); - EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); + EXPECT_EQ(record->event->physical, kPhysicalNumLock); + EXPECT_EQ(record->event->logical, kLogicalNumLock); EXPECT_STREQ(record->event->character, nullptr); EXPECT_EQ(record->event->synthesized, true); @@ -1186,24 +1186,24 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEventsRemapped record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); EXPECT_EQ(record->event->timestamp, 102000); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); - EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); - EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); + EXPECT_EQ(record->event->physical, kPhysicalNumLock); + EXPECT_EQ(record->event->logical, kLogicalNumLock); EXPECT_STREQ(record->event->character, nullptr); EXPECT_EQ(record->event->synthesized, true); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 1)); EXPECT_EQ(record->event->timestamp, 102000); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); - EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); - EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); + EXPECT_EQ(record->event->physical, kPhysicalNumLock); + EXPECT_EQ(record->event->logical, kLogicalNumLock); EXPECT_STREQ(record->event->character, nullptr); EXPECT_EQ(record->event->synthesized, true); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 2)); EXPECT_EQ(record->event->timestamp, 102000); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); - EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); - EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); + EXPECT_EQ(record->event->physical, kPhysicalNumLock); + EXPECT_EQ(record->event->logical, kLogicalNumLock); EXPECT_STREQ(record->event->character, nullptr); EXPECT_EQ(record->event->synthesized, true); @@ -1258,24 +1258,24 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) { record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); EXPECT_EQ(record->event->timestamp, 101000); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); - EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); - EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); + EXPECT_EQ(record->event->physical, kPhysicalNumLock); + EXPECT_EQ(record->event->logical, kLogicalNumLock); EXPECT_STREQ(record->event->character, nullptr); EXPECT_EQ(record->event->synthesized, true); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 1)); EXPECT_EQ(record->event->timestamp, 101000); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); - EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); - EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); + EXPECT_EQ(record->event->physical, kPhysicalNumLock); + EXPECT_EQ(record->event->logical, kLogicalNumLock); EXPECT_STREQ(record->event->character, nullptr); EXPECT_EQ(record->event->synthesized, true); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 2)); EXPECT_EQ(record->event->timestamp, 101000); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); - EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); - EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); + EXPECT_EQ(record->event->physical, kPhysicalNumLock); + EXPECT_EQ(record->event->logical, kLogicalNumLock); EXPECT_STREQ(record->event->character, nullptr); EXPECT_EQ(record->event->synthesized, false); @@ -1296,32 +1296,32 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) { record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); EXPECT_EQ(record->event->timestamp, 102000); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); - EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); - EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); + EXPECT_EQ(record->event->physical, kPhysicalNumLock); + EXPECT_EQ(record->event->logical, kLogicalNumLock); EXPECT_STREQ(record->event->character, nullptr); EXPECT_EQ(record->event->synthesized, true); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 1)); EXPECT_EQ(record->event->timestamp, 102000); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); - EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); - EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); + EXPECT_EQ(record->event->physical, kPhysicalNumLock); + EXPECT_EQ(record->event->logical, kLogicalNumLock); EXPECT_STREQ(record->event->character, nullptr); EXPECT_EQ(record->event->synthesized, true); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 2)); EXPECT_EQ(record->event->timestamp, 102000); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); - EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); - EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); + EXPECT_EQ(record->event->physical, kPhysicalNumLock); + EXPECT_EQ(record->event->logical, kLogicalNumLock); EXPECT_STREQ(record->event->character, nullptr); EXPECT_EQ(record->event->synthesized, true); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 3)); EXPECT_EQ(record->event->timestamp, 102000); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); - EXPECT_EQ(record->event->physical, kPhysicalKeyNumLock); - EXPECT_EQ(record->event->logical, kLogicalKeyNumLock); + EXPECT_EQ(record->event->physical, kPhysicalNumLock); + EXPECT_EQ(record->event->logical, kLogicalNumLock); EXPECT_STREQ(record->event->character, nullptr); EXPECT_EQ(record->event->synthesized, false); From 6ecfeb8f61f19fd00f3912ae6a0ea15c95693265 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Fri, 7 May 2021 05:35:57 -0700 Subject: [PATCH 062/126] ATP except for new test --- .../platform/linux/fl_key_channel_responder.h | 7 +- .../linux/fl_key_embedder_responder.cc | 142 +++++++++++------- .../linux/fl_key_embedder_responder_private.h | 8 +- .../linux/fl_key_embedder_responder_test.cc | 10 +- shell/platform/linux/key_mapping.cc | 28 ++-- 5 files changed, 116 insertions(+), 79 deletions(-) diff --git a/shell/platform/linux/fl_key_channel_responder.h b/shell/platform/linux/fl_key_channel_responder.h index a1c5196c51fde..7337dfdc9819e 100644 --- a/shell/platform/linux/fl_key_channel_responder.h +++ b/shell/platform/linux/fl_key_channel_responder.h @@ -17,13 +17,14 @@ typedef FlValue* (*FlValueConverter)(FlValue*); /** * FlKeyChannelResponderMock: * - * Allows mocking of FlKeyChannelResponder methods and values. Only used in unittests. + * Allows mocking of FlKeyChannelResponder methods and values. Only used in + * unittests. */ typedef struct _FlKeyChannelResponderMock { /** * FlKeyChannelResponderMock::value_converter: - * If #value_converter is not nullptr, then this function is applied to the reply - * of the message, whose return value is taken as the message reply. + * If #value_converter is not nullptr, then this function is applied to the + * reply of the message, whose return value is taken as the message reply. */ FlValueConverter value_converter; diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index 8c2d9e0b9ae53..a29517f6dd020 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -383,7 +383,7 @@ namespace { typedef struct { FlKeyEmbedderResponder* self; guint state; - uint64_t event_physical_key; + uint64_t event_logical_key; bool is_down; double timestamp; } SyncStateLoopContext; @@ -430,11 +430,10 @@ static void possibly_update_lock_bit(FlKeyEmbedderResponder* self, } static void update_mapping_record(FlKeyEmbedderResponder* self, - uint64_t physical_key, - uint64_t logical_key) { - g_hash_table_insert(self->mapping_records, - uint64_to_gpointer(logical_key), - uint64_to_gpointer(physical_key)); + uint64_t physical_key, + uint64_t logical_key) { + g_hash_table_insert(self->mapping_records, uint64_to_gpointer(logical_key), + uint64_to_gpointer(physical_key)); } // Synchronizes the pressing state of a key to its state from the event by @@ -451,54 +450,78 @@ static void synchronize_pressed_states_loop_body(gpointer key, const guint modifier_bit = GPOINTER_TO_INT(key); FlKeyEmbedderResponder* self = context->self; - const uint64_t physical_keys[] = { - checked_key->primary_physical_key, - checked_key->secondary_physical_key, + const uint64_t logical_keys[] = { + checked_key->primary_logical_key, + checked_key->secondary_logical_key, }; - const guint length = checked_key->secondary_physical_key == 0 ? 1 : 2; + const guint length = checked_key->secondary_logical_key == 0 ? 1 : 2; const bool pressed_by_state = (context->state & modifier_bit) != 0; + bool pressed_by_record = false; - // If the modifier should not be pressed, release all keys. - for (guint physical_key_idx = 0; physical_key_idx < length; - physical_key_idx++) { - const uint64_t physical_key = physical_keys[physical_key_idx]; - const uint64_t pressed_logical_key = - lookup_hash_table(self->pressing_records, physical_key); - - const bool this_key_is_event_key = physical_key - == context->event_physical_key; - const bool this_key_pressed_before_event = pressed_logical_key != 0; - const bool this_key_pressed_after_event = this_key_pressed_before_event - ^ this_key_is_event_key; - - if (this_key_pressed_after_event) { - pressed_by_record = true; - if (!pressed_by_state) { - g_return_if_fail(!this_key_is_event_key); - synthesize_simple_event(self, kFlutterKeyEventTypeUp, physical_key, - pressed_logical_key, context->timestamp); - update_pressing_state(self, physical_key, 0); - } + // Traverse each logical key of this modifier bit for 2 purposes: + // + // 1. Find if this logical key is pressed before the event, + // and synthesize a release event if needed. + // 2. Find if any logical key of this modifier is pressed + // before the event (#pressed_by_record), so that we can decide + // whether to synthesize a press event later. + for (guint logical_key_idx = 0; logical_key_idx < length; logical_key_idx++) { + const uint64_t logical_key = logical_keys[logical_key_idx]; + // const bool this_key_is_event_key = + // logical_key == context->event_logical_key; + + const uint64_t recorded_physical_key = + lookup_hash_table(self->mapping_records, logical_key); + const uint64_t pressed_logical_key_before_event = + recorded_physical_key == 0 + ? 0 + : lookup_hash_table(self->pressing_records, recorded_physical_key); + const bool this_key_pressed_before_event = + pressed_logical_key_before_event != 0; + + printf("pressedLogical %lx logical %lx recordedPh %lx\n", pressed_logical_key_before_event, + logical_key, recorded_physical_key); + fflush(stdout); + g_return_if_fail(pressed_logical_key_before_event == 0 || + pressed_logical_key_before_event == logical_key); + + // const bool this_key_pressed_after_event = + // this_key_pressed_before_event ^ this_key_is_event_key; + + pressed_by_record = pressed_by_record || this_key_pressed_before_event; + + if (this_key_pressed_before_event && !pressed_by_state) { + printf("syn by release\n"); + fflush(stdout); + synthesize_simple_event(self, kFlutterKeyEventTypeUp, + recorded_physical_key, logical_key, + context->timestamp); + update_pressing_state(self, recorded_physical_key, 0); } } // If the modifier should be pressed, press its primary key. if (pressed_by_state && !pressed_by_record) { const uint64_t logical_key = checked_key->primary_logical_key; - const uint64_t record_physical_key = lookup_hash_table(self->mapping_records, - logical_key); + const uint64_t record_physical_key = + lookup_hash_table(self->mapping_records, logical_key); // The physical key is derived from past mapping record if possible. // // The event to be synthesized is a key down event. There might not have // been a mapping record, in which case the hard-coded #primary_physical_key // is used. - const uint64_t physical_key = record_physical_key != 0 ? record_physical_key : - checked_key->primary_physical_key; + const uint64_t physical_key = record_physical_key != 0 + ? record_physical_key + : checked_key->primary_physical_key; if (record_physical_key == 0) { + printf("update by synpress ph %lx lo %lx\n", physical_key, logical_key); + fflush(stdout); update_mapping_record(self, physical_key, logical_key); } - g_return_if_fail(physical_key != context->event_physical_key); + g_return_if_fail(logical_key != context->event_logical_key); + printf("syn by press\n"); + fflush(stdout); synthesize_simple_event(self, kFlutterKeyEventTypeDown, physical_key, logical_key, context->timestamp); update_pressing_state(self, physical_key, logical_key); @@ -600,8 +623,8 @@ static void synchronize_lock_states_loop_body(gpointer key, FlKeyEmbedderResponder* self = context->self; const uint64_t logical_key = checked_key->primary_logical_key; - const uint64_t record_physical_key = lookup_hash_table(self->mapping_records, - logical_key); + const uint64_t record_physical_key = + lookup_hash_table(self->mapping_records, logical_key); // The physical key is derived from past mapping record if possible. // // If the event to be synthesized is a key up event, then there must have @@ -609,11 +632,9 @@ static void synchronize_lock_states_loop_body(gpointer key, // If the event to be synthesized is a key down event, then there might // not have been a mapping record, in which case the hard-coded // #primary_physical_key is used. - const uint64_t physical_key = record_physical_key != 0 ? record_physical_key : - checked_key->primary_physical_key; - if (record_physical_key == 0) { - update_mapping_record(self, physical_key, logical_key); - } + const uint64_t physical_key = record_physical_key != 0 + ? record_physical_key + : checked_key->primary_physical_key; // A lock mode key can be at any of a 4-stage cycle, depending on whether it's // pressed and enabled. The following table lists the definition of each @@ -640,12 +661,15 @@ static void synchronize_lock_states_loop_body(gpointer key, // cases. g_return_if_fail(pressed_logical_key == 0 || pressed_logical_key == logical_key); + printf("pressedLogical %lx lockRecords %d\n", pressed_logical_key, + self->lock_records); + fflush(stdout); const int stage_by_record = find_stage_by_record( pressed_logical_key != 0, (self->lock_records & modifier_bit) != 0); const bool enabled_by_state = (context->state & modifier_bit) != 0; - const bool is_self_event = physical_key == context->event_physical_key; - if (is_self_event && checked_key->is_caps_lock) { + const bool this_key_is_event_key = logical_key == context->event_logical_key; + if (this_key_is_event_key && checked_key->is_caps_lock) { update_caps_lock_state_logic_inferrence(self, context->is_down, enabled_by_state, stage_by_record); g_return_if_fail(self->caps_lock_state_logic_inferrence != @@ -655,7 +679,7 @@ static void synchronize_lock_states_loop_body(gpointer key, checked_key->is_caps_lock && self->caps_lock_state_logic_inferrence == kStateLogicReversed; const int stage_by_event = - is_self_event + this_key_is_event_key ? find_stage_by_self_event(stage_by_record, context->is_down, enabled_by_state, reverse_state_logic) : find_stage_by_others_event(stage_by_record, enabled_by_state); @@ -671,6 +695,9 @@ static void synchronize_lock_states_loop_body(gpointer key, if (stage_by_record == destination_stage) { return; } + printf("stageByRecord %d, stageDest %d\n", stage_by_record, + destination_stage); + fflush(stdout); for (int current_stage = stage_by_record; current_stage < destination_stage; current_stage += 1) { if (current_stage == 9) { @@ -680,10 +707,17 @@ static void synchronize_lock_states_loop_body(gpointer key, const int standard_current_stage = current_stage % kNumStages; const bool is_down_event = standard_current_stage == 0 || standard_current_stage == 2; + if (is_down_event && record_physical_key == 0) { + printf("update by lock ph %lx lo %lx\n", physical_key, logical_key); + fflush(stdout); + update_mapping_record(self, physical_key, logical_key); + } FlutterKeyEventType type = is_down_event ? kFlutterKeyEventTypeDown : kFlutterKeyEventTypeUp; update_pressing_state(self, physical_key, is_down_event ? logical_key : 0); possibly_update_lock_bit(self, logical_key, is_down_event); + printf("syn by lock\n"); + fflush(stdout); synthesize_simple_event(self, type, physical_key, logical_key, context->timestamp); } @@ -696,7 +730,6 @@ static void fl_key_embedder_responder_handle_event( FlKeyResponderAsyncCallback callback, gpointer user_data) { FlKeyEmbedderResponder* self = FL_KEY_EMBEDDER_RESPONDER(responder); - printf("ev scan %hx\n", event->hardware_keycode);fflush(stdout); g_return_if_fail(event != nullptr); g_return_if_fail(callback != nullptr); @@ -708,16 +741,12 @@ static void fl_key_embedder_responder_handle_event( const double timestamp = event_to_timestamp(event); const bool is_down_event = event->type == GDK_KEY_PRESS; - if (is_down_event) { - update_mapping_record(self, physical_key, logical_key); - } - SyncStateLoopContext sync_pressed_state_context; sync_pressed_state_context.self = self; sync_pressed_state_context.state = event->state; sync_pressed_state_context.timestamp = timestamp; sync_pressed_state_context.is_down = is_down_event; - sync_pressed_state_context.event_physical_key = physical_key; + sync_pressed_state_context.event_logical_key = logical_key; // Update lock mode states g_hash_table_foreach(self->lock_bit_to_checked_keys, @@ -761,14 +790,19 @@ static void fl_key_embedder_responder_handle_event( out_event.type = kFlutterKeyEventTypeUp; } } - update_pressing_state(self, physical_key, is_down_event ? logical_key : 0); - possibly_update_lock_bit(self, physical_key, is_down_event); // Update pressing states g_hash_table_foreach(self->modifier_bit_to_checked_keys, synchronize_pressed_states_loop_body, &sync_pressed_state_context); + update_pressing_state(self, physical_key, is_down_event ? logical_key : 0); + possibly_update_lock_bit(self, logical_key, is_down_event); + if (is_down_event) { + printf("update by event ph %lx lo %lx\n", physical_key, logical_key); + fflush(stdout); + update_mapping_record(self, physical_key, logical_key); + } FlKeyEmbedderUserData* response_data = fl_key_embedder_user_data_new(self, callback, user_data); diff --git a/shell/platform/linux/fl_key_embedder_responder_private.h b/shell/platform/linux/fl_key_embedder_responder_private.h index daa3611990775..635cbc672e4af 100644 --- a/shell/platform/linux/fl_key_embedder_responder_private.h +++ b/shell/platform/linux/fl_key_embedder_responder_private.h @@ -32,12 +32,12 @@ * available to pressing states, which is the right of the modifiers. */ typedef struct { - // The logical key for the primary key. - uint64_t primary_logical_key; // The physical key for the primary key. uint64_t primary_physical_key; - // The physical key for the secondary key. - uint64_t secondary_physical_key; + // The logical key for the primary key. + uint64_t primary_logical_key; + // The logical key for the secondary key. + uint64_t secondary_logical_key; // Whether this key is CapsLock. CapsLock uses a different event model in GDK // and needs special treatment. bool is_caps_lock; diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index c3e1ee99c5a51..a05306baad3c5 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -942,7 +942,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingState) { invoke_record_callback_and_verify(record, TRUE, &user_data); g_ptr_array_clear(g_call_records); - // A key up of control right is missed. + // A key up of control left is missed. state = 0; // Send a normal event (KeyA up) @@ -982,7 +982,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingState) { kIsModifier), verify_response_handled, &user_data); - EXPECT_EQ(g_call_records->len, 2u); + EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); EXPECT_EQ(record->event->timestamp, 101000); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); @@ -1004,7 +1004,8 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingState) { kIsNotModifier), verify_response_handled, &user_data); - // The synthesized event should have physical CapsLock and logical ControlLeft. + // The synthesized event should have physical CapsLock and logical + // ControlLeft. EXPECT_EQ(g_call_records->len, 2u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); EXPECT_EQ(record->event->timestamp, 102000); @@ -1132,7 +1133,8 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { // Test if missed lock keys can be detected and synthesized with state // information upon events that are not for this modifier key. -TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEventsRemapped) { +TEST(FlKeyEmbedderResponderTest, + SynthesizeForDesyncLockModeOnSelfEventsRemapped) { EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); g_autoptr(FlEngine) engine = make_mock_engine_with_records(); diff --git a/shell/platform/linux/key_mapping.cc b/shell/platform/linux/key_mapping.cc index c74dca0927dc2..4e4be1478206e 100644 --- a/shell/platform/linux/key_mapping.cc +++ b/shell/platform/linux/key_mapping.cc @@ -424,30 +424,30 @@ void initialize_modifier_bit_to_checked_keys(GHashTable* table) { data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_SHIFT_MASK), data); data->is_caps_lock = false; - data->primary_logical_key = 0x3000000010d; // shiftLeft - data->primary_physical_key = 0x0000700e1; // shiftLeft - data->secondary_physical_key = 0x0000700e5; // shiftRight + data->primary_physical_key = 0x0000700e1; // shiftLeft + data->primary_logical_key = 0x3000000010d; // shiftLeft + data->secondary_logical_key = 0x4000000010d; // shiftRight data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_CONTROL_MASK), data); data->is_caps_lock = false; - data->primary_logical_key = 0x30000000105; // controlLeft - data->primary_physical_key = 0x0000700e0; // controlLeft - data->secondary_physical_key = 0x0000700e4; // controlRight + data->primary_physical_key = 0x0000700e0; // controlLeft + data->primary_logical_key = 0x30000000105; // controlLeft + data->secondary_logical_key = 0x40000000105; // controlRight data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_MOD1_MASK), data); data->is_caps_lock = false; - data->primary_logical_key = 0x30000000102; // altLeft - data->primary_physical_key = 0x0000700e2; // altLeft - data->secondary_physical_key = 0x0000700e6; // altRight + data->primary_physical_key = 0x0000700e2; // altLeft + data->primary_logical_key = 0x30000000102; // altLeft + data->secondary_logical_key = 0x40000000102; // altRight data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_META_MASK), data); data->is_caps_lock = false; - data->primary_logical_key = 0x30000000109; // metaLeft - data->primary_physical_key = 0x0000700e3; // metaLeft - data->secondary_physical_key = 0x0000700e7; // metaRight + data->primary_physical_key = 0x0000700e3; // metaLeft + data->primary_logical_key = 0x30000000109; // metaLeft + data->secondary_logical_key = 0x40000000109; // metaRight } void initialize_lock_bit_to_checked_keys(GHashTable* table) { @@ -456,12 +456,12 @@ void initialize_lock_bit_to_checked_keys(GHashTable* table) { data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_LOCK_MASK), data); data->is_caps_lock = true; - data->primary_logical_key = 0x01000000104; // capsLock data->primary_physical_key = 0x000070039; // capsLock + data->primary_logical_key = 0x01000000104; // capsLock data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_MOD2_MASK), data); data->is_caps_lock = false; - data->primary_logical_key = 0x0100000010a; // numLock data->primary_physical_key = 0x000070053; // numLock + data->primary_logical_key = 0x0100000010a; // numLock } From 2f62618b5222b32a87fc089caae5efc2a30cdf10 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Fri, 7 May 2021 05:40:51 -0700 Subject: [PATCH 063/126] New test 1 passed --- shell/platform/linux/fl_key_embedder_responder_test.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index a05306baad3c5..c9a295fe93272 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -23,7 +23,7 @@ constexpr guint16 kKeyCodeShiftRight = 0x3Eu; constexpr guint16 kKeyCodeNumpad1 = 0x57u; constexpr guint16 kKeyCodeNumLock = 0x4Du; constexpr guint16 kKeyCodeCapsLock = 0x42u; -constexpr guint16 kKeyCodeControlLeft = 0x25u; +// constexpr guint16 kKeyCodeControlLeft = 0x25u; constexpr uint64_t kPhysicalKeyA = 0x00070004; constexpr uint64_t kPhysicalControlLeft = 0x000700e0; @@ -974,11 +974,11 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingState) { // Press physical CapsLock remapped to logical ControlLeft. - state = GDK_CONTROL_MASK; + state = 0; fl_key_responder_handle_event( responder, - key_event_new(101, kPress, GDK_KEY_Caps_Lock, kKeyCodeControlLeft, state, + key_event_new(101, kPress, GDK_KEY_Control_L, kKeyCodeCapsLock, state, kIsModifier), verify_response_handled, &user_data); From 942e6e6e7cc268a8ac99ee9c8c452472a53c57f9 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 10 May 2021 02:59:44 -0700 Subject: [PATCH 064/126] ATP --- .../linux/fl_key_embedder_responder.cc | 24 ++++++++++--------- .../linux/fl_key_embedder_responder_test.cc | 4 ++-- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index a29517f6dd020..742befb4dab46 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -504,17 +504,17 @@ static void synchronize_pressed_states_loop_body(gpointer key, // If the modifier should be pressed, press its primary key. if (pressed_by_state && !pressed_by_record) { const uint64_t logical_key = checked_key->primary_logical_key; - const uint64_t record_physical_key = + const uint64_t recorded_physical_key = lookup_hash_table(self->mapping_records, logical_key); // The physical key is derived from past mapping record if possible. // // The event to be synthesized is a key down event. There might not have // been a mapping record, in which case the hard-coded #primary_physical_key // is used. - const uint64_t physical_key = record_physical_key != 0 - ? record_physical_key + const uint64_t physical_key = recorded_physical_key != 0 + ? recorded_physical_key : checked_key->primary_physical_key; - if (record_physical_key == 0) { + if (recorded_physical_key == 0) { printf("update by synpress ph %lx lo %lx\n", physical_key, logical_key); fflush(stdout); update_mapping_record(self, physical_key, logical_key); @@ -623,7 +623,7 @@ static void synchronize_lock_states_loop_body(gpointer key, FlKeyEmbedderResponder* self = context->self; const uint64_t logical_key = checked_key->primary_logical_key; - const uint64_t record_physical_key = + const uint64_t recorded_physical_key = lookup_hash_table(self->mapping_records, logical_key); // The physical key is derived from past mapping record if possible. // @@ -632,8 +632,8 @@ static void synchronize_lock_states_loop_body(gpointer key, // If the event to be synthesized is a key down event, then there might // not have been a mapping record, in which case the hard-coded // #primary_physical_key is used. - const uint64_t physical_key = record_physical_key != 0 - ? record_physical_key + const uint64_t physical_key = recorded_physical_key != 0 + ? recorded_physical_key : checked_key->primary_physical_key; // A lock mode key can be at any of a 4-stage cycle, depending on whether it's @@ -656,13 +656,15 @@ static void synchronize_lock_states_loop_body(gpointer key, // minimal synthesization. const uint64_t pressed_logical_key = - lookup_hash_table(self->pressing_records, physical_key); + recorded_physical_key == 0 + ? 0 + : lookup_hash_table(self->pressing_records, recorded_physical_key); + // const uint64_t pressed_logical_key = + // lookup_hash_table(self->pressing_records, physical_key); // For simplicity, we're not considering remapped lock keys until we meet such // cases. g_return_if_fail(pressed_logical_key == 0 || pressed_logical_key == logical_key); - printf("pressedLogical %lx lockRecords %d\n", pressed_logical_key, - self->lock_records); fflush(stdout); const int stage_by_record = find_stage_by_record( pressed_logical_key != 0, (self->lock_records & modifier_bit) != 0); @@ -707,7 +709,7 @@ static void synchronize_lock_states_loop_body(gpointer key, const int standard_current_stage = current_stage % kNumStages; const bool is_down_event = standard_current_stage == 0 || standard_current_stage == 2; - if (is_down_event && record_physical_key == 0) { + if (is_down_event && recorded_physical_key == 0) { printf("update by lock ph %lx lo %lx\n", physical_key, logical_key); fflush(stdout); update_mapping_record(self, physical_key, logical_key); diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index c9a295fe93272..904d516fc0679 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -1000,7 +1000,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingState) { // Send a normal event (KeyA down). fl_key_responder_handle_event( responder, - key_event_new(102, kRelease, GDK_KEY_A, kKeyCodeKeyA, state, + key_event_new(102, kPress, GDK_KEY_A, kKeyCodeKeyA, state, kIsNotModifier), verify_response_handled, &user_data); @@ -1020,7 +1020,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingState) { EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); EXPECT_EQ(record->event->physical, kPhysicalKeyA); EXPECT_EQ(record->event->logical, kLogicalKeyA); - EXPECT_STREQ(record->event->character, nullptr); + EXPECT_STREQ(record->event->character, "A"); EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); From ceedf5a6dbde5bc6748227a29e49949fb231ebbd Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 10 May 2021 03:22:05 -0700 Subject: [PATCH 065/126] SynthesizationOccursOnSkippedEvents --- .../linux/fl_key_embedder_responder.cc | 15 +++---- .../linux/fl_key_embedder_responder_test.cc | 42 +++++++++++++++++++ 2 files changed, 48 insertions(+), 9 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index 742befb4dab46..c9dbaa8623fe6 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -659,10 +659,7 @@ static void synchronize_lock_states_loop_body(gpointer key, recorded_physical_key == 0 ? 0 : lookup_hash_table(self->pressing_records, recorded_physical_key); - // const uint64_t pressed_logical_key = - // lookup_hash_table(self->pressing_records, physical_key); - // For simplicity, we're not considering remapped lock keys until we meet such - // cases. + g_return_if_fail(pressed_logical_key == 0 || pressed_logical_key == logical_key); fflush(stdout); @@ -755,6 +752,11 @@ static void fl_key_embedder_responder_handle_event( synchronize_lock_states_loop_body, &sync_pressed_state_context); + // Update pressing states + g_hash_table_foreach(self->modifier_bit_to_checked_keys, + synchronize_pressed_states_loop_body, + &sync_pressed_state_context); + // Construct the real event const uint64_t last_logical_record = lookup_hash_table(self->pressing_records, physical_key); @@ -793,11 +795,6 @@ static void fl_key_embedder_responder_handle_event( } } - // Update pressing states - g_hash_table_foreach(self->modifier_bit_to_checked_keys, - synchronize_pressed_states_loop_body, - &sync_pressed_state_context); - update_pressing_state(self, physical_key, is_down_event ? logical_key : 0); possibly_update_lock_bit(self, logical_key, is_down_event); if (is_down_event) { diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index 904d516fc0679..e2d3c7b9c1823 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -1332,3 +1332,45 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) { clear_g_call_records(); } + +TEST(FlKeyEmbedderResponderTest, SynthesizationOccursOnSkippedEvents) { + EXPECT_EQ(g_call_records, nullptr); + g_call_records = g_ptr_array_new_with_free_func(g_object_unref); + g_autoptr(FlEngine) engine = make_mock_engine_with_records(); + g_autoptr(FlKeyResponder) responder = + FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); + int user_data = 123; // Arbitrary user data + + FlKeyEmbedderCallRecord* record; + + // The NumLock is desynchronized by being enabled, and Control is pressed. + guint state = GDK_MOD2_MASK | GDK_CONTROL_MASK; + + // Send a KeyA up event, which will be ignored + fl_key_responder_handle_event( + responder, + key_event_new(101, kRelease, GDK_KEY_a, kKeyCodeKeyA, state, + kIsNotModifier), + verify_response_handled, &user_data); + + EXPECT_EQ(g_call_records->len, 2u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->timestamp, 101000); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->physical, kPhysicalNumLock); + EXPECT_EQ(record->event->logical, kLogicalNumLock); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, true); + + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 1)); + EXPECT_EQ(record->event->timestamp, 101000); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->physical, kPhysicalControlLeft); + EXPECT_EQ(record->event->logical, kLogicalControlLeft); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, true); + + g_ptr_array_clear(g_call_records); + + clear_g_call_records(); +} From a63ad572a80aa240c62708afeca1110643685176 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 10 May 2021 03:23:21 -0700 Subject: [PATCH 066/126] Remove printf --- .../linux/fl_key_embedder_responder.cc | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index c9dbaa8623fe6..6ef5082421775 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -481,9 +481,6 @@ static void synchronize_pressed_states_loop_body(gpointer key, const bool this_key_pressed_before_event = pressed_logical_key_before_event != 0; - printf("pressedLogical %lx logical %lx recordedPh %lx\n", pressed_logical_key_before_event, - logical_key, recorded_physical_key); - fflush(stdout); g_return_if_fail(pressed_logical_key_before_event == 0 || pressed_logical_key_before_event == logical_key); @@ -493,8 +490,6 @@ static void synchronize_pressed_states_loop_body(gpointer key, pressed_by_record = pressed_by_record || this_key_pressed_before_event; if (this_key_pressed_before_event && !pressed_by_state) { - printf("syn by release\n"); - fflush(stdout); synthesize_simple_event(self, kFlutterKeyEventTypeUp, recorded_physical_key, logical_key, context->timestamp); @@ -515,13 +510,9 @@ static void synchronize_pressed_states_loop_body(gpointer key, ? recorded_physical_key : checked_key->primary_physical_key; if (recorded_physical_key == 0) { - printf("update by synpress ph %lx lo %lx\n", physical_key, logical_key); - fflush(stdout); update_mapping_record(self, physical_key, logical_key); } g_return_if_fail(logical_key != context->event_logical_key); - printf("syn by press\n"); - fflush(stdout); synthesize_simple_event(self, kFlutterKeyEventTypeDown, physical_key, logical_key, context->timestamp); update_pressing_state(self, physical_key, logical_key); @@ -694,9 +685,6 @@ static void synchronize_lock_states_loop_body(gpointer key, if (stage_by_record == destination_stage) { return; } - printf("stageByRecord %d, stageDest %d\n", stage_by_record, - destination_stage); - fflush(stdout); for (int current_stage = stage_by_record; current_stage < destination_stage; current_stage += 1) { if (current_stage == 9) { @@ -707,16 +695,12 @@ static void synchronize_lock_states_loop_body(gpointer key, const bool is_down_event = standard_current_stage == 0 || standard_current_stage == 2; if (is_down_event && recorded_physical_key == 0) { - printf("update by lock ph %lx lo %lx\n", physical_key, logical_key); - fflush(stdout); update_mapping_record(self, physical_key, logical_key); } FlutterKeyEventType type = is_down_event ? kFlutterKeyEventTypeDown : kFlutterKeyEventTypeUp; update_pressing_state(self, physical_key, is_down_event ? logical_key : 0); possibly_update_lock_bit(self, logical_key, is_down_event); - printf("syn by lock\n"); - fflush(stdout); synthesize_simple_event(self, type, physical_key, logical_key, context->timestamp); } @@ -798,8 +782,6 @@ static void fl_key_embedder_responder_handle_event( update_pressing_state(self, physical_key, is_down_event ? logical_key : 0); possibly_update_lock_bit(self, logical_key, is_down_event); if (is_down_event) { - printf("update by event ph %lx lo %lx\n", physical_key, logical_key); - fflush(stdout); update_mapping_record(self, physical_key, logical_key); } FlKeyEmbedderUserData* response_data = From 44de3b8b51d92a22481b9b29da3987d2c5dba0d0 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 10 May 2021 03:23:52 -0700 Subject: [PATCH 067/126] Remove commented --- shell/platform/linux/fl_key_embedder_responder.cc | 6 ------ 1 file changed, 6 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index 6ef5082421775..fd21d6bf3e766 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -469,9 +469,6 @@ static void synchronize_pressed_states_loop_body(gpointer key, // whether to synthesize a press event later. for (guint logical_key_idx = 0; logical_key_idx < length; logical_key_idx++) { const uint64_t logical_key = logical_keys[logical_key_idx]; - // const bool this_key_is_event_key = - // logical_key == context->event_logical_key; - const uint64_t recorded_physical_key = lookup_hash_table(self->mapping_records, logical_key); const uint64_t pressed_logical_key_before_event = @@ -484,9 +481,6 @@ static void synchronize_pressed_states_loop_body(gpointer key, g_return_if_fail(pressed_logical_key_before_event == 0 || pressed_logical_key_before_event == logical_key); - // const bool this_key_pressed_after_event = - // this_key_pressed_before_event ^ this_key_is_event_key; - pressed_by_record = pressed_by_record || this_key_pressed_before_event; if (this_key_pressed_before_event && !pressed_by_state) { From 86046d860abcaf4e4fed5ad911c45137d1aceb74 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 10 May 2021 05:04:55 -0700 Subject: [PATCH 068/126] More test --- .../linux/fl_key_embedder_responder.cc | 3 +- .../linux/fl_key_embedder_responder_test.cc | 221 +++++++++++++----- 2 files changed, 162 insertions(+), 62 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index fd21d6bf3e766..660f710bc1d3e 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -479,7 +479,7 @@ static void synchronize_pressed_states_loop_body(gpointer key, pressed_logical_key_before_event != 0; g_return_if_fail(pressed_logical_key_before_event == 0 || - pressed_logical_key_before_event == logical_key); + pressed_logical_key_before_event == logical_key); pressed_by_record = pressed_by_record || this_key_pressed_before_event; @@ -506,7 +506,6 @@ static void synchronize_pressed_states_loop_body(gpointer key, if (recorded_physical_key == 0) { update_mapping_record(self, physical_key, logical_key); } - g_return_if_fail(logical_key != context->event_logical_key); synthesize_simple_event(self, kFlutterKeyEventTypeDown, physical_key, logical_key, context->timestamp); update_pressing_state(self, physical_key, logical_key); diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index e2d3c7b9c1823..9622e153155c6 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -23,7 +23,8 @@ constexpr guint16 kKeyCodeShiftRight = 0x3Eu; constexpr guint16 kKeyCodeNumpad1 = 0x57u; constexpr guint16 kKeyCodeNumLock = 0x4Du; constexpr guint16 kKeyCodeCapsLock = 0x42u; -// constexpr guint16 kKeyCodeControlLeft = 0x25u; +constexpr guint16 kKeyCodeControlLeft = 0x25u; +constexpr guint16 kKeyCodeControlRight = 0x69u; constexpr uint64_t kPhysicalKeyA = 0x00070004; constexpr uint64_t kPhysicalControlLeft = 0x000700e0; @@ -901,8 +902,139 @@ TEST(FlKeyEmbedderResponderTest, IgnoreAbruptUpEvent) { } // Test if missed modifier keys can be detected and synthesized with state -// information. -TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingState) { +// information upon events that are for this modifier key. +TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) { + EXPECT_EQ(g_call_records, nullptr); + g_call_records = g_ptr_array_new_with_free_func(g_object_unref); + g_autoptr(FlEngine) engine = make_mock_engine_with_records(); + g_autoptr(FlKeyResponder) responder = + FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); + int user_data = 123; // Arbitrary user data + + FlKeyEmbedderCallRecord* record; + + // Test 1: synthesize key down. + + // A key down of control left is missed. + guint state = GDK_CONTROL_MASK; + + // Send a ControlLeft up + fl_key_responder_handle_event( + responder, + key_event_new(101, kRelease, GDK_KEY_Control_L, kKeyCodeControlLeft, + state, kIsModifier), + verify_response_handled, &user_data); + + EXPECT_EQ(g_call_records->len, 2u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->timestamp, 101000); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->physical, kPhysicalControlLeft); + EXPECT_EQ(record->event->logical, kLogicalControlLeft); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, true); + + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 1)); + EXPECT_EQ(record->event->timestamp, 101000); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); + EXPECT_EQ(record->event->physical, kPhysicalControlLeft); + EXPECT_EQ(record->event->logical, kLogicalControlLeft); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + // Test 2: synthesize key up. + + // Send a ControlLeft down. + state = 0; + fl_key_responder_handle_event( + responder, + key_event_new(102, kPress, GDK_KEY_Control_L, kKeyCodeControlLeft, state, + kIsModifier), + verify_response_handled, &user_data); + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + // A key up of control left is missed. + state = 0; + + // Send another ControlLeft down + fl_key_responder_handle_event( + responder, + key_event_new(103, kPress, GDK_KEY_Control_L, kKeyCodeControlLeft, state, + kIsModifier), + verify_response_handled, &user_data); + + EXPECT_EQ(g_call_records->len, 2u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->timestamp, 103000); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); + EXPECT_EQ(record->event->physical, kPhysicalControlLeft); + EXPECT_EQ(record->event->logical, kLogicalControlLeft); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, true); + + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 1)); + EXPECT_EQ(record->event->timestamp, 103000); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->physical, kPhysicalControlLeft); + EXPECT_EQ(record->event->logical, kLogicalControlLeft); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + // Send a ControlLeft up to clear up state. + state = GDK_CONTROL_MASK; + fl_key_responder_handle_event( + responder, + key_event_new(104, kRelease, GDK_KEY_Control_L, kKeyCodeControlLeft, + state, kIsModifier), + verify_response_handled, &user_data); + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + // Test 3: synthesize by right modifier. + + // A key down of control right is missed. + state = GDK_CONTROL_MASK; + + // Send a ControlRight up. + fl_key_responder_handle_event( + responder, + key_event_new(105, kRelease, GDK_KEY_Control_R, kKeyCodeControlRight, + state, kIsModifier), + verify_response_handled, &user_data); + + // A ControlLeft down is synthesized, with no non-synthesized event. + // Reason: The ControlLeft down is synthesized to synchronize the state + // showing Control as pressed. The ControlRight event is ignored because + // the event is considered a duplicate up event. + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->timestamp, 105000); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->physical, kPhysicalControlLeft); + EXPECT_EQ(record->event->logical, kLogicalControlLeft); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, true); + + g_ptr_array_clear(g_call_records); + + clear_g_call_records(); +} + +// Test if missed modifier keys can be detected and synthesized with state +// information upon events that are not for this modifier key. +TEST(FlKeyEmbedderResponderTest, + SynthesizeForDesyncPressingStateOnNonSelfEvents) { EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); g_autoptr(FlEngine) engine = make_mock_engine_with_records(); @@ -972,8 +1104,9 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingState) { invoke_record_callback_and_verify(record, TRUE, &user_data); g_ptr_array_clear(g_call_records); - // Press physical CapsLock remapped to logical ControlLeft. + // Test non-default key mapping. + // Press a key with physical CapsLock and logical ControlLeft. state = 0; fl_key_responder_handle_event( @@ -1029,9 +1162,10 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingState) { clear_g_call_records(); } -// Test if missed lock keys can be detected and synthesized with state -// information upon events that are not for this modifier key. -TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { +// Test if missed modifier keys can be detected and synthesized with state +// information upon events that do not have the standard key mapping. +TEST(FlKeyEmbedderResponderTest, + SynthesizeForDesyncPressingStateOnRemappedEvents) { EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); g_autoptr(FlEngine) engine = make_mock_engine_with_records(); @@ -1041,100 +1175,65 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { FlKeyEmbedderCallRecord* record; - // The NumLock is desynchronized by being enabled. - guint state = GDK_MOD2_MASK; + // Press a key with physical CapsLock and logical ControlLeft. + guint state = 0; - // Send a normal event fl_key_responder_handle_event( responder, - key_event_new(101, kPress, GDK_KEY_a, kKeyCodeKeyA, state, - kIsNotModifier), + key_event_new(101, kPress, GDK_KEY_Control_L, kKeyCodeCapsLock, state, + kIsModifier), verify_response_handled, &user_data); - EXPECT_EQ(g_call_records->len, 2u); + EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); EXPECT_EQ(record->event->timestamp, 101000); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); - EXPECT_EQ(record->event->physical, kPhysicalNumLock); - EXPECT_EQ(record->event->logical, kLogicalNumLock); + EXPECT_EQ(record->event->physical, kPhysicalCapsLock); + EXPECT_EQ(record->event->logical, kLogicalControlLeft); EXPECT_STREQ(record->event->character, nullptr); - EXPECT_EQ(record->event->synthesized, true); - - record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 1)); - EXPECT_EQ(record->event->timestamp, 101000); - EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); - EXPECT_EQ(record->event->physical, kPhysicalKeyA); - EXPECT_EQ(record->event->logical, kLogicalKeyA); - EXPECT_STREQ(record->event->character, "a"); EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); g_ptr_array_clear(g_call_records); - // The NumLock is desynchronized by being disabled. + // The key up of the control left press is missed. state = 0; - // Release key A + // Send a normal event (KeyA down). fl_key_responder_handle_event( responder, - key_event_new(102, kRelease, GDK_KEY_A, kKeyCodeKeyA, state, + key_event_new(102, kPress, GDK_KEY_A, kKeyCodeKeyA, state, kIsNotModifier), verify_response_handled, &user_data); - EXPECT_EQ(g_call_records->len, 4u); + // The synthesized event should have physical CapsLock and logical + // ControlLeft. + EXPECT_EQ(g_call_records->len, 2u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); EXPECT_EQ(record->event->timestamp, 102000); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); - EXPECT_EQ(record->event->physical, kPhysicalNumLock); - EXPECT_EQ(record->event->logical, kLogicalNumLock); + EXPECT_EQ(record->event->physical, kPhysicalCapsLock); + EXPECT_EQ(record->event->logical, kLogicalControlLeft); EXPECT_STREQ(record->event->character, nullptr); EXPECT_EQ(record->event->synthesized, true); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 1)); EXPECT_EQ(record->event->timestamp, 102000); EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); - EXPECT_EQ(record->event->physical, kPhysicalNumLock); - EXPECT_EQ(record->event->logical, kLogicalNumLock); - EXPECT_STREQ(record->event->character, nullptr); - EXPECT_EQ(record->event->synthesized, true); - - record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 2)); - EXPECT_EQ(record->event->timestamp, 102000); - EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); - EXPECT_EQ(record->event->physical, kPhysicalNumLock); - EXPECT_EQ(record->event->logical, kLogicalNumLock); - EXPECT_STREQ(record->event->character, nullptr); - EXPECT_EQ(record->event->synthesized, true); - - record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 3)); - EXPECT_EQ(record->event->timestamp, 102000); - EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); EXPECT_EQ(record->event->physical, kPhysicalKeyA); EXPECT_EQ(record->event->logical, kLogicalKeyA); - EXPECT_STREQ(record->event->character, nullptr); + EXPECT_STREQ(record->event->character, "A"); EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); g_ptr_array_clear(g_call_records); - // Release NumLock. Since the previous event should have synthesized NumLock - // to be released, this should result in no events. - g_expected_handled = true; - fl_key_responder_handle_event( - responder, - key_event_new(103, kRelease, GDK_KEY_Num_Lock, kKeyCodeNumLock, state, - kIsModifier), - verify_response_handled, &user_data); - - EXPECT_EQ(g_call_records->len, 0u); - clear_g_call_records(); } // Test if missed lock keys can be detected and synthesized with state // information upon events that are not for this modifier key. -TEST(FlKeyEmbedderResponderTest, - SynthesizeForDesyncLockModeOnSelfEventsRemapped) { +TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); g_autoptr(FlEngine) engine = make_mock_engine_with_records(); @@ -1333,7 +1432,9 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) { clear_g_call_records(); } -TEST(FlKeyEmbedderResponderTest, SynthesizationOccursOnSkippedEvents) { +// Ensures that even if the primary event is ignored (due to duplicate +// key up or down events), key synthesization is still performed. +TEST(FlKeyEmbedderResponderTest, SynthesizationOccursOnIgnoredEvents) { EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); g_autoptr(FlEngine) engine = make_mock_engine_with_records(); From ff590636802b70c501f6d487926baa54216e4021 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 11 May 2021 04:51:33 -0700 Subject: [PATCH 069/126] Revert windows key map --- shell/platform/windows/flutter_key_map.cc | 250 +++++++++++----------- 1 file changed, 124 insertions(+), 126 deletions(-) diff --git a/shell/platform/windows/flutter_key_map.cc b/shell/platform/windows/flutter_key_map.cc index c9b854ed1235e..69256a78f2606 100644 --- a/shell/platform/windows/flutter_key_map.cc +++ b/shell/platform/windows/flutter_key_map.cc @@ -182,6 +182,10 @@ std::map KeyboardKeyEmbedderHandler::windowsToPhysicalMap_ = std::map KeyboardKeyEmbedderHandler::windowsToLogicalMap_ = { + {0x00000008, 0x00000000008}, // BACK + {0x00000009, 0x00000000009}, // TAB + {0x0000000d, 0x0000000000d}, // RETURN + {0x0000001b, 0x0000000001b}, // ESCAPE {0x00000020, 0x00000000020}, // SPACE {0x000000de, 0x00000000022}, // OEM_7 {0x000000bc, 0x0000000002c}, // OEM_COMMA @@ -194,136 +198,130 @@ std::map KeyboardKeyEmbedderHandler::windowsToLogicalMap_ = {0x000000dc, 0x0000000005c}, // OEM_5 {0x000000dd, 0x0000000005d}, // OEM_6 {0x000000c0, 0x00000000060}, // OEM_3 - {0x00000008, 0x01000000008}, // BACK - {0x00000009, 0x01000000009}, // TAB - {0x0000000d, 0x0100000000d}, // RETURN - {0x0000001b, 0x0100000001b}, // ESCAPE - {0x0000002e, 0x0100000007f}, // DELETE - {0x00000014, 0x01000000104}, // CAPITAL - {0x00000090, 0x0100000010a}, // NUMLOCK - {0x00000091, 0x0100000010c}, // SCROLL - {0x00000028, 0x01000000301}, // DOWN - {0x00000025, 0x01000000302}, // LEFT - {0x00000027, 0x01000000303}, // RIGHT - {0x00000026, 0x01000000304}, // UP - {0x00000023, 0x01000000305}, // END - {0x00000024, 0x01000000306}, // HOME - {0x00000022, 0x01000000307}, // NEXT - {0x00000021, 0x01000000308}, // PRIOR - {0x0000000c, 0x01000000401}, // CLEAR - {0x0000002d, 0x01000000407}, // INSERT - {0x0000001e, 0x01000000501}, // ACCEPT - {0x000000f6, 0x01000000503}, // ATTN - {0x00000003, 0x01000000504}, // CANCEL - {0x0000005d, 0x01000000505}, // APPS - {0x0000002b, 0x01000000506}, // EXECUTE - {0x0000002f, 0x01000000508}, // HELP - {0x00000013, 0x01000000509}, // PAUSE - {0x000000fa, 0x0100000050a}, // PLAY - {0x00000029, 0x0100000050c}, // SELECT - {0x0000001c, 0x01000000705}, // CONVERT - {0x00000018, 0x01000000706}, // FINAL - {0x0000001f, 0x0100000070b}, // MODECHANGE - {0x00000019, 0x01000000712}, // HANJA - {0x00000017, 0x01000000713}, // JUNJA - {0x00000019, 0x01000000719}, // KANJI - {0x00000070, 0x01000000801}, // F1 - {0x00000071, 0x01000000802}, // F2 - {0x00000072, 0x01000000803}, // F3 - {0x00000073, 0x01000000804}, // F4 - {0x00000074, 0x01000000805}, // F5 - {0x00000075, 0x01000000806}, // F6 - {0x00000076, 0x01000000807}, // F7 - {0x00000077, 0x01000000808}, // F8 - {0x00000078, 0x01000000809}, // F9 - {0x00000079, 0x0100000080a}, // F10 - {0x0000007a, 0x0100000080b}, // F11 - {0x0000007b, 0x0100000080c}, // F12 - {0x0000007c, 0x0100000080d}, // F13 - {0x0000007d, 0x0100000080e}, // F14 - {0x0000007e, 0x0100000080f}, // F15 - {0x0000007f, 0x01000000810}, // F16 - {0x00000080, 0x01000000811}, // F17 - {0x00000081, 0x01000000812}, // F18 - {0x00000082, 0x01000000813}, // F19 - {0x00000083, 0x01000000814}, // F20 - {0x00000084, 0x01000000815}, // F21 - {0x00000085, 0x01000000816}, // F22 - {0x00000086, 0x01000000817}, // F23 - {0x00000087, 0x01000000818}, // F24 - {0x000000b3, 0x01000000a05}, // MEDIA_PLAY_PAUSE - {0x000000b2, 0x01000000a07}, // MEDIA_STOP - {0x0000002a, 0x01000000a0c}, // PRINT - {0x000000ae, 0x01000000a0f}, // VOLUME_DOWN - {0x000000af, 0x01000000a10}, // VOLUME_UP - {0x000000ad, 0x01000000a11}, // VOLUME_MUTE - {0x000000b4, 0x01000000b03}, // LAUNCH_MAIL - {0x000000a6, 0x01000000c01}, // BROWSER_BACK - {0x000000ab, 0x01000000c02}, // BROWSER_FAVORITES - {0x000000a7, 0x01000000c03}, // BROWSER_FORWARD - {0x000000ac, 0x01000000c04}, // BROWSER_HOME - {0x000000a8, 0x01000000c05}, // BROWSER_REFRESH - {0x000000aa, 0x01000000c06}, // BROWSER_SEARCH - {0x000000a9, 0x01000000c07}, // BROWSER_STOP - {0x000000c3, 0x0100005ff08}, // GAMEPAD_A - {0x000000c4, 0x0100005ff09}, // GAMEPAD_B - {0x000000c5, 0x0100005ff0a}, // GAMEPAD_X - {0x000000c6, 0x0100005ff0b}, // GAMEPAD_Y - {0x000000c7, 0x0100005ff0c}, // GAMEPAD_RIGHT_SHOULDER - {0x000000c8, 0x0100005ff0d}, // GAMEPAD_LEFT_SHOULDER - {0x000000c9, 0x0100005ff0e}, // GAMEPAD_LEFT_TRIGGER - {0x000000ca, 0x0100005ff0f}, // GAMEPAD_RIGHT_TRIGGER - {0x000000cb, 0x0100005ff10}, // GAMEPAD_DPAD_UP - {0x0000005f, 0x01100010082}, // SLEEP - {0x00000015, 0x01100070090}, // KANA, HANGEUL, HANGUL - {0x000000a4, 0x30000000102}, // LMENU - {0x00000011, 0x30000000105}, // CONTROL - {0x000000a2, 0x30000000105}, // LCONTROL - {0x0000005b, 0x30000000109}, // LWIN - {0x00000010, 0x3000000010d}, // SHIFT - {0x000000a0, 0x3000000010d}, // LSHIFT - {0x000000a5, 0x40000000102}, // RMENU - {0x000000a3, 0x40000000105}, // RCONTROL - {0x0000005c, 0x40000000109}, // RWIN - {0x000000a1, 0x4000000010d}, // RSHIFT - {0x0000006a, 0x5000000002a}, // MULTIPLY - {0x0000006b, 0x5000000002b}, // ADD - {0x0000006d, 0x5000000002d}, // SUBTRACT - {0x0000006e, 0x5000000002e}, // DECIMAL - {0x0000006f, 0x5000000002f}, // DIVIDE - {0x00000060, 0x50000000030}, // NUMPAD0 - {0x00000061, 0x50000000031}, // NUMPAD1 - {0x00000062, 0x50000000032}, // NUMPAD2 - {0x00000063, 0x50000000033}, // NUMPAD3 - {0x00000064, 0x50000000034}, // NUMPAD4 - {0x00000065, 0x50000000035}, // NUMPAD5 - {0x00000066, 0x50000000036}, // NUMPAD6 - {0x00000067, 0x50000000037}, // NUMPAD7 - {0x00000068, 0x50000000038}, // NUMPAD8 - {0x00000069, 0x50000000039}, // NUMPAD9 - {0x00000092, 0x5000000003d}, // OEM_NEC_EQUAL + {0x0000002e, 0x0000000007f}, // DELETE + {0x00000014, 0x00000000104}, // CAPITAL + {0x00000090, 0x0000000010a}, // NUMLOCK + {0x00000091, 0x0000000010c}, // SCROLL + {0x00000028, 0x00000000301}, // DOWN + {0x00000025, 0x00000000302}, // LEFT + {0x00000027, 0x00000000303}, // RIGHT + {0x00000026, 0x00000000304}, // UP + {0x00000023, 0x00000000305}, // END + {0x00000024, 0x00000000306}, // HOME + {0x00000022, 0x00000000307}, // NEXT + {0x00000021, 0x00000000308}, // PRIOR + {0x0000000c, 0x00000000401}, // CLEAR + {0x0000002d, 0x00000000407}, // INSERT + {0x0000001e, 0x00000000501}, // ACCEPT + {0x000000f6, 0x00000000503}, // ATTN + {0x00000003, 0x00000000504}, // CANCEL + {0x0000005d, 0x00000000505}, // APPS + {0x0000002b, 0x00000000506}, // EXECUTE + {0x0000002f, 0x00000000508}, // HELP + {0x00000013, 0x00000000509}, // PAUSE + {0x000000fa, 0x0000000050a}, // PLAY + {0x00000029, 0x0000000050c}, // SELECT + {0x0000001c, 0x00000000705}, // CONVERT + {0x0000001f, 0x0000000070b}, // MODECHANGE + {0x00000070, 0x00000000801}, // F1 + {0x00000071, 0x00000000802}, // F2 + {0x00000072, 0x00000000803}, // F3 + {0x00000073, 0x00000000804}, // F4 + {0x00000074, 0x00000000805}, // F5 + {0x00000075, 0x00000000806}, // F6 + {0x00000076, 0x00000000807}, // F7 + {0x00000077, 0x00000000808}, // F8 + {0x00000078, 0x00000000809}, // F9 + {0x00000079, 0x0000000080a}, // F10 + {0x0000007a, 0x0000000080b}, // F11 + {0x0000007b, 0x0000000080c}, // F12 + {0x0000007c, 0x0000000080d}, // F13 + {0x0000007d, 0x0000000080e}, // F14 + {0x0000007e, 0x0000000080f}, // F15 + {0x0000007f, 0x00000000810}, // F16 + {0x00000080, 0x00000000811}, // F17 + {0x00000081, 0x00000000812}, // F18 + {0x00000082, 0x00000000813}, // F19 + {0x00000083, 0x00000000814}, // F20 + {0x00000084, 0x00000000815}, // F21 + {0x00000085, 0x00000000816}, // F22 + {0x00000086, 0x00000000817}, // F23 + {0x00000087, 0x00000000818}, // F24 + {0x000000b3, 0x00000000a05}, // MEDIA_PLAY_PAUSE + {0x000000b2, 0x00000000a07}, // MEDIA_STOP + {0x0000002a, 0x00000000a0c}, // PRINT + {0x000000ae, 0x00000000a0f}, // VOLUME_DOWN + {0x000000af, 0x00000000a10}, // VOLUME_UP + {0x000000ad, 0x00000000a11}, // VOLUME_MUTE + {0x000000b4, 0x00000000b03}, // LAUNCH_MAIL + {0x000000a6, 0x00000000c01}, // BROWSER_BACK + {0x000000ab, 0x00000000c02}, // BROWSER_FAVORITES + {0x000000a7, 0x00000000c03}, // BROWSER_FORWARD + {0x000000ac, 0x00000000c04}, // BROWSER_HOME + {0x000000a8, 0x00000000c05}, // BROWSER_REFRESH + {0x000000aa, 0x00000000c06}, // BROWSER_SEARCH + {0x000000a9, 0x00000000c07}, // BROWSER_STOP + {0x000000c3, 0x0000005ff08}, // GAMEPAD_A + {0x000000c4, 0x0000005ff09}, // GAMEPAD_B + {0x000000c5, 0x0000005ff0a}, // GAMEPAD_X + {0x000000c6, 0x0000005ff0b}, // GAMEPAD_Y + {0x000000c7, 0x0000005ff0c}, // GAMEPAD_RIGHT_SHOULDER + {0x000000c8, 0x0000005ff0d}, // GAMEPAD_LEFT_SHOULDER + {0x000000c9, 0x0000005ff0e}, // GAMEPAD_LEFT_TRIGGER + {0x000000ca, 0x0000005ff0f}, // GAMEPAD_RIGHT_TRIGGER + {0x000000cb, 0x0000005ff10}, // GAMEPAD_DPAD_UP + {0x0000005f, 0x00100010082}, // SLEEP + {0x00000015, 0x00100070090}, // KANA + {0x00000015, 0x00100070090}, // HANGEUL + {0x00000015, 0x00100070090}, // HANGUL + {0x0000006a, 0x0020000002a}, // MULTIPLY + {0x0000006b, 0x0020000002b}, // ADD + {0x0000006d, 0x0020000002d}, // SUBTRACT + {0x0000006e, 0x0020000002e}, // DECIMAL + {0x0000006f, 0x0020000002f}, // DIVIDE + {0x00000060, 0x00200000030}, // NUMPAD0 + {0x00000061, 0x00200000031}, // NUMPAD1 + {0x00000062, 0x00200000032}, // NUMPAD2 + {0x00000063, 0x00200000033}, // NUMPAD3 + {0x00000064, 0x00200000034}, // NUMPAD4 + {0x00000065, 0x00200000035}, // NUMPAD5 + {0x00000066, 0x00200000036}, // NUMPAD6 + {0x00000067, 0x00200000037}, // NUMPAD7 + {0x00000068, 0x00200000038}, // NUMPAD8 + {0x00000069, 0x00200000039}, // NUMPAD9 + {0x00000092, 0x0020000003d}, // OEM_NEC_EQUAL + {0x000000a4, 0x00300000102}, // LMENU + {0x00000011, 0x00300000105}, // CONTROL + {0x000000a2, 0x00300000105}, // LCONTROL + {0x0000005b, 0x00300000109}, // LWIN + {0x00000010, 0x0030000010d}, // SHIFT + {0x000000a0, 0x0030000010d}, // LSHIFT + {0x000000a5, 0x00400000102}, // RMENU + {0x000000a3, 0x00400000105}, // RCONTROL + {0x0000005c, 0x00400000109}, // RWIN + {0x000000a1, 0x0040000010d}, // RSHIFT }; std::map KeyboardKeyEmbedderHandler::scanCodeToLogicalMap_ = { - {0x0000e01d, 0x40000000105}, // ControlRight - {0x0000e038, 0x40000000102}, // AltRight - {0x0000004f, 0x50000000031}, // Numpad1 - {0x00000050, 0x50000000032}, // Numpad2 - {0x00000051, 0x50000000033}, // Numpad3 - {0x0000004b, 0x50000000034}, // Numpad4 - {0x0000004c, 0x50000000035}, // Numpad5 - {0x0000004d, 0x50000000036}, // Numpad6 - {0x00000047, 0x50000000037}, // Numpad7 - {0x00000048, 0x50000000038}, // Numpad8 - {0x00000049, 0x50000000039}, // Numpad9 - {0x00000052, 0x50000000030}, // Numpad0 - {0x0000004e, 0x5000000002b}, // NumpadAdd - {0x00000053, 0x5000000002e}, // NumpadDecimal - {0x0000e035, 0x5000000002f}, // NumpadDivide - {0x00000059, 0x5000000003d}, // NumpadEqual - {0x00000037, 0x5000000002a}, // NumpadMultiply - {0x0000004a, 0x5000000002d}, // NumpadSubtract + {0x0000e01d, 0x0400000105}, // ControlRight + {0x0000e038, 0x0400000102}, // AltRight + {0x0000004f, 0x0200000031}, // Numpad1 + {0x00000050, 0x0200000032}, // Numpad2 + {0x00000051, 0x0200000033}, // Numpad3 + {0x0000004b, 0x0200000034}, // Numpad4 + {0x0000004c, 0x0200000035}, // Numpad5 + {0x0000004d, 0x0200000036}, // Numpad6 + {0x00000047, 0x0200000037}, // Numpad7 + {0x00000048, 0x0200000038}, // Numpad8 + {0x00000049, 0x0200000039}, // Numpad9 + {0x00000052, 0x0200000030}, // Numpad0 + {0x0000004e, 0x020000002b}, // NumpadAdd + {0x00000053, 0x020000002e}, // NumpadDecimal + {0x0000e035, 0x020000002f}, // NumpadDivide + {0x00000059, 0x020000003d}, // NumpadEqual + {0x00000037, 0x020000002a}, // NumpadMultiply + {0x0000004a, 0x020000002d}, // NumpadSubtract }; } // namespace flutter From 1bf7b2974f0c5e4767dc25384a2610ae016d3dcd Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 11 May 2021 05:19:00 -0700 Subject: [PATCH 070/126] g_ptr_array_find_with_equal_func1 --- shell/platform/linux/fl_keyboard_manager.cc | 27 +++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/shell/platform/linux/fl_keyboard_manager.cc b/shell/platform/linux/fl_keyboard_manager.cc index aff6804911210..d9c2fe5cd5575 100644 --- a/shell/platform/linux/fl_keyboard_manager.cc +++ b/shell/platform/linux/fl_keyboard_manager.cc @@ -226,6 +226,29 @@ static void fl_keyboard_manager_dispose(GObject* object) { /* Implement FlKeyboardManager */ +// This is an exact copy of g_ptr_array_find_with_equal_func. Somehow CI +// reports that can not find symbol g_ptr_array_find_with_equal_func, despite +// the fact that it runs well locally. +gboolean g_ptr_array_find_with_equal_func1(GPtrArray *haystack, + gconstpointer needle, + GEqualFunc equal_func, + guint *index_) { + guint i; + g_return_val_if_fail (haystack != NULL, FALSE); + if (equal_func == NULL) + equal_func = g_direct_equal; + for (i = 0; i < haystack->len; i++) { + if (equal_func(g_ptr_array_index(haystack, i), needle)) { + if (index_ != NULL) { + *index_ = i; + } + return TRUE; + } + } + + return FALSE; +} + // Compare a #FlKeyboardPendingEvent with the given sequence_id. The needle // should be a pointer to uint64_t sequence_id. static gboolean compare_pending_by_sequence_id( @@ -251,7 +274,7 @@ static gboolean compare_pending_by_hash(gconstpointer pending, static bool fl_keyboard_manager_remove_redispatched(FlKeyboardManager* self, uint64_t hash) { guint result_index; - gboolean found = g_ptr_array_find_with_equal_func( + gboolean found = g_ptr_array_find_with_equal_func1( self->pending_redispatches, static_cast(&hash), compare_pending_by_hash, &result_index); if (found) { @@ -274,7 +297,7 @@ static void responder_handle_event_callback(bool handled, FlKeyboardManager* self = user_data->manager; guint result_index = -1; - gboolean found = g_ptr_array_find_with_equal_func( + gboolean found = g_ptr_array_find_with_equal_func1( self->pending_responds, &user_data->sequence_id, compare_pending_by_sequence_id, &result_index); g_return_if_fail(found); From 858c980db317b27ab9c3cdf3782288ee5860dd30 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 11 May 2021 13:56:06 -0700 Subject: [PATCH 071/126] Fix format --- shell/platform/linux/fl_keyboard_manager.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/shell/platform/linux/fl_keyboard_manager.cc b/shell/platform/linux/fl_keyboard_manager.cc index d9c2fe5cd5575..c61acfa923a49 100644 --- a/shell/platform/linux/fl_keyboard_manager.cc +++ b/shell/platform/linux/fl_keyboard_manager.cc @@ -230,11 +230,11 @@ static void fl_keyboard_manager_dispose(GObject* object) { // reports that can not find symbol g_ptr_array_find_with_equal_func, despite // the fact that it runs well locally. gboolean g_ptr_array_find_with_equal_func1(GPtrArray *haystack, - gconstpointer needle, - GEqualFunc equal_func, - guint *index_) { + gconstpointer needle, + GEqualFunc equal_func, + guint *index_) { guint i; - g_return_val_if_fail (haystack != NULL, FALSE); + g_return_val_if_fail(haystack != NULL, FALSE); if (equal_func == NULL) equal_func = g_direct_equal; for (i = 0; i < haystack->len; i++) { From 64a589a5f095ff74f3db206c1e4601caf8697bfd Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 11 May 2021 14:26:24 -0700 Subject: [PATCH 072/126] format --- shell/platform/linux/fl_keyboard_manager.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shell/platform/linux/fl_keyboard_manager.cc b/shell/platform/linux/fl_keyboard_manager.cc index c61acfa923a49..d627188ca270c 100644 --- a/shell/platform/linux/fl_keyboard_manager.cc +++ b/shell/platform/linux/fl_keyboard_manager.cc @@ -229,10 +229,10 @@ static void fl_keyboard_manager_dispose(GObject* object) { // This is an exact copy of g_ptr_array_find_with_equal_func. Somehow CI // reports that can not find symbol g_ptr_array_find_with_equal_func, despite // the fact that it runs well locally. -gboolean g_ptr_array_find_with_equal_func1(GPtrArray *haystack, +gboolean g_ptr_array_find_with_equal_func1(GPtrArray* haystack, gconstpointer needle, GEqualFunc equal_func, - guint *index_) { + guint* index_) { guint i; g_return_val_if_fail(haystack != NULL, FALSE); if (equal_func == NULL) From 12c891293e4a371bceee687a0485801be144c723 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 11 May 2021 16:46:34 -0700 Subject: [PATCH 073/126] FlKeyEvent --- shell/platform/linux/fl_key_event.cc | 28 +++++++++++ shell/platform/linux/fl_key_event.h | 57 ++++++++++++++++++++++ shell/platform/linux/fl_keyboard_manager.h | 2 +- 3 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 shell/platform/linux/fl_key_event.cc create mode 100644 shell/platform/linux/fl_key_event.h diff --git a/shell/platform/linux/fl_key_event.cc b/shell/platform/linux/fl_key_event.cc new file mode 100644 index 0000000000000..5537ba374394f --- /dev/null +++ b/shell/platform/linux/fl_key_event.cc @@ -0,0 +1,28 @@ +// 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_key_event.h" + +FlKeyEvent* fl_key_event_new_from_gdk_event(GdkEventKey* event) { + GdkEventType type = gdk_event_get_event_type(event); + g_return_val_if_fail(type == GDK_KEY_PRESS || type == GDK_KEY_RELEASE, nullptr); + bool valid = true; + FlKeyEvent* result = g_new(FlKeyEvent, 1); + + result->time = gdk_event_get_time(event); + result->is_press = type == GDK_KEY_PRESS; + valid = valid && gdk_event_get_keycode(event, &result->keycode); + valid = valid && gdk_event_get_keyval(event, &result->keyval); + valid = valid && gdk_event_get_state(event, &result->state); + result->origin = event; + + g_return_val_if_fail(valid, nullptr); + return result; +} + +FlKeyEvent* fl_key_event_copy(FlKeyEvent* source) { + FlKeyEvent* result = g_new(FlKeyEvent, 1); + *result = *source; + return result; +} diff --git a/shell/platform/linux/fl_key_event.h b/shell/platform/linux/fl_key_event.h new file mode 100644 index 0000000000000..45f6d31a6da69 --- /dev/null +++ b/shell/platform/linux/fl_key_event.h @@ -0,0 +1,57 @@ +// 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_KEY_EVENT_H_ +#define FLUTTER_SHELL_PLATFORM_LINUX_FL_KEY_EVENT_H_ + +#include + +/** + * FlKeyEvent: + * A struct that stores information from GdkEvent. + * + * GDK will stop supporting creating GdkEvent since 4.0. This struct + * is used so that Flutter can create an event object in unittests. + */ +typedef struct _FlKeyEvent { + // Time in milliseconds. + guint32 time; + // True if is a press event, otherwise a release event. + bool is_press; + // Hardware keycode. + guint16 keycode; + // Keyval. + guint keyval; + // Modifier state. + GdkModifierType state; + // The original event. + // + // For native events, this is #GdkEvent pointer. + // For unit tests, this is a dummy pointer. + gpointer origin; +} FlKeyEvent; + +/** + * fl_key_event_new_from_gdk_event: + * @event: the #GdkEvent this #FlKeyEvent is based on. Must be a #GdkEventKey. + * + * Create a new #FlKeyEvent based on a #GdkEventKey. + * + * Returns: a new #FlKeyEvent. Must be freed with #free (or #g_free). + */ +FlKeyEvent* fl_key_event_new_from_gdk_event(GdkEvent* event); + +/** + * fl_key_event_copy: + * @source: the source to copy from. + * + * Allocates a new event with all properties shallow copied from source. + * + * Returns: a cloned #FlKeyEvent. Must be freed with #free (or #g_free). + */ +FlKeyEvent* fl_key_event_copy(FlKeyEvent* source); + +G_END_DECLS + +#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_KEY_EVENT_H_ diff --git a/shell/platform/linux/fl_keyboard_manager.h b/shell/platform/linux/fl_keyboard_manager.h index db9524fabe5ac..98777c83e895f 100644 --- a/shell/platform/linux/fl_keyboard_manager.h +++ b/shell/platform/linux/fl_keyboard_manager.h @@ -21,7 +21,7 @@ typedef void (*FlKeyboardManagerRedispatcher)(const GdkEvent* event); G_BEGIN_DECLS -#define FL_TYPE_KEYBOARD_MANAGER fl_keyboard_manager_get_type +#define FL_TYPE_KEYBOARD_MANAGER fl_keyboard_manager_get_type() G_DECLARE_FINAL_TYPE(FlKeyboardManager, fl_keyboard_manager, FL, From 86738887817c5c8f657e7e0b0f7ea0fd19bf3b02 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Thu, 13 May 2021 02:01:41 -0700 Subject: [PATCH 074/126] Migrate (untested) --- .../linux/fl_key_channel_responder.cc | 19 +-- .../linux/fl_key_channel_responder_test.cc | 116 +++++++-------- .../linux/fl_key_embedder_responder.cc | 16 +-- .../linux/fl_key_embedder_responder_test.cc | 132 +++++++++--------- shell/platform/linux/fl_key_event.cc | 19 ++- shell/platform/linux/fl_key_event.h | 20 ++- shell/platform/linux/fl_key_responder.cc | 2 +- shell/platform/linux/fl_key_responder.h | 8 +- shell/platform/linux/fl_keyboard_manager.cc | 39 +++--- shell/platform/linux/fl_keyboard_manager.h | 12 +- .../linux/fl_keyboard_manager_test.cc | 81 +++++------ shell/platform/linux/fl_text_input_plugin.cc | 8 +- shell/platform/linux/fl_text_input_plugin.h | 7 +- shell/platform/linux/fl_view.cc | 18 ++- 14 files changed, 250 insertions(+), 247 deletions(-) diff --git a/shell/platform/linux/fl_key_channel_responder.cc b/shell/platform/linux/fl_key_channel_responder.cc index d226d8ff45d0a..3a6643b1ce768 100644 --- a/shell/platform/linux/fl_key_channel_responder.cc +++ b/shell/platform/linux/fl_key_channel_responder.cc @@ -114,7 +114,7 @@ G_DEFINE_TYPE_WITH_CODE( static void fl_key_channel_responder_handle_event( FlKeyResponder* responder, - GdkEventKey* event, + FlKeyEvent* event, FlKeyResponderAsyncCallback callback, gpointer user_data); @@ -200,26 +200,15 @@ FlKeyChannelResponder* fl_key_channel_responder_new( // Sends a key event to the framework. static void fl_key_channel_responder_handle_event( FlKeyResponder* responder, - GdkEventKey* event, + FlKeyEvent* event, FlKeyResponderAsyncCallback callback, gpointer user_data) { FlKeyChannelResponder* self = FL_KEY_CHANNEL_RESPONDER(responder); g_return_if_fail(event != nullptr); g_return_if_fail(callback != nullptr); - const gchar* type; - switch (event->type) { - case GDK_KEY_PRESS: - type = kTypeValueDown; - break; - case GDK_KEY_RELEASE: - type = kTypeValueUp; - break; - default: - return; - } - - int64_t scan_code = event->hardware_keycode; + const gchar* type = event->is_press ? kTypeValueDown : kTypeValueUp; + int64_t scan_code = event->keycode; int64_t unicode_scarlar_values = gdk_keyval_to_unicode(event->keyval); // For most modifier keys, GTK keeps track of the "pressed" state of the diff --git a/shell/platform/linux/fl_key_channel_responder_test.cc b/shell/platform/linux/fl_key_channel_responder_test.cc index d99e27bdc7a6e..6492d84fb6ddc 100644 --- a/shell/platform/linux/fl_key_channel_responder_test.cc +++ b/shell/platform/linux/fl_key_channel_responder_test.cc @@ -29,6 +29,52 @@ static void responder_callback(bool handled, gpointer user_data) { g_main_loop_quit(static_cast(user_data)); } +namespace { +// A dummy object, whose pointer will be used as _g_key_event->origin. +static int _origin_event; +// A global variable to store new event. It is a global variable so that it can +// be returned by key_event_new for easy use. +static FlKeyEvent _g_key_event; +} // namespace + +// Clone #string onto the heap. +// +// If #string is nullptr, returns nullptr. Otherwise, the returned pointer must +// be freed with g_free. The #out_length must not be nullptr, and is used to +// store the length of the string. +static char* clone_string(const char* string, size_t* out_length) { + if (string == nullptr) { + *out_length = 0; + return nullptr; + } + size_t len = strlen(string); + char* result = g_new(char, len + 1); + strcpy(result, string); + *out_length = len; + return result; +} + +static FlKeyEvent* fl_key_event_new_by_mock(guint32 time_in_milliseconds, + bool is_press, + guint keyval, + guint16 keycode, + guint state, + const char* string, + gboolean is_modifier) { + if (_g_key_event.string != nullptr) { + g_free(_g_key_event.string); + } + _g_key_event.is_press = is_press; + _g_key_event.time = time_in_milliseconds; + _g_key_event.state = state; + _g_key_event.keyval = keyval; + _g_key_event.string = clone_string(string, &_g_key_event.length); + _g_key_event.keycode = keycode; + _g_key_event.origin = &_origin_event; + _g_key_event.dispose_origin = nullptr; + return &_g_key_event; +} + // Test sending a letter "A"; TEST(FlKeyChannelResponderTest, SendKeyEvent) { g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); @@ -42,22 +88,7 @@ TEST(FlKeyChannelResponderTest, SendKeyEvent) { g_autoptr(FlKeyResponder) responder = FL_KEY_RESPONDER(fl_key_channel_responder_new(messenger, &mock)); - char string[] = "A"; - GdkEventKey key_event = GdkEventKey{ - GDK_KEY_PRESS, // event type - nullptr, // window (not needed) - FALSE, // event was sent explicitly - 12345, // time - 0x0, // modifier state - GDK_KEY_A, // key code - 1, // length of string representation - reinterpret_cast(&string[0]), // string representation - 0x04, // scan code - 0, // keyboard group - 0, // is a modifier - }; - - fl_key_responder_handle_event(responder, &key_event, responder_callback, + fl_key_responder_handle_event(responder, fl_key_event_new_by_mock(true, 0x04, GDK_KEY_A, 0x0, "A", false), responder_callback, loop); expected_value = "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, keyCode: 65, " @@ -67,21 +98,7 @@ TEST(FlKeyChannelResponderTest, SendKeyEvent) { // Blocks here until echo_response_cb is called. g_main_loop_run(loop); - key_event = GdkEventKey{ - GDK_KEY_RELEASE, // event type - nullptr, // window (not needed) - FALSE, // event was sent explicitly - 23456, // time - 0x0, // modifier state - GDK_KEY_A, // key code - 1, // length of string representation - reinterpret_cast(&string[0]), // string representation - 0x04, // scan code - 0, // keyboard group - 0, // is a modifier - }; - - fl_key_responder_handle_event(responder, &key_event, responder_callback, + fl_key_responder_handle_event(responder, fl_key_event_new_by_mock(false, 0x04, GDK_KEY_A, 0x0, "A", false), responder_callback, loop); expected_value = "{type: keyup, keymap: linux, scanCode: 4, toolkit: gtk, keyCode: 65, " @@ -106,21 +123,7 @@ void test_lock_event(guint key_code, g_autoptr(FlKeyResponder) responder = FL_KEY_RESPONDER(fl_key_channel_responder_new(messenger, &mock)); - GdkEventKey key_event = GdkEventKey{ - GDK_KEY_PRESS, // event type - nullptr, // window (not needed) - FALSE, // event was sent explicitly - 12345, // time - 0x10, // modifier state - key_code, // key code - 1, // length of string representation - nullptr, // string representation - 0x04, // scan code - 0, // keyboard group - 0, // is a modifier - }; - - fl_key_responder_handle_event(responder, &key_event, responder_callback, + fl_key_responder_handle_event(responder, fl_key_event_new_by_mock(true, 0x04, key_code, 0x0, nullptr, false), responder_callback, loop); expected_value = down_expected; expected_handled = FALSE; @@ -128,12 +131,9 @@ void test_lock_event(guint key_code, // Blocks here until echo_response_cb is called. g_main_loop_run(loop); - key_event.type = GDK_KEY_RELEASE; - key_event.time++; - expected_value = up_expected; expected_handled = FALSE; - fl_key_responder_handle_event(responder, &key_event, responder_callback, + fl_key_responder_handle_event(responder, fl_key_event_new_by_mock(false, 0x04, key_code, 0x0, nullptr, false), responder_callback, loop); // Blocks here until echo_response_cb is called. @@ -179,21 +179,7 @@ TEST(FlKeyChannelResponderTest, TestKeyEventHandledByFramework) { g_autoptr(FlKeyResponder) responder = FL_KEY_RESPONDER(fl_key_channel_responder_new(messenger, &mock)); - GdkEventKey key_event = GdkEventKey{ - GDK_KEY_PRESS, // event type - nullptr, // window (not needed) - FALSE, // event was sent explicitly - 12345, // time - 0x10, // modifier state - GDK_KEY_A, // key code - 1, // length of string representation - nullptr, // string representation - 0x04, // scan code - 0, // keyboard group - 0, // is a modifier - }; - - fl_key_responder_handle_event(responder, &key_event, responder_callback, + fl_key_responder_handle_event(responder, fl_key_event_new_by_mock(true, 0x04, GDK_KEY_A, 0x0, nullptr, false), responder_callback, loop); expected_handled = TRUE; expected_value = diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index 660f710bc1d3e..6a6438ef9e1a3 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -28,13 +28,13 @@ static uint64_t lookup_hash_table(GHashTable* table, uint64_t key) { g_hash_table_lookup(table, uint64_to_gpointer(key))); } -static uint64_t event_to_physical_key(const GdkEventKey* event, +static uint64_t event_to_physical_key(const FlKeyEvent* event, GHashTable* table) { - uint64_t record = lookup_hash_table(table, event->hardware_keycode); + uint64_t record = lookup_hash_table(table, event->keycode); if (record != 0) { return record; } - return kGtkKeyIdPlane | event->hardware_keycode; + return kGtkKeyIdPlane | event->keycode; } static uint64_t to_lower(uint64_t n) { @@ -219,7 +219,7 @@ G_DEFINE_TYPE_WITH_CODE( static void fl_key_embedder_responder_handle_event( FlKeyResponder* responder, - GdkEventKey* event, + FlKeyEvent* event, FlKeyResponderAsyncCallback callback, gpointer user_data); @@ -308,7 +308,7 @@ FlKeyEmbedderResponder* fl_key_embedder_responder_new(FlEngine* engine) { /* Implement FlKeyEmbedderUserData */ -static uint64_t event_to_logical_key(const GdkEventKey* event, +static uint64_t event_to_logical_key(const FlKeyEvent* event, GHashTable* table) { guint keyval = event->keyval; uint64_t record = lookup_hash_table(table, keyval); @@ -323,13 +323,13 @@ static uint64_t event_to_logical_key(const GdkEventKey* event, return kGtkKeyIdPlane | keyval; } -static uint64_t event_to_timestamp(const GdkEventKey* event) { +static uint64_t event_to_timestamp(const FlKeyEvent* event) { return kMicrosecondsPerMillisecond * (double)event->time; } // Returns a newly accocated UTF-8 string from event->keyval that must be // freed later with g_free(). -static char* event_to_character(const GdkEventKey* event) { +static char* event_to_character(const FlKeyEvent* event) { gunichar unicodeChar = gdk_keyval_to_unicode(event->keyval); glong items_written; gchar* result = g_ucs4_to_utf8(&unicodeChar, 1, NULL, &items_written, NULL); @@ -702,7 +702,7 @@ static void synchronize_lock_states_loop_body(gpointer key, // Sends a key event to the framework. static void fl_key_embedder_responder_handle_event( FlKeyResponder* responder, - GdkEventKey* event, + FlKeyEvent* event, FlKeyResponderAsyncCallback callback, gpointer user_data) { FlKeyEmbedderResponder* self = FL_KEY_EMBEDDER_RESPONDER(responder); diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index 9622e153155c6..bac83d969faf1 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -109,28 +109,28 @@ static FlKeyEmbedderCallRecord* fl_key_embedder_call_record_new( } namespace { +// A dummy object, whose pointer will be used as _g_key_event->origin. +static int _origin_event; // A global variable to store new event. It is a global variable so that it can // be returned by key_event_new for easy use. -GdkEventKey _g_key_event; +FlKeyEvent _g_key_event; } // namespace -static GdkEventKey* key_event_new(guint32 time_in_milliseconds, - gboolean is_down, - guint keyval, - guint16 hardware_keycode, - guint state, - gboolean is_modifier) { - _g_key_event.type = is_down ? GDK_KEY_PRESS : GDK_KEY_RELEASE; - _g_key_event.window = nullptr; - _g_key_event.send_event = FALSE; +static FlKeyEvent* fl_key_event_new_by_mock(guint32 time_in_milliseconds, + bool is_press, + guint keyval, + guint16 keycode, + guint state, + gboolean is_modifier) { + _g_key_event.type = is_press; _g_key_event.time = time_in_milliseconds; _g_key_event.state = state; _g_key_event.keyval = keyval; _g_key_event.length = 0; _g_key_event.string = nullptr; - _g_key_event.hardware_keycode = hardware_keycode; - _g_key_event.group = 0; - _g_key_event.is_modifier = is_modifier ? 1 : 0; + _g_key_event.keycode = keycode; + _g_key_event.origin = &_origin_event; + _g_key_event.dispose_origin = nullptr; return &_g_key_event; } @@ -189,7 +189,7 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { // Key down fl_key_responder_handle_event( responder, - key_event_new(12345, kPress, GDK_KEY_a, kKeyCodeKeyA, 0, kIsNotModifier), + fl_key_event_new_by_mock(12345, kPress, GDK_KEY_a, kKeyCodeKeyA, 0, kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -209,7 +209,7 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { // Key up fl_key_responder_handle_event(responder, - key_event_new(12346, kRelease, GDK_KEY_a, + fl_key_event_new_by_mock(12346, kRelease, GDK_KEY_a, kKeyCodeKeyA, 0, kIsNotModifier), verify_response_handled, &user_data); @@ -230,7 +230,7 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { // Key down fl_key_responder_handle_event( responder, - key_event_new(12347, kPress, GDK_KEY_q, kKeyCodeKeyA, 0, kIsNotModifier), + fl_key_event_new_by_mock(12347, kPress, GDK_KEY_q, kKeyCodeKeyA, 0, kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -248,7 +248,7 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { // Key up fl_key_responder_handle_event(responder, - key_event_new(12348, kRelease, GDK_KEY_q, + fl_key_event_new_by_mock(12348, kRelease, GDK_KEY_q, kKeyCodeKeyA, 0, kIsNotModifier), verify_response_handled, &user_data); @@ -282,7 +282,7 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { // Press shift right fl_key_responder_handle_event( responder, - key_event_new(101, kPress, GDK_KEY_Shift_R, kKeyCodeShiftRight, 0, + fl_key_event_new_by_mock(101, kPress, GDK_KEY_Shift_R, kKeyCodeShiftRight, 0, kIsModifier), verify_response_handled, &user_data); @@ -300,7 +300,7 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { // Press key A fl_key_responder_handle_event( responder, - key_event_new(102, kPress, GDK_KEY_A, kKeyCodeKeyA, 0x1, kIsNotModifier), + fl_key_event_new_by_mock(102, kPress, GDK_KEY_A, kKeyCodeKeyA, 0x1, kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -317,7 +317,7 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { // Release shift right fl_key_responder_handle_event( responder, - key_event_new(103, kRelease, GDK_KEY_Shift_R, kKeyCodeShiftRight, 0x1, + fl_key_event_new_by_mock(103, kRelease, GDK_KEY_Shift_R, kKeyCodeShiftRight, 0x1, kIsModifier), verify_response_handled, &user_data); @@ -335,7 +335,7 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { // Release key A fl_key_responder_handle_event( responder, - key_event_new(104, kRelease, GDK_KEY_A, kKeyCodeKeyA, 0, kIsNotModifier), + fl_key_event_new_by_mock(104, kRelease, GDK_KEY_A, kKeyCodeKeyA, 0, kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -373,7 +373,7 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { // Press Numpad 1 (stage 0) fl_key_responder_handle_event( responder, - key_event_new(101, kPress, GDK_KEY_KP_End, kKeyCodeNumpad1, 0, + fl_key_event_new_by_mock(101, kPress, GDK_KEY_KP_End, kKeyCodeNumpad1, 0, kIsNotModifier), verify_response_handled, &user_data); @@ -391,7 +391,7 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { // Press NumLock (stage 0 -> 1) fl_key_responder_handle_event( responder, - key_event_new(102, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock, 0, + fl_key_event_new_by_mock(102, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock, 0, kIsNotModifier), verify_response_handled, &user_data); @@ -409,7 +409,7 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { // Release numpad 1 (stage 1) fl_key_responder_handle_event( responder, - key_event_new(104, kRelease, GDK_KEY_KP_1, kKeyCodeNumpad1, 0x10, + fl_key_event_new_by_mock(104, kRelease, GDK_KEY_KP_1, kKeyCodeNumpad1, 0x10, kIsNotModifier), verify_response_handled, &user_data); @@ -427,7 +427,7 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { // Release NumLock (stage 1 -> 2) fl_key_responder_handle_event( responder, - key_event_new(103, kRelease, GDK_KEY_Num_Lock, kKeyCodeNumLock, 0x10, + fl_key_event_new_by_mock(103, kRelease, GDK_KEY_Num_Lock, kKeyCodeNumLock, 0x10, kIsModifier), verify_response_handled, &user_data); @@ -445,7 +445,7 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { // Press Numpad 1 (stage 2) fl_key_responder_handle_event( responder, - key_event_new(101, kPress, GDK_KEY_KP_End, kKeyCodeNumpad1, 0x10, + fl_key_event_new_by_mock(101, kPress, GDK_KEY_KP_End, kKeyCodeNumpad1, 0x10, kIsNotModifier), verify_response_handled, &user_data); @@ -463,7 +463,7 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { // Press NumLock (stage 2 -> 3) fl_key_responder_handle_event( responder, - key_event_new(102, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock, 0x10, + fl_key_event_new_by_mock(102, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock, 0x10, kIsNotModifier), verify_response_handled, &user_data); @@ -481,7 +481,7 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { // Release numpad 1 (stage 3) fl_key_responder_handle_event( responder, - key_event_new(104, kRelease, GDK_KEY_KP_1, kKeyCodeNumpad1, 0x10, + fl_key_event_new_by_mock(104, kRelease, GDK_KEY_KP_1, kKeyCodeNumpad1, 0x10, kIsNotModifier), verify_response_handled, &user_data); @@ -499,7 +499,7 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { // Release NumLock (stage 3 -> 0) fl_key_responder_handle_event( responder, - key_event_new(103, kRelease, GDK_KEY_Num_Lock, kKeyCodeNumLock, 0x10, + fl_key_event_new_by_mock(103, kRelease, GDK_KEY_Num_Lock, kKeyCodeNumLock, 0x10, kIsModifier), verify_response_handled, &user_data); @@ -534,7 +534,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { // Press CapsLock (stage 0 -> 1) fl_key_responder_handle_event( responder, - key_event_new(101, kPress, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x0, + fl_key_event_new_by_mock(101, kPress, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x0, kIsModifier), verify_response_handled, &user_data); @@ -552,7 +552,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { // Press key A (stage 1) fl_key_responder_handle_event( responder, - key_event_new(102, kPress, GDK_KEY_A, kKeyCodeKeyA, 0x2, kIsNotModifier), + fl_key_event_new_by_mock(102, kPress, GDK_KEY_A, kKeyCodeKeyA, 0x2, kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -569,7 +569,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { // Release CapsLock (stage 1 -> 2) fl_key_responder_handle_event( responder, - key_event_new(103, kRelease, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x2, + fl_key_event_new_by_mock(103, kRelease, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x2, kIsModifier), verify_response_handled, &user_data); @@ -587,7 +587,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { // Release key A (stage 2) fl_key_responder_handle_event( responder, - key_event_new(104, kRelease, GDK_KEY_A, kKeyCodeKeyA, 0x2, + fl_key_event_new_by_mock(104, kRelease, GDK_KEY_A, kKeyCodeKeyA, 0x2, kIsNotModifier), verify_response_handled, &user_data); @@ -605,7 +605,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { // Press CapsLock (stage 2 -> 3) fl_key_responder_handle_event( responder, - key_event_new(105, kPress, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x2, + fl_key_event_new_by_mock(105, kPress, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x2, kIsModifier), verify_response_handled, &user_data); @@ -623,7 +623,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { // Press key A (stage 3) fl_key_responder_handle_event( responder, - key_event_new(106, kPress, GDK_KEY_A, kKeyCodeKeyA, 0x2, kIsNotModifier), + fl_key_event_new_by_mock(106, kPress, GDK_KEY_A, kKeyCodeKeyA, 0x2, kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -640,7 +640,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { // Release CapsLock (stage 3 -> 0) fl_key_responder_handle_event( responder, - key_event_new(107, kRelease, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x2, + fl_key_event_new_by_mock(107, kRelease, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x2, kIsModifier), verify_response_handled, &user_data); @@ -658,7 +658,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { // Release key A (stage 0) fl_key_responder_handle_event( responder, - key_event_new(108, kRelease, GDK_KEY_a, kKeyCodeKeyA, 0x0, + fl_key_event_new_by_mock(108, kRelease, GDK_KEY_a, kKeyCodeKeyA, 0x0, kIsNotModifier), verify_response_handled, &user_data); @@ -693,7 +693,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { // Press key A (stage 0) fl_key_responder_handle_event( responder, - key_event_new(101, kPress, GDK_KEY_a, kKeyCodeKeyA, 0x0, kIsNotModifier), + fl_key_event_new_by_mock(101, kPress, GDK_KEY_a, kKeyCodeKeyA, 0x0, kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -710,7 +710,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { // Press CapsLock (stage 0 -> 1) fl_key_responder_handle_event( responder, - key_event_new(102, kPress, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x2, + fl_key_event_new_by_mock(102, kPress, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x2, kIsModifier), verify_response_handled, &user_data); @@ -728,7 +728,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { // Release CapsLock (stage 1 -> 2) fl_key_responder_handle_event( responder, - key_event_new(103, kRelease, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x2, + fl_key_event_new_by_mock(103, kRelease, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x2, kIsModifier), verify_response_handled, &user_data); @@ -746,7 +746,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { // Release key A (stage 2) fl_key_responder_handle_event( responder, - key_event_new(104, kRelease, GDK_KEY_A, kKeyCodeKeyA, 0x2, + fl_key_event_new_by_mock(104, kRelease, GDK_KEY_A, kKeyCodeKeyA, 0x2, kIsNotModifier), verify_response_handled, &user_data); @@ -764,7 +764,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { // Press key A (stage 2) fl_key_responder_handle_event( responder, - key_event_new(105, kPress, GDK_KEY_A, kKeyCodeKeyA, 0x2, kIsNotModifier), + fl_key_event_new_by_mock(105, kPress, GDK_KEY_A, kKeyCodeKeyA, 0x2, kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -781,7 +781,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { // Press CapsLock (stage 2 -> 3) fl_key_responder_handle_event( responder, - key_event_new(106, kPress, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x0, + fl_key_event_new_by_mock(106, kPress, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x0, kIsModifier), verify_response_handled, &user_data); @@ -799,7 +799,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { // Release CapsLock (stage 3 -> 0) fl_key_responder_handle_event( responder, - key_event_new(107, kRelease, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x2, + fl_key_event_new_by_mock(107, kRelease, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x2, kIsModifier), verify_response_handled, &user_data); @@ -817,7 +817,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { // Release key A (stage 0) fl_key_responder_handle_event( responder, - key_event_new(108, kRelease, GDK_KEY_a, kKeyCodeKeyA, 0x0, + fl_key_event_new_by_mock(108, kRelease, GDK_KEY_a, kKeyCodeKeyA, 0x0, kIsNotModifier), verify_response_handled, &user_data); @@ -848,7 +848,7 @@ TEST(FlKeyEmbedderResponderTest, IgnoreDuplicateDownEvent) { // Press KeyA fl_key_responder_handle_event( responder, - key_event_new(101, kPress, GDK_KEY_a, kKeyCodeKeyA, 0, kIsNotModifier), + fl_key_event_new_by_mock(101, kPress, GDK_KEY_a, kKeyCodeKeyA, 0, kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -862,7 +862,7 @@ TEST(FlKeyEmbedderResponderTest, IgnoreDuplicateDownEvent) { g_expected_handled = true; fl_key_responder_handle_event( responder, - key_event_new(102, kPress, GDK_KEY_q, kKeyCodeKeyA, 0, kIsNotModifier), + fl_key_event_new_by_mock(102, kPress, GDK_KEY_q, kKeyCodeKeyA, 0, kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 0u); @@ -870,7 +870,7 @@ TEST(FlKeyEmbedderResponderTest, IgnoreDuplicateDownEvent) { // Release KeyA fl_key_responder_handle_event( responder, - key_event_new(103, kRelease, GDK_KEY_q, kKeyCodeKeyA, 0, kIsNotModifier), + fl_key_event_new_by_mock(103, kRelease, GDK_KEY_q, kKeyCodeKeyA, 0, kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -893,7 +893,7 @@ TEST(FlKeyEmbedderResponderTest, IgnoreAbruptUpEvent) { g_expected_handled = true; fl_key_responder_handle_event( responder, - key_event_new(103, kRelease, GDK_KEY_q, kKeyCodeKeyA, 0, kIsNotModifier), + fl_key_event_new_by_mock(103, kRelease, GDK_KEY_q, kKeyCodeKeyA, 0, kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 0u); @@ -921,7 +921,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) { // Send a ControlLeft up fl_key_responder_handle_event( responder, - key_event_new(101, kRelease, GDK_KEY_Control_L, kKeyCodeControlLeft, + fl_key_event_new_by_mock(101, kRelease, GDK_KEY_Control_L, kKeyCodeControlLeft, state, kIsModifier), verify_response_handled, &user_data); @@ -951,7 +951,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) { state = 0; fl_key_responder_handle_event( responder, - key_event_new(102, kPress, GDK_KEY_Control_L, kKeyCodeControlLeft, state, + fl_key_event_new_by_mock(102, kPress, GDK_KEY_Control_L, kKeyCodeControlLeft, state, kIsModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -965,7 +965,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) { // Send another ControlLeft down fl_key_responder_handle_event( responder, - key_event_new(103, kPress, GDK_KEY_Control_L, kKeyCodeControlLeft, state, + fl_key_event_new_by_mock(103, kPress, GDK_KEY_Control_L, kKeyCodeControlLeft, state, kIsModifier), verify_response_handled, &user_data); @@ -993,7 +993,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) { state = GDK_CONTROL_MASK; fl_key_responder_handle_event( responder, - key_event_new(104, kRelease, GDK_KEY_Control_L, kKeyCodeControlLeft, + fl_key_event_new_by_mock(104, kRelease, GDK_KEY_Control_L, kKeyCodeControlLeft, state, kIsModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -1009,7 +1009,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) { // Send a ControlRight up. fl_key_responder_handle_event( responder, - key_event_new(105, kRelease, GDK_KEY_Control_R, kKeyCodeControlRight, + fl_key_event_new_by_mock(105, kRelease, GDK_KEY_Control_R, kKeyCodeControlRight, state, kIsModifier), verify_response_handled, &user_data); @@ -1050,7 +1050,7 @@ TEST(FlKeyEmbedderResponderTest, // Send a normal event (KeyA down) fl_key_responder_handle_event( responder, - key_event_new(101, kPress, GDK_KEY_a, kKeyCodeKeyA, state, + fl_key_event_new_by_mock(101, kPress, GDK_KEY_a, kKeyCodeKeyA, state, kIsNotModifier), verify_response_handled, &user_data); @@ -1080,7 +1080,7 @@ TEST(FlKeyEmbedderResponderTest, // Send a normal event (KeyA up) fl_key_responder_handle_event( responder, - key_event_new(102, kRelease, GDK_KEY_A, kKeyCodeKeyA, state, + fl_key_event_new_by_mock(102, kRelease, GDK_KEY_A, kKeyCodeKeyA, state, kIsNotModifier), verify_response_handled, &user_data); @@ -1111,7 +1111,7 @@ TEST(FlKeyEmbedderResponderTest, fl_key_responder_handle_event( responder, - key_event_new(101, kPress, GDK_KEY_Control_L, kKeyCodeCapsLock, state, + fl_key_event_new_by_mock(101, kPress, GDK_KEY_Control_L, kKeyCodeCapsLock, state, kIsModifier), verify_response_handled, &user_data); @@ -1133,7 +1133,7 @@ TEST(FlKeyEmbedderResponderTest, // Send a normal event (KeyA down). fl_key_responder_handle_event( responder, - key_event_new(102, kPress, GDK_KEY_A, kKeyCodeKeyA, state, + fl_key_event_new_by_mock(102, kPress, GDK_KEY_A, kKeyCodeKeyA, state, kIsNotModifier), verify_response_handled, &user_data); @@ -1180,7 +1180,7 @@ TEST(FlKeyEmbedderResponderTest, fl_key_responder_handle_event( responder, - key_event_new(101, kPress, GDK_KEY_Control_L, kKeyCodeCapsLock, state, + fl_key_event_new_by_mock(101, kPress, GDK_KEY_Control_L, kKeyCodeCapsLock, state, kIsModifier), verify_response_handled, &user_data); @@ -1202,7 +1202,7 @@ TEST(FlKeyEmbedderResponderTest, // Send a normal event (KeyA down). fl_key_responder_handle_event( responder, - key_event_new(102, kPress, GDK_KEY_A, kKeyCodeKeyA, state, + fl_key_event_new_by_mock(102, kPress, GDK_KEY_A, kKeyCodeKeyA, state, kIsNotModifier), verify_response_handled, &user_data); @@ -1249,7 +1249,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { // Send a normal event fl_key_responder_handle_event( responder, - key_event_new(101, kPress, GDK_KEY_a, kKeyCodeKeyA, state, + fl_key_event_new_by_mock(101, kPress, GDK_KEY_a, kKeyCodeKeyA, state, kIsNotModifier), verify_response_handled, &user_data); @@ -1279,7 +1279,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { // Release key A fl_key_responder_handle_event( responder, - key_event_new(102, kRelease, GDK_KEY_A, kKeyCodeKeyA, state, + fl_key_event_new_by_mock(102, kRelease, GDK_KEY_A, kKeyCodeKeyA, state, kIsNotModifier), verify_response_handled, &user_data); @@ -1324,7 +1324,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { g_expected_handled = true; fl_key_responder_handle_event( responder, - key_event_new(103, kRelease, GDK_KEY_Num_Lock, kKeyCodeNumLock, state, + fl_key_event_new_by_mock(103, kRelease, GDK_KEY_Num_Lock, kKeyCodeNumLock, state, kIsModifier), verify_response_handled, &user_data); @@ -1351,7 +1351,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) { // NumLock down fl_key_responder_handle_event( responder, - key_event_new(101, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock, state, + fl_key_event_new_by_mock(101, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock, state, kIsModifier), verify_response_handled, &user_data); @@ -1389,7 +1389,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) { // NumLock up fl_key_responder_handle_event( responder, - key_event_new(102, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock, state, + fl_key_event_new_by_mock(102, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock, state, kIsModifier), verify_response_handled, &user_data); @@ -1450,7 +1450,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizationOccursOnIgnoredEvents) { // Send a KeyA up event, which will be ignored fl_key_responder_handle_event( responder, - key_event_new(101, kRelease, GDK_KEY_a, kKeyCodeKeyA, state, + fl_key_event_new_by_mock(101, kRelease, GDK_KEY_a, kKeyCodeKeyA, state, kIsNotModifier), verify_response_handled, &user_data); diff --git a/shell/platform/linux/fl_key_event.cc b/shell/platform/linux/fl_key_event.cc index 5537ba374394f..e603e87c6833c 100644 --- a/shell/platform/linux/fl_key_event.cc +++ b/shell/platform/linux/fl_key_event.cc @@ -4,7 +4,12 @@ #include "flutter/shell/platform/linux/fl_key_event.h" +static void dispose_gdk_event(gpointer target) { + dispose_gdk_event(reinterpret_cast(target)); +} + FlKeyEvent* fl_key_event_new_from_gdk_event(GdkEventKey* event) { + g_return_val_if_fail(event != nullptr, nullptr); GdkEventType type = gdk_event_get_event_type(event); g_return_val_if_fail(type == GDK_KEY_PRESS || type == GDK_KEY_RELEASE, nullptr); bool valid = true; @@ -16,13 +21,19 @@ FlKeyEvent* fl_key_event_new_from_gdk_event(GdkEventKey* event) { valid = valid && gdk_event_get_keyval(event, &result->keyval); valid = valid && gdk_event_get_state(event, &result->state); result->origin = event; + result->dispose_origin = dispose_gdk_event; g_return_val_if_fail(valid, nullptr); return result; } -FlKeyEvent* fl_key_event_copy(FlKeyEvent* source) { - FlKeyEvent* result = g_new(FlKeyEvent, 1); - *result = *source; - return result; +void fl_key_event_dispose(FlKeyEvent* event) { + if (event->dispose_origin != nullptr) { + event->dispose_origin(event->origin); + } + g_free(event); +} + +void fl_key_event_destroy_notify(gpointer event) { + fl_key_event_dispose(reinterpret_cast(event)); } diff --git a/shell/platform/linux/fl_key_event.h b/shell/platform/linux/fl_key_event.h index 45f6d31a6da69..b1ebd7c250281 100644 --- a/shell/platform/linux/fl_key_event.h +++ b/shell/platform/linux/fl_key_event.h @@ -7,6 +7,8 @@ #include +typedef void FlKeyEventDisposeOrigin(gpointer); + /** * FlKeyEvent: * A struct that stores information from GdkEvent. @@ -25,16 +27,26 @@ typedef struct _FlKeyEvent { guint keyval; // Modifier state. GdkModifierType state; - // The original event. + // String, null-terminated. + // + // Can be nullptr. + const char* string; + // Length of #string (without the terminating \0). + size_t length; + // An opaque pointer to the original event. // + // This is used when dispatching. // For native events, this is #GdkEvent pointer. // For unit tests, this is a dummy pointer. gpointer origin; + // A callback to free #origin, called when #FlKeyEvent is disposed. + FlKeyEventDisposeOrigin dispose_origin; } FlKeyEvent; /** * fl_key_event_new_from_gdk_event: - * @event: the #GdkEvent this #FlKeyEvent is based on. Must be a #GdkEventKey. + * @event: the #GdkEvent this #FlKeyEvent is based on. The #event be a #GdkEventKey, + * and will be destroyed by #fl_key_event_dispose. * * Create a new #FlKeyEvent based on a #GdkEventKey. * @@ -50,8 +62,8 @@ FlKeyEvent* fl_key_event_new_from_gdk_event(GdkEvent* event); * * Returns: a cloned #FlKeyEvent. Must be freed with #free (or #g_free). */ -FlKeyEvent* fl_key_event_copy(FlKeyEvent* source); +void fl_key_event_dispose(FlKeyEvent* event); -G_END_DECLS +void fl_key_event_destroy_notify(gpointer event); #endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_KEY_EVENT_H_ diff --git a/shell/platform/linux/fl_key_responder.cc b/shell/platform/linux/fl_key_responder.cc index 5628786fc8ecc..c5ac80d290d87 100644 --- a/shell/platform/linux/fl_key_responder.cc +++ b/shell/platform/linux/fl_key_responder.cc @@ -9,7 +9,7 @@ G_DEFINE_INTERFACE(FlKeyResponder, fl_key_responder, G_TYPE_OBJECT) static void fl_key_responder_default_init(FlKeyResponderInterface* iface) {} void fl_key_responder_handle_event(FlKeyResponder* self, - GdkEventKey* event, + FlKeyEvent* event, FlKeyResponderAsyncCallback callback, gpointer user_data) { g_return_if_fail(FL_IS_KEY_RESPONDER(self)); diff --git a/shell/platform/linux/fl_key_responder.h b/shell/platform/linux/fl_key_responder.h index 1b415089c3aff..4d5533ac4c9d8 100644 --- a/shell/platform/linux/fl_key_responder.h +++ b/shell/platform/linux/fl_key_responder.h @@ -9,6 +9,7 @@ #include #include "flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h" +#include "flutter/shell/platform/linux/public/flutter_linux/fl_key_event.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_value.h" G_BEGIN_DECLS @@ -51,7 +52,7 @@ struct _FlKeyResponderInterface { * The implementation of #fl_key_responder_handle_event. */ void (*handle_event)(FlKeyResponder* responder, - GdkEventKey* event, + FlKeyEvent* event, FlKeyResponderAsyncCallback callback, gpointer user_data); }; @@ -59,7 +60,8 @@ struct _FlKeyResponderInterface { /** * fl_key_responder_handle_event: * @responder: the #FlKeyResponder self. - * @event: the event to be handled. Must not be null. + * @event: the event to be handled. Must not be null. The object is managed + * by callee and must not be assumed available after this function. * @callback: the callback to report the result. It should be called exactly * once. Must not be null. * @user_data: a value that will be sent back in the callback. Can be null. @@ -70,7 +72,7 @@ struct _FlKeyResponderInterface { * `fl_key_responder_handle_event` or during it. */ void fl_key_responder_handle_event(FlKeyResponder* responder, - GdkEventKey* event, + FlKeyEvent* event, FlKeyResponderAsyncCallback callback, gpointer user_data); diff --git a/shell/platform/linux/fl_keyboard_manager.cc b/shell/platform/linux/fl_keyboard_manager.cc index d627188ca270c..020745ff292fd 100644 --- a/shell/platform/linux/fl_keyboard_manager.cc +++ b/shell/platform/linux/fl_keyboard_manager.cc @@ -25,10 +25,10 @@ G_DECLARE_FINAL_TYPE(FlKeyboardPendingEvent, struct _FlKeyboardPendingEvent { GObject parent_instance; - // A clone of the target event. + // The target event. // // This is freed by #FlKeyboardPendingEvent. - GdkEventKey* event; + FlKeyEvent* event; // Self-incrementing ID attached to an event sent to the framework. // @@ -63,39 +63,34 @@ static void fl_keyboard_pending_event_class_init( static void fl_keyboard_pending_event_init(FlKeyboardPendingEvent* self) {} -// Calculates a unique ID for a given GdkEventKey object to use for +// Calculates a unique ID for a given FlKeyEvent object to use for // identification of responses from the framework. -static uint64_t fl_keyboard_manager_get_event_hash(GdkEventKey* event) { +static uint64_t fl_keyboard_manager_get_event_hash(FlKeyEvent* event) { // Combine the event timestamp, the type of event, and the hardware keycode // (scan code) of the event to come up with a unique id for this event that // can be derived solely from the event data itself, so that we can identify // whether or not we have seen this event already. return (event->time & 0xffffffff) | (static_cast(event->type) & 0xffff) << 32 | - (static_cast(event->hardware_keycode) & 0xffff) << 48; + (static_cast(event->keycode) & 0xffff) << 48; } // Create a new FlKeyboardPendingEvent by providing the target event, // the sequence ID, and the number of responders that will reply. -FlKeyboardPendingEvent* fl_keyboard_pending_event_new(GdkEventKey* event, +// +// This will acquire the ownership of the event. +FlKeyboardPendingEvent* fl_keyboard_pending_event_new(FlKeyEvent* event, uint64_t sequence_id, size_t to_reply) { FlKeyboardPendingEvent* self = FL_KEYBOARD_PENDING_EVENT( g_object_new(fl_keyboard_pending_event_get_type(), nullptr)); - FL_KEYBOARD_PENDING_EVENT(self); - - // Copy the event to preserve refcounts for referenced values (mainly the - // window). - GdkEventKey* event_copy = reinterpret_cast( - gdk_event_copy(reinterpret_cast(event))); - FlKeyboardPendingEvent* self2 = FL_KEYBOARD_PENDING_EVENT(self); - self->event = event_copy; + self->event = event; self->sequence_id = sequence_id; self->unreplied = to_reply; self->any_handled = false; self->hash = fl_keyboard_manager_get_event_hash(event); - return self2; + return self; } /* Declare and define FlKeyboardManagerUserData */ @@ -125,7 +120,7 @@ namespace { // Context variables for the foreach call used to dispatch events to responders. typedef struct { - GdkEventKey* event; + FlKeyEvent* event; FlKeyboardManagerUserData* user_data; } DispatchToResponderLoopContext; @@ -216,9 +211,9 @@ static void fl_keyboard_manager_dispose(GObject* object) { if (self->text_input_plugin != nullptr) g_clear_object(&self->text_input_plugin); g_ptr_array_free(self->responder_list, TRUE); - g_ptr_array_set_free_func(self->pending_responds, g_object_unref); + g_ptr_array_set_free_func(self->pending_responds, fl_key_event_destroy_notify); g_ptr_array_free(self->pending_responds, TRUE); - g_ptr_array_set_free_func(self->pending_redispatches, g_object_unref); + g_ptr_array_set_free_func(self->pending_redispatches, fl_key_event_destroy_notify); g_ptr_array_free(self->pending_redispatches, TRUE); G_OBJECT_CLASS(fl_keyboard_manager_parent_class)->dispose(object); @@ -281,7 +276,7 @@ static bool fl_keyboard_manager_remove_redispatched(FlKeyboardManager* self, gpointer removed = g_ptr_array_remove_index_fast(self->pending_redispatches, result_index); g_return_val_if_fail(removed != nullptr, TRUE); - g_object_unref(removed); + fl_key_event_destroy_notify(removed); return TRUE; } else { return FALSE; @@ -323,9 +318,9 @@ static void responder_handle_event_callback(bool handled, } if (should_redispatch) { g_ptr_array_add(self->pending_redispatches, pending); - self->redispatch_callback(reinterpret_cast(pending->event)); + self->redispatch_callback(pending->event->origin); } else { - g_object_unref(pending); + fl_key_event_destroy_notify(pending); } } } @@ -373,7 +368,7 @@ static void dispatch_to_responder(gpointer responder_data, } gboolean fl_keyboard_manager_handle_event(FlKeyboardManager* self, - GdkEventKey* event) { + FlKeyEvent* event) { g_return_val_if_fail(FL_IS_KEYBOARD_MANAGER(self), FALSE); g_return_val_if_fail(event != nullptr, FALSE); diff --git a/shell/platform/linux/fl_keyboard_manager.h b/shell/platform/linux/fl_keyboard_manager.h index 98777c83e895f..6917e82eb3a26 100644 --- a/shell/platform/linux/fl_keyboard_manager.h +++ b/shell/platform/linux/fl_keyboard_manager.h @@ -12,12 +12,15 @@ /** * FlKeyboardManagerRedispatcher: - * @event: the event to dispatch. + * @event: the pointer to the event to dispatch. * * The signature for a callback with which a #FlKeyboardManager redispatches * key events that are not handled by anyone. + * + * The #gdk_event is an opaque pointer. It will be GdkEvent* in actual + * applications, or a dummy pointer in unit tests. **/ -typedef void (*FlKeyboardManagerRedispatcher)(const GdkEvent* event); +typedef void (*FlKeyboardManagerRedispatcher)(const gpointer gdk_event); G_BEGIN_DECLS @@ -86,13 +89,14 @@ void fl_keyboard_manager_add_responder(FlKeyboardManager* manager, /** * fl_keyboard_manager_handle_event: * @manager: the #FlKeyboardManager self. - * @event: the event to be dispatched. + * @event: the event to be dispatched. This event will be managed and + * released by #FlKeyboardManager. * * Add a new #FlKeyResponder to the #FlKeyboardManager. Responders added * earlier will receive events earlier. */ gboolean fl_keyboard_manager_handle_event(FlKeyboardManager* manager, - GdkEventKey* event); + FlKeyEvent* event); /** * fl_keyboard_manager_is_state_clear: diff --git a/shell/platform/linux/fl_keyboard_manager_test.cc b/shell/platform/linux/fl_keyboard_manager_test.cc index 150ae04faaf5a..f6017b4959746 100644 --- a/shell/platform/linux/fl_keyboard_manager_test.cc +++ b/shell/platform/linux/fl_keyboard_manager_test.cc @@ -26,7 +26,7 @@ struct _FlKeyboardCallRecord { GObject parent_instance; FlKeyMockResponder* responder; - GdkEventKey* event; + FlKeyEvent* event; FlKeyResponderAsyncCallback callback; gpointer user_data; }; @@ -68,7 +68,7 @@ static void fl_keyboard_call_record_class_init( static FlKeyboardCallRecord* fl_keyboard_call_record_new( FlKeyMockResponder* responder, - GdkEventKey* event, + FlKeyEvent* event, FlKeyResponderAsyncCallback callback, gpointer user_data) { g_return_val_if_fail(FL_IS_KEY_MOCK_RESPONDER(responder), nullptr); @@ -108,7 +108,7 @@ G_DEFINE_TYPE_WITH_CODE(FlKeyMockResponder, static void fl_key_mock_responder_handle_event( FlKeyResponder* responder, - GdkEventKey* event, + FlKeyEvent* event, FlKeyResponderAsyncCallback callback, gpointer user_data); @@ -118,7 +118,7 @@ static void fl_key_mock_responder_iface_init(FlKeyResponderInterface* iface) { static void fl_key_mock_responder_handle_event( FlKeyResponder* responder, - GdkEventKey* event, + FlKeyEvent* event, FlKeyResponderAsyncCallback callback, gpointer user_data) { FlKeyMockResponder* self = FL_KEY_MOCK_RESPONDER(responder); @@ -153,27 +153,27 @@ static gpointer g_ptr_array_last(GPtrArray* array) { } namespace { +// A dummy object, whose pointer will be used as _g_key_event->origin. +static int _origin_event; // A global variable to store new event. It is a global variable so that it can -// be returned by key_event_new for easy use. -GdkEventKey _g_key_event; +// be returned by fl_key_event_new_by_mock for easy use. +static FlKeyEvent _g_key_event; } // namespace -static GdkEventKey* key_event_new(gboolean is_down, - guint keyval, - guint16 hardware_keycode, - guint state, - gboolean is_modifier) { - _g_key_event.type = is_down ? GDK_KEY_PRESS : GDK_KEY_RELEASE; - _g_key_event.window = nullptr; - _g_key_event.send_event = FALSE; - _g_key_event.time = 12345; +static FlKeyEvent* fl_fl_key_event_new_by_mock_by_mock(bool is_press, + guint keyval, + guint16 keycode, + guint state, + gboolean is_modifier) { + _g_key_event.is_press = is_press; + _g_key_event.time = 0; _g_key_event.state = state; _g_key_event.keyval = keyval; _g_key_event.length = 0; _g_key_event.string = nullptr; - _g_key_event.hardware_keycode = hardware_keycode; - _g_key_event.group = 0; - _g_key_event.is_modifier = is_modifier ? 1 : 0; + _g_key_event.keycode = keycode; + _g_key_event.origin = &_origin_event; + _g_key_event.dispose_origin = nullptr; return &_g_key_event; } @@ -183,25 +183,16 @@ namespace { GPtrArray* _g_redispatched_events; } // namespace -static GdkEventKey* GDK_EVENT_KEY(gpointer pointer) { - return reinterpret_cast(pointer); -} - -static void gdk_event_destroy_notify(gpointer pointer) { - gdk_event_free((GdkEvent*)pointer); -} - static GPtrArray* redispatched_events() { if (_g_redispatched_events == nullptr) { _g_redispatched_events = - g_ptr_array_new_with_free_func(gdk_event_destroy_notify); + g_ptr_array_new_with_free_func(fl_key_event_destroy_notify); } return _g_redispatched_events; } -static void store_redispatched_event(const GdkEvent* event) { - // We don't use gdk_event_copy here because it crashes, likely because - // _g_key_event is statically allocated. - GdkEvent* new_event = gdk_event_new(event->type); +static void store_redispatched_event(const FlKeyEvent* event) { + g_return_if_fail(event->origin == &_origin_event); + FlKeyEvent* new_event = g_new(FlKeyEvent, 1); *new_event = *event; g_ptr_array_add(redispatched_events(), new_event); } @@ -220,7 +211,7 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { // Dispatch a key event manager_handled = fl_keyboard_manager_handle_event( - manager, key_event_new(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); + manager, fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); EXPECT_EQ(manager_handled, true); EXPECT_EQ(redispatched_events()->len, 0u); EXPECT_EQ(call_records->len, 1u); @@ -237,7 +228,7 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { /// Test 2: Two events that are unhandled by the framework manager_handled = fl_keyboard_manager_handle_event( - manager, key_event_new(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); + manager, fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); EXPECT_EQ(manager_handled, true); EXPECT_EQ(redispatched_events()->len, 0u); EXPECT_EQ(call_records->len, 1u); @@ -248,7 +239,7 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { // Dispatch another key event manager_handled = fl_keyboard_manager_handle_event( - manager, key_event_new(true, GDK_KEY_b, kKeyCodeKeyB, 0x10, false)); + manager, fl_key_event_new_by_mock(true, GDK_KEY_b, kKeyCodeKeyB, 0x10, false)); EXPECT_EQ(manager_handled, true); EXPECT_EQ(redispatched_events()->len, 0u); EXPECT_EQ(call_records->len, 2u); @@ -261,22 +252,22 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { record = FL_KEYBOARD_CALL_RECORD(g_ptr_array_index(call_records, 1)); record->callback(false, record->user_data); EXPECT_EQ(redispatched_events()->len, 1u); - EXPECT_EQ(GDK_EVENT_KEY(g_ptr_array_last(redispatched_events()))->keyval, + EXPECT_EQ(g_ptr_array_last(redispatched_events())->keyval, 0x62u); record = FL_KEYBOARD_CALL_RECORD(g_ptr_array_index(call_records, 0)); record->callback(false, record->user_data); EXPECT_EQ(redispatched_events()->len, 2u); - EXPECT_EQ(GDK_EVENT_KEY(g_ptr_array_last(redispatched_events()))->keyval, + EXPECT_EQ(g_ptr_array_last(redispatched_events())->keyval, 0x61u); g_ptr_array_clear(call_records); // Resolve redispatches manager_handled = fl_keyboard_manager_handle_event( - manager, GDK_EVENT_KEY(g_ptr_array_index(redispatched_events(), 0))); + manager, g_ptr_array_index(redispatched_events(), 0)); EXPECT_EQ(manager_handled, false); manager_handled = fl_keyboard_manager_handle_event( - manager, GDK_EVENT_KEY(g_ptr_array_index(redispatched_events(), 1))); + manager, g_ptr_array_index(redispatched_events(), 1)); EXPECT_EQ(manager_handled, false); EXPECT_EQ(call_records->len, 0u); @@ -286,7 +277,7 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { /// Test 3: Dispatch the same event again to ensure that prevention from /// redispatching only works once. manager_handled = fl_keyboard_manager_handle_event( - manager, key_event_new(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); + manager, fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); EXPECT_EQ(manager_handled, true); EXPECT_EQ(redispatched_events()->len, 0u); EXPECT_EQ(call_records->len, 1u); @@ -312,7 +303,7 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithSyncResponds) { // Dispatch a key event responder->callback_handler = respond_true; manager_handled = fl_keyboard_manager_handle_event( - manager, key_event_new(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); + manager, fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); EXPECT_EQ(manager_handled, true); EXPECT_EQ(call_records->len, 1u); record = FL_KEYBOARD_CALL_RECORD(g_ptr_array_index(call_records, 0)); @@ -329,7 +320,7 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithSyncResponds) { /// Test 2: An event unhandled by the framework responder->callback_handler = respond_false; manager_handled = fl_keyboard_manager_handle_event( - manager, key_event_new(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); + manager, fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); EXPECT_EQ(manager_handled, true); EXPECT_EQ(call_records->len, 1u); record = FL_KEYBOARD_CALL_RECORD(g_ptr_array_index(call_records, 0)); @@ -342,7 +333,7 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithSyncResponds) { // Resolve redispatch manager_handled = fl_keyboard_manager_handle_event( - manager, GDK_EVENT_KEY(g_ptr_array_index(redispatched_events(), 0))); + manager, g_ptr_array_index(redispatched_events(), 0)); EXPECT_EQ(manager_handled, false); EXPECT_EQ(call_records->len, 0u); @@ -365,7 +356,7 @@ TEST(FlKeyboardManagerTest, WithTwoAsyncDelegates) { /// Test 1: One delegate responds true, the other false manager_handled = fl_keyboard_manager_handle_event( - manager, key_event_new(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); + manager, fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); EXPECT_EQ(manager_handled, true); EXPECT_EQ(redispatched_events()->len, 0u); @@ -388,7 +379,7 @@ TEST(FlKeyboardManagerTest, WithTwoAsyncDelegates) { /// Test 2: All delegates respond false manager_handled = fl_keyboard_manager_handle_event( - manager, key_event_new(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); + manager, fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); EXPECT_EQ(manager_handled, true); EXPECT_EQ(redispatched_events()->len, 0u); @@ -405,7 +396,7 @@ TEST(FlKeyboardManagerTest, WithTwoAsyncDelegates) { // Resolve redispatch manager_handled = fl_keyboard_manager_handle_event( - manager, GDK_EVENT_KEY(g_ptr_array_index(redispatched_events(), 0))); + manager, g_ptr_array_index(redispatched_events(), 0)); EXPECT_EQ(manager_handled, false); EXPECT_EQ(call_records->len, 0u); diff --git a/shell/platform/linux/fl_text_input_plugin.cc b/shell/platform/linux/fl_text_input_plugin.cc index 2c4e4debe1a3a..ae6d41fa3e52c 100644 --- a/shell/platform/linux/fl_text_input_plugin.cc +++ b/shell/platform/linux/fl_text_input_plugin.cc @@ -488,7 +488,7 @@ static void fl_text_input_plugin_dispose(GObject* object) { // Implements FlTextInputPlugin::filter_keypress. static gboolean fl_text_input_plugin_filter_keypress_default( FlTextInputPlugin* self, - GdkEventKey* event) { + FlKeyEvent* event) { g_return_val_if_fail(FL_IS_TEXT_INPUT_PLUGIN(self), false); FlTextInputPluginPrivate* priv = static_cast( @@ -498,7 +498,7 @@ static gboolean fl_text_input_plugin_filter_keypress_default( return FALSE; } - if (gtk_im_context_filter_keypress(priv->im_context, event)) { + if (gtk_im_context_filter_keypress(priv->im_context, reinterpret_cast(event->origin))) { return TRUE; } @@ -506,7 +506,7 @@ static gboolean fl_text_input_plugin_filter_keypress_default( gboolean do_action = FALSE; // Handle navigation keys. gboolean changed = FALSE; - if (event->type == GDK_KEY_PRESS) { + if (event->is_press) { switch (event->keyval) { case GDK_KEY_End: case GDK_KEY_KP_End: @@ -612,7 +612,7 @@ FlTextInputPlugin* fl_text_input_plugin_new(FlBinaryMessenger* messenger, // Filters the a keypress given to the plugin through the plugin's // filter_keypress callback. gboolean fl_text_input_plugin_filter_keypress(FlTextInputPlugin* self, - GdkEventKey* event) { + FlKeyEvent* event) { g_return_val_if_fail(FL_IS_TEXT_INPUT_PLUGIN(self), FALSE); if (FL_TEXT_INPUT_PLUGIN_GET_CLASS(self)->filter_keypress) { return FL_TEXT_INPUT_PLUGIN_GET_CLASS(self)->filter_keypress(self, event); diff --git a/shell/platform/linux/fl_text_input_plugin.h b/shell/platform/linux/fl_text_input_plugin.h index 0f5d216f7da53..df65e5712f90c 100644 --- a/shell/platform/linux/fl_text_input_plugin.h +++ b/shell/platform/linux/fl_text_input_plugin.h @@ -7,6 +7,7 @@ #include +#include "flutter/shell/platform/linux/fl_key_event.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_view.h" @@ -31,7 +32,7 @@ struct _FlTextInputPluginClass { /** * Virtual method called to filter a keypress. */ - gboolean (*filter_keypress)(FlTextInputPlugin* self, GdkEventKey* event); + gboolean (*filter_keypress)(FlTextInputPlugin* self, FlKeyEvent* event); }; /** @@ -50,14 +51,14 @@ FlTextInputPlugin* fl_text_input_plugin_new(FlBinaryMessenger* messenger, /** * fl_text_input_plugin_filter_keypress * @plugin: an #FlTextInputPlugin. - * @event: a #GdkEventKey + * @event: a #FlKeyEvent * * Process a Gdk key event. * * Returns: %TRUE if the event was used. */ gboolean fl_text_input_plugin_filter_keypress(FlTextInputPlugin* plugin, - GdkEventKey* event); + FlKeyEvent* event); G_END_DECLS diff --git a/shell/platform/linux/fl_view.cc b/shell/platform/linux/fl_view.cc index 1334fedc7b243..89a4e714b257e 100644 --- a/shell/platform/linux/fl_view.cc +++ b/shell/platform/linux/fl_view.cc @@ -12,6 +12,7 @@ #include "flutter/shell/platform/linux/fl_engine_private.h" #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/fl_key_event.h" #include "flutter/shell/platform/linux/fl_keyboard_manager.h" #include "flutter/shell/platform/linux/fl_mouse_cursor_plugin.h" #include "flutter/shell/platform/linux/fl_platform_plugin.h" @@ -157,6 +158,8 @@ static void fl_view_plugin_registry_iface_init( iface->get_registrar_for_plugin = fl_view_get_registrar_for_plugin; } +static void redispatch_key_event(const gpointer* raw_event); + static gboolean event_box_button_release_event(GtkWidget* widget, GdkEventButton* event, FlView* view); @@ -185,7 +188,7 @@ static void fl_view_constructed(GObject* object) { FlBinaryMessenger* messenger = fl_engine_get_binary_messenger(self->engine); self->accessibility_plugin = fl_accessibility_plugin_new(self); self->keyboard_manager = fl_keyboard_manager_new( - fl_text_input_plugin_new(messenger, self), gdk_event_put); + fl_text_input_plugin_new(messenger, self), redispatch_key_event); // The embedder responder must be added before the channel responder. fl_keyboard_manager_add_responder( self->keyboard_manager, @@ -509,14 +512,16 @@ static gboolean event_box_motion_notify_event(GtkWidget* widget, static gboolean fl_view_key_press_event(GtkWidget* widget, GdkEventKey* event) { FlView* self = FL_VIEW(widget); - return fl_keyboard_manager_handle_event(self->keyboard_manager, event); + return fl_keyboard_manager_handle_event(self->keyboard_manager, + fl_key_event_new_from_gdk_event(gdk_event_copy(event))); } // Implements GtkWidget::key_release_event. static gboolean fl_view_key_release_event(GtkWidget* widget, GdkEventKey* event) { FlView* self = FL_VIEW(widget); - return fl_keyboard_manager_handle_event(self->keyboard_manager, event); + return fl_keyboard_manager_handle_event(self->keyboard_manager, + fl_key_event_new_from_gdk_event(gdk_event_copy(event))); } static void fl_view_put(FlView* self, @@ -742,3 +747,10 @@ void fl_view_end_frame(FlView* view) { gtk_widget_queue_draw(GTK_WIDGET(view)); } + +static void redispatch_key_event(const gpointer* raw_event) { + const GdkEvent* event = reinterpret_cast(raw_event); + GdkEventType type = gdk_event_get_event_type(event); + g_return_if_fail(type == GDK_KEY_PRESS || type == GDK_KEY_RELEASE); + gdk_event_put(event); +} From 740b91d889b805af31acb30ea158478111f87bd3 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Thu, 13 May 2021 03:20:26 -0700 Subject: [PATCH 075/126] Compilable --- shell/platform/linux/BUILD.gn | 2 + .../linux/fl_key_channel_responder.cc | 6 +- .../linux/fl_key_channel_responder_test.cc | 37 ++-- .../linux/fl_key_embedder_responder.cc | 2 +- .../linux/fl_key_embedder_responder_test.cc | 190 ++++++++++-------- shell/platform/linux/fl_key_event.cc | 22 +- shell/platform/linux/fl_key_event.h | 8 +- shell/platform/linux/fl_key_responder.h | 2 +- shell/platform/linux/fl_keyboard_manager.cc | 13 +- shell/platform/linux/fl_keyboard_manager.h | 8 +- .../linux/fl_keyboard_manager_test.cc | 54 +++-- shell/platform/linux/fl_text_input_plugin.cc | 13 +- shell/platform/linux/fl_text_input_plugin.h | 22 +- shell/platform/linux/fl_view.cc | 34 +++- .../linux/testing/mock_text_input_plugin.cc | 11 +- 15 files changed, 255 insertions(+), 169 deletions(-) diff --git a/shell/platform/linux/BUILD.gn b/shell/platform/linux/BUILD.gn index 371d142f6c42d..a8109be879bc8 100644 --- a/shell/platform/linux/BUILD.gn +++ b/shell/platform/linux/BUILD.gn @@ -75,6 +75,7 @@ source_set("flutter_linux_sources") { "fl_dart_project_private.h", "fl_engine_private.h", "fl_keyboard_manager.h", + "fl_key_event.h", "fl_key_responder.h", "fl_key_channel_responder.h", "fl_key_embedder_responder.h", @@ -104,6 +105,7 @@ source_set("flutter_linux_sources") { "fl_json_method_codec.cc", "fl_key_channel_responder.cc", "fl_key_embedder_responder.cc", + "fl_key_event.cc", "fl_key_responder.cc", "fl_keyboard_manager.cc", "fl_message_codec.cc", diff --git a/shell/platform/linux/fl_key_channel_responder.cc b/shell/platform/linux/fl_key_channel_responder.cc index 3a6643b1ce768..76c080e0d2c69 100644 --- a/shell/platform/linux/fl_key_channel_responder.cc +++ b/shell/platform/linux/fl_key_channel_responder.cc @@ -244,13 +244,13 @@ static void fl_key_channel_responder_handle_event( static bool num_lock_pressed = FALSE; switch (event->keyval) { case GDK_KEY_Num_Lock: - num_lock_pressed = event->type == GDK_KEY_PRESS; + num_lock_pressed = event->is_press; break; case GDK_KEY_Caps_Lock: - caps_lock_pressed = event->type == GDK_KEY_PRESS; + caps_lock_pressed = event->is_press; break; case GDK_KEY_Shift_Lock: - shift_lock_pressed = event->type == GDK_KEY_PRESS; + shift_lock_pressed = event->is_press; break; } diff --git a/shell/platform/linux/fl_key_channel_responder_test.cc b/shell/platform/linux/fl_key_channel_responder_test.cc index 6492d84fb6ddc..00beabd780c5f 100644 --- a/shell/platform/linux/fl_key_channel_responder_test.cc +++ b/shell/platform/linux/fl_key_channel_responder_test.cc @@ -58,11 +58,11 @@ static FlKeyEvent* fl_key_event_new_by_mock(guint32 time_in_milliseconds, bool is_press, guint keyval, guint16 keycode, - guint state, + int state, const char* string, gboolean is_modifier) { if (_g_key_event.string != nullptr) { - g_free(_g_key_event.string); + g_free(const_cast(_g_key_event.string)); } _g_key_event.is_press = is_press; _g_key_event.time = time_in_milliseconds; @@ -88,8 +88,10 @@ TEST(FlKeyChannelResponderTest, SendKeyEvent) { g_autoptr(FlKeyResponder) responder = FL_KEY_RESPONDER(fl_key_channel_responder_new(messenger, &mock)); - fl_key_responder_handle_event(responder, fl_key_event_new_by_mock(true, 0x04, GDK_KEY_A, 0x0, "A", false), responder_callback, - loop); + fl_key_responder_handle_event( + responder, + fl_key_event_new_by_mock(12345, true, 0x04, GDK_KEY_A, 0x0, "A", false), + responder_callback, loop); expected_value = "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, keyCode: 65, " "modifiers: 0, unicodeScalarValues: 65}"; @@ -98,8 +100,10 @@ TEST(FlKeyChannelResponderTest, SendKeyEvent) { // Blocks here until echo_response_cb is called. g_main_loop_run(loop); - fl_key_responder_handle_event(responder, fl_key_event_new_by_mock(false, 0x04, GDK_KEY_A, 0x0, "A", false), responder_callback, - loop); + fl_key_responder_handle_event( + responder, + fl_key_event_new_by_mock(23456, false, 0x04, GDK_KEY_A, 0x0, "A", false), + responder_callback, loop); expected_value = "{type: keyup, keymap: linux, scanCode: 4, toolkit: gtk, keyCode: 65, " "modifiers: 0, unicodeScalarValues: 65}"; @@ -123,8 +127,11 @@ void test_lock_event(guint key_code, g_autoptr(FlKeyResponder) responder = FL_KEY_RESPONDER(fl_key_channel_responder_new(messenger, &mock)); - fl_key_responder_handle_event(responder, fl_key_event_new_by_mock(true, 0x04, key_code, 0x0, nullptr, false), responder_callback, - loop); + fl_key_responder_handle_event( + responder, + fl_key_event_new_by_mock(12345, true, 0x04, key_code, 0x0, nullptr, + false), + responder_callback, loop); expected_value = down_expected; expected_handled = FALSE; @@ -133,8 +140,11 @@ void test_lock_event(guint key_code, expected_value = up_expected; expected_handled = FALSE; - fl_key_responder_handle_event(responder, fl_key_event_new_by_mock(false, 0x04, key_code, 0x0, nullptr, false), responder_callback, - loop); + fl_key_responder_handle_event( + responder, + fl_key_event_new_by_mock(12346, false, 0x04, key_code, 0x0, nullptr, + false), + responder_callback, loop); // Blocks here until echo_response_cb is called. g_main_loop_run(loop); @@ -179,8 +189,11 @@ TEST(FlKeyChannelResponderTest, TestKeyEventHandledByFramework) { g_autoptr(FlKeyResponder) responder = FL_KEY_RESPONDER(fl_key_channel_responder_new(messenger, &mock)); - fl_key_responder_handle_event(responder, fl_key_event_new_by_mock(true, 0x04, GDK_KEY_A, 0x0, nullptr, false), responder_callback, - loop); + fl_key_responder_handle_event( + responder, + fl_key_event_new_by_mock(12345, true, 0x04, GDK_KEY_A, 0x0, nullptr, + false), + responder_callback, loop); expected_handled = TRUE; expected_value = "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, " diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index 6a6438ef9e1a3..5cb4b2bca61e4 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -715,7 +715,7 @@ static void fl_key_embedder_responder_handle_event( const uint64_t logical_key = event_to_logical_key(event, self->keyval_to_logical_key); const double timestamp = event_to_timestamp(event); - const bool is_down_event = event->type == GDK_KEY_PRESS; + const bool is_down_event = event->is_press; SyncStateLoopContext sync_pressed_state_context; sync_pressed_state_context.self = self; diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index bac83d969faf1..39701d64d633a 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -120,9 +120,9 @@ static FlKeyEvent* fl_key_event_new_by_mock(guint32 time_in_milliseconds, bool is_press, guint keyval, guint16 keycode, - guint state, + int state, gboolean is_modifier) { - _g_key_event.type = is_press; + _g_key_event.is_press = is_press; _g_key_event.time = time_in_milliseconds; _g_key_event.state = state; _g_key_event.keyval = keyval; @@ -189,7 +189,8 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { // Key down fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(12345, kPress, GDK_KEY_a, kKeyCodeKeyA, 0, kIsNotModifier), + fl_key_event_new_by_mock(12345, kPress, GDK_KEY_a, kKeyCodeKeyA, 0, + kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -208,10 +209,11 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { // Skip testing key repeats, which is not present on GDK. // Key up - fl_key_responder_handle_event(responder, - fl_key_event_new_by_mock(12346, kRelease, GDK_KEY_a, - kKeyCodeKeyA, 0, kIsNotModifier), - verify_response_handled, &user_data); + fl_key_responder_handle_event( + responder, + fl_key_event_new_by_mock(12346, kRelease, GDK_KEY_a, kKeyCodeKeyA, 0, + kIsNotModifier), + verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); @@ -230,7 +232,8 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { // Key down fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(12347, kPress, GDK_KEY_q, kKeyCodeKeyA, 0, kIsNotModifier), + fl_key_event_new_by_mock(12347, kPress, GDK_KEY_q, kKeyCodeKeyA, 0, + kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -247,10 +250,11 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { g_ptr_array_clear(g_call_records); // Key up - fl_key_responder_handle_event(responder, - fl_key_event_new_by_mock(12348, kRelease, GDK_KEY_q, - kKeyCodeKeyA, 0, kIsNotModifier), - verify_response_handled, &user_data); + fl_key_responder_handle_event( + responder, + fl_key_event_new_by_mock(12348, kRelease, GDK_KEY_q, kKeyCodeKeyA, 0, + kIsNotModifier), + verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); @@ -282,8 +286,8 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { // Press shift right fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(101, kPress, GDK_KEY_Shift_R, kKeyCodeShiftRight, 0, - kIsModifier), + fl_key_event_new_by_mock(101, kPress, GDK_KEY_Shift_R, kKeyCodeShiftRight, + 0, kIsModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -300,7 +304,8 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { // Press key A fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(102, kPress, GDK_KEY_A, kKeyCodeKeyA, 0x1, kIsNotModifier), + fl_key_event_new_by_mock(102, kPress, GDK_KEY_A, kKeyCodeKeyA, 0x1, + kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -317,8 +322,8 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { // Release shift right fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(103, kRelease, GDK_KEY_Shift_R, kKeyCodeShiftRight, 0x1, - kIsModifier), + fl_key_event_new_by_mock(103, kRelease, GDK_KEY_Shift_R, + kKeyCodeShiftRight, 0x1, kIsModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -335,7 +340,8 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { // Release key A fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(104, kRelease, GDK_KEY_A, kKeyCodeKeyA, 0, kIsNotModifier), + fl_key_event_new_by_mock(104, kRelease, GDK_KEY_A, kKeyCodeKeyA, 0, + kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -374,7 +380,7 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { fl_key_responder_handle_event( responder, fl_key_event_new_by_mock(101, kPress, GDK_KEY_KP_End, kKeyCodeNumpad1, 0, - kIsNotModifier), + kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -391,8 +397,8 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { // Press NumLock (stage 0 -> 1) fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(102, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock, 0, - kIsNotModifier), + fl_key_event_new_by_mock(102, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock, + 0, kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -409,8 +415,8 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { // Release numpad 1 (stage 1) fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(104, kRelease, GDK_KEY_KP_1, kKeyCodeNumpad1, 0x10, - kIsNotModifier), + fl_key_event_new_by_mock(104, kRelease, GDK_KEY_KP_1, kKeyCodeNumpad1, + 0x10, kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -427,8 +433,8 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { // Release NumLock (stage 1 -> 2) fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(103, kRelease, GDK_KEY_Num_Lock, kKeyCodeNumLock, 0x10, - kIsModifier), + fl_key_event_new_by_mock(103, kRelease, GDK_KEY_Num_Lock, kKeyCodeNumLock, + 0x10, kIsModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -445,8 +451,8 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { // Press Numpad 1 (stage 2) fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(101, kPress, GDK_KEY_KP_End, kKeyCodeNumpad1, 0x10, - kIsNotModifier), + fl_key_event_new_by_mock(101, kPress, GDK_KEY_KP_End, kKeyCodeNumpad1, + 0x10, kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -463,8 +469,8 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { // Press NumLock (stage 2 -> 3) fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(102, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock, 0x10, - kIsNotModifier), + fl_key_event_new_by_mock(102, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock, + 0x10, kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -481,8 +487,8 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { // Release numpad 1 (stage 3) fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(104, kRelease, GDK_KEY_KP_1, kKeyCodeNumpad1, 0x10, - kIsNotModifier), + fl_key_event_new_by_mock(104, kRelease, GDK_KEY_KP_1, kKeyCodeNumpad1, + 0x10, kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -499,8 +505,8 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { // Release NumLock (stage 3 -> 0) fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(103, kRelease, GDK_KEY_Num_Lock, kKeyCodeNumLock, 0x10, - kIsModifier), + fl_key_event_new_by_mock(103, kRelease, GDK_KEY_Num_Lock, kKeyCodeNumLock, + 0x10, kIsModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -534,8 +540,8 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { // Press CapsLock (stage 0 -> 1) fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(101, kPress, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x0, - kIsModifier), + fl_key_event_new_by_mock(101, kPress, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, + 0x0, kIsModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -552,7 +558,8 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { // Press key A (stage 1) fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(102, kPress, GDK_KEY_A, kKeyCodeKeyA, 0x2, kIsNotModifier), + fl_key_event_new_by_mock(102, kPress, GDK_KEY_A, kKeyCodeKeyA, 0x2, + kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -569,8 +576,8 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { // Release CapsLock (stage 1 -> 2) fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(103, kRelease, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x2, - kIsModifier), + fl_key_event_new_by_mock(103, kRelease, GDK_KEY_Caps_Lock, + kKeyCodeCapsLock, 0x2, kIsModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -588,7 +595,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { fl_key_responder_handle_event( responder, fl_key_event_new_by_mock(104, kRelease, GDK_KEY_A, kKeyCodeKeyA, 0x2, - kIsNotModifier), + kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -605,8 +612,8 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { // Press CapsLock (stage 2 -> 3) fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(105, kPress, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x2, - kIsModifier), + fl_key_event_new_by_mock(105, kPress, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, + 0x2, kIsModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -623,7 +630,8 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { // Press key A (stage 3) fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(106, kPress, GDK_KEY_A, kKeyCodeKeyA, 0x2, kIsNotModifier), + fl_key_event_new_by_mock(106, kPress, GDK_KEY_A, kKeyCodeKeyA, 0x2, + kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -640,8 +648,8 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { // Release CapsLock (stage 3 -> 0) fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(107, kRelease, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x2, - kIsModifier), + fl_key_event_new_by_mock(107, kRelease, GDK_KEY_Caps_Lock, + kKeyCodeCapsLock, 0x2, kIsModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -659,7 +667,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { fl_key_responder_handle_event( responder, fl_key_event_new_by_mock(108, kRelease, GDK_KEY_a, kKeyCodeKeyA, 0x0, - kIsNotModifier), + kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -693,7 +701,8 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { // Press key A (stage 0) fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(101, kPress, GDK_KEY_a, kKeyCodeKeyA, 0x0, kIsNotModifier), + fl_key_event_new_by_mock(101, kPress, GDK_KEY_a, kKeyCodeKeyA, 0x0, + kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -710,8 +719,8 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { // Press CapsLock (stage 0 -> 1) fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(102, kPress, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x2, - kIsModifier), + fl_key_event_new_by_mock(102, kPress, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, + 0x2, kIsModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -728,8 +737,8 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { // Release CapsLock (stage 1 -> 2) fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(103, kRelease, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x2, - kIsModifier), + fl_key_event_new_by_mock(103, kRelease, GDK_KEY_Caps_Lock, + kKeyCodeCapsLock, 0x2, kIsModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -747,7 +756,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { fl_key_responder_handle_event( responder, fl_key_event_new_by_mock(104, kRelease, GDK_KEY_A, kKeyCodeKeyA, 0x2, - kIsNotModifier), + kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -764,7 +773,8 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { // Press key A (stage 2) fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(105, kPress, GDK_KEY_A, kKeyCodeKeyA, 0x2, kIsNotModifier), + fl_key_event_new_by_mock(105, kPress, GDK_KEY_A, kKeyCodeKeyA, 0x2, + kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -781,8 +791,8 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { // Press CapsLock (stage 2 -> 3) fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(106, kPress, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x0, - kIsModifier), + fl_key_event_new_by_mock(106, kPress, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, + 0x0, kIsModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -799,8 +809,8 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { // Release CapsLock (stage 3 -> 0) fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(107, kRelease, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, 0x2, - kIsModifier), + fl_key_event_new_by_mock(107, kRelease, GDK_KEY_Caps_Lock, + kKeyCodeCapsLock, 0x2, kIsModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -818,7 +828,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { fl_key_responder_handle_event( responder, fl_key_event_new_by_mock(108, kRelease, GDK_KEY_a, kKeyCodeKeyA, 0x0, - kIsNotModifier), + kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -848,7 +858,8 @@ TEST(FlKeyEmbedderResponderTest, IgnoreDuplicateDownEvent) { // Press KeyA fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(101, kPress, GDK_KEY_a, kKeyCodeKeyA, 0, kIsNotModifier), + fl_key_event_new_by_mock(101, kPress, GDK_KEY_a, kKeyCodeKeyA, 0, + kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -862,7 +873,8 @@ TEST(FlKeyEmbedderResponderTest, IgnoreDuplicateDownEvent) { g_expected_handled = true; fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(102, kPress, GDK_KEY_q, kKeyCodeKeyA, 0, kIsNotModifier), + fl_key_event_new_by_mock(102, kPress, GDK_KEY_q, kKeyCodeKeyA, 0, + kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 0u); @@ -870,7 +882,8 @@ TEST(FlKeyEmbedderResponderTest, IgnoreDuplicateDownEvent) { // Release KeyA fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(103, kRelease, GDK_KEY_q, kKeyCodeKeyA, 0, kIsNotModifier), + fl_key_event_new_by_mock(103, kRelease, GDK_KEY_q, kKeyCodeKeyA, 0, + kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -893,7 +906,8 @@ TEST(FlKeyEmbedderResponderTest, IgnoreAbruptUpEvent) { g_expected_handled = true; fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(103, kRelease, GDK_KEY_q, kKeyCodeKeyA, 0, kIsNotModifier), + fl_key_event_new_by_mock(103, kRelease, GDK_KEY_q, kKeyCodeKeyA, 0, + kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 0u); @@ -921,8 +935,8 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) { // Send a ControlLeft up fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(101, kRelease, GDK_KEY_Control_L, kKeyCodeControlLeft, - state, kIsModifier), + fl_key_event_new_by_mock(101, kRelease, GDK_KEY_Control_L, + kKeyCodeControlLeft, state, kIsModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 2u); @@ -951,8 +965,8 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) { state = 0; fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(102, kPress, GDK_KEY_Control_L, kKeyCodeControlLeft, state, - kIsModifier), + fl_key_event_new_by_mock(102, kPress, GDK_KEY_Control_L, + kKeyCodeControlLeft, state, kIsModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); @@ -965,8 +979,8 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) { // Send another ControlLeft down fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(103, kPress, GDK_KEY_Control_L, kKeyCodeControlLeft, state, - kIsModifier), + fl_key_event_new_by_mock(103, kPress, GDK_KEY_Control_L, + kKeyCodeControlLeft, state, kIsModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 2u); @@ -993,8 +1007,8 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) { state = GDK_CONTROL_MASK; fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(104, kRelease, GDK_KEY_Control_L, kKeyCodeControlLeft, - state, kIsModifier), + fl_key_event_new_by_mock(104, kRelease, GDK_KEY_Control_L, + kKeyCodeControlLeft, state, kIsModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); @@ -1009,8 +1023,8 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) { // Send a ControlRight up. fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(105, kRelease, GDK_KEY_Control_R, kKeyCodeControlRight, - state, kIsModifier), + fl_key_event_new_by_mock(105, kRelease, GDK_KEY_Control_R, + kKeyCodeControlRight, state, kIsModifier), verify_response_handled, &user_data); // A ControlLeft down is synthesized, with no non-synthesized event. @@ -1051,7 +1065,7 @@ TEST(FlKeyEmbedderResponderTest, fl_key_responder_handle_event( responder, fl_key_event_new_by_mock(101, kPress, GDK_KEY_a, kKeyCodeKeyA, state, - kIsNotModifier), + kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 2u); @@ -1081,7 +1095,7 @@ TEST(FlKeyEmbedderResponderTest, fl_key_responder_handle_event( responder, fl_key_event_new_by_mock(102, kRelease, GDK_KEY_A, kKeyCodeKeyA, state, - kIsNotModifier), + kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 2u); @@ -1111,8 +1125,8 @@ TEST(FlKeyEmbedderResponderTest, fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(101, kPress, GDK_KEY_Control_L, kKeyCodeCapsLock, state, - kIsModifier), + fl_key_event_new_by_mock(101, kPress, GDK_KEY_Control_L, kKeyCodeCapsLock, + state, kIsModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -1134,7 +1148,7 @@ TEST(FlKeyEmbedderResponderTest, fl_key_responder_handle_event( responder, fl_key_event_new_by_mock(102, kPress, GDK_KEY_A, kKeyCodeKeyA, state, - kIsNotModifier), + kIsNotModifier), verify_response_handled, &user_data); // The synthesized event should have physical CapsLock and logical @@ -1180,8 +1194,8 @@ TEST(FlKeyEmbedderResponderTest, fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(101, kPress, GDK_KEY_Control_L, kKeyCodeCapsLock, state, - kIsModifier), + fl_key_event_new_by_mock(101, kPress, GDK_KEY_Control_L, kKeyCodeCapsLock, + state, kIsModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -1203,7 +1217,7 @@ TEST(FlKeyEmbedderResponderTest, fl_key_responder_handle_event( responder, fl_key_event_new_by_mock(102, kPress, GDK_KEY_A, kKeyCodeKeyA, state, - kIsNotModifier), + kIsNotModifier), verify_response_handled, &user_data); // The synthesized event should have physical CapsLock and logical @@ -1250,7 +1264,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { fl_key_responder_handle_event( responder, fl_key_event_new_by_mock(101, kPress, GDK_KEY_a, kKeyCodeKeyA, state, - kIsNotModifier), + kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 2u); @@ -1280,7 +1294,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { fl_key_responder_handle_event( responder, fl_key_event_new_by_mock(102, kRelease, GDK_KEY_A, kKeyCodeKeyA, state, - kIsNotModifier), + kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 4u); @@ -1324,8 +1338,8 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { g_expected_handled = true; fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(103, kRelease, GDK_KEY_Num_Lock, kKeyCodeNumLock, state, - kIsModifier), + fl_key_event_new_by_mock(103, kRelease, GDK_KEY_Num_Lock, kKeyCodeNumLock, + state, kIsModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 0u); @@ -1351,8 +1365,8 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) { // NumLock down fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(101, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock, state, - kIsModifier), + fl_key_event_new_by_mock(101, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock, + state, kIsModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 3u); @@ -1389,8 +1403,8 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) { // NumLock up fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(102, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock, state, - kIsModifier), + fl_key_event_new_by_mock(102, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock, + state, kIsModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 4u); @@ -1451,7 +1465,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizationOccursOnIgnoredEvents) { fl_key_responder_handle_event( responder, fl_key_event_new_by_mock(101, kRelease, GDK_KEY_a, kKeyCodeKeyA, state, - kIsNotModifier), + kIsNotModifier), verify_response_handled, &user_data); EXPECT_EQ(g_call_records->len, 2u); diff --git a/shell/platform/linux/fl_key_event.cc b/shell/platform/linux/fl_key_event.cc index e603e87c6833c..8944df14ed4a7 100644 --- a/shell/platform/linux/fl_key_event.cc +++ b/shell/platform/linux/fl_key_event.cc @@ -5,25 +5,25 @@ #include "flutter/shell/platform/linux/fl_key_event.h" static void dispose_gdk_event(gpointer target) { - dispose_gdk_event(reinterpret_cast(target)); + gdk_event_free(reinterpret_cast(target)); } -FlKeyEvent* fl_key_event_new_from_gdk_event(GdkEventKey* event) { - g_return_val_if_fail(event != nullptr, nullptr); - GdkEventType type = gdk_event_get_event_type(event); - g_return_val_if_fail(type == GDK_KEY_PRESS || type == GDK_KEY_RELEASE, nullptr); - bool valid = true; +FlKeyEvent* fl_key_event_new_from_gdk_event(GdkEvent* raw_event) { + g_return_val_if_fail(raw_event != nullptr, nullptr); + GdkEventKey* event = reinterpret_cast(raw_event); + GdkEventType type = event->type; + g_return_val_if_fail(type == GDK_KEY_PRESS || type == GDK_KEY_RELEASE, + nullptr); FlKeyEvent* result = g_new(FlKeyEvent, 1); - result->time = gdk_event_get_time(event); + result->time = event->time; result->is_press = type == GDK_KEY_PRESS; - valid = valid && gdk_event_get_keycode(event, &result->keycode); - valid = valid && gdk_event_get_keyval(event, &result->keyval); - valid = valid && gdk_event_get_state(event, &result->state); + result->keycode = event->hardware_keycode; + result->keyval = event->keyval; + result->state = event->state; result->origin = event; result->dispose_origin = dispose_gdk_event; - g_return_val_if_fail(valid, nullptr); return result; } diff --git a/shell/platform/linux/fl_key_event.h b/shell/platform/linux/fl_key_event.h index b1ebd7c250281..d8ce82c840102 100644 --- a/shell/platform/linux/fl_key_event.h +++ b/shell/platform/linux/fl_key_event.h @@ -7,7 +7,7 @@ #include -typedef void FlKeyEventDisposeOrigin(gpointer); +typedef void (*FlKeyEventDisposeOrigin)(gpointer); /** * FlKeyEvent: @@ -26,7 +26,7 @@ typedef struct _FlKeyEvent { // Keyval. guint keyval; // Modifier state. - GdkModifierType state; + int state; // String, null-terminated. // // Can be nullptr. @@ -45,8 +45,8 @@ typedef struct _FlKeyEvent { /** * fl_key_event_new_from_gdk_event: - * @event: the #GdkEvent this #FlKeyEvent is based on. The #event be a #GdkEventKey, - * and will be destroyed by #fl_key_event_dispose. + * @event: the #GdkEvent this #FlKeyEvent is based on. The #event be a + * #GdkEventKey, and will be destroyed by #fl_key_event_dispose. * * Create a new #FlKeyEvent based on a #GdkEventKey. * diff --git a/shell/platform/linux/fl_key_responder.h b/shell/platform/linux/fl_key_responder.h index 4d5533ac4c9d8..a21620675d005 100644 --- a/shell/platform/linux/fl_key_responder.h +++ b/shell/platform/linux/fl_key_responder.h @@ -8,8 +8,8 @@ #include #include +#include "flutter/shell/platform/linux/fl_key_event.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h" -#include "flutter/shell/platform/linux/public/flutter_linux/fl_key_event.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_value.h" G_BEGIN_DECLS diff --git a/shell/platform/linux/fl_keyboard_manager.cc b/shell/platform/linux/fl_keyboard_manager.cc index 020745ff292fd..1966f319391ce 100644 --- a/shell/platform/linux/fl_keyboard_manager.cc +++ b/shell/platform/linux/fl_keyboard_manager.cc @@ -71,7 +71,10 @@ static uint64_t fl_keyboard_manager_get_event_hash(FlKeyEvent* event) { // can be derived solely from the event data itself, so that we can identify // whether or not we have seen this event already. return (event->time & 0xffffffff) | - (static_cast(event->type) & 0xffff) << 32 | + (static_cast(event->is_press ? GDK_KEY_PRESS + : GDK_KEY_RELEASE) & + 0xffff) + << 32 | (static_cast(event->keycode) & 0xffff) << 48; } @@ -211,9 +214,11 @@ static void fl_keyboard_manager_dispose(GObject* object) { if (self->text_input_plugin != nullptr) g_clear_object(&self->text_input_plugin); g_ptr_array_free(self->responder_list, TRUE); - g_ptr_array_set_free_func(self->pending_responds, fl_key_event_destroy_notify); + g_ptr_array_set_free_func(self->pending_responds, + fl_key_event_destroy_notify); g_ptr_array_free(self->pending_responds, TRUE); - g_ptr_array_set_free_func(self->pending_redispatches, fl_key_event_destroy_notify); + g_ptr_array_set_free_func(self->pending_redispatches, + fl_key_event_destroy_notify); g_ptr_array_free(self->pending_redispatches, TRUE); G_OBJECT_CLASS(fl_keyboard_manager_parent_class)->dispose(object); @@ -318,7 +323,7 @@ static void responder_handle_event_callback(bool handled, } if (should_redispatch) { g_ptr_array_add(self->pending_redispatches, pending); - self->redispatch_callback(pending->event->origin); + self->redispatch_callback(pending->event); } else { fl_key_event_destroy_notify(pending); } diff --git a/shell/platform/linux/fl_keyboard_manager.h b/shell/platform/linux/fl_keyboard_manager.h index 6917e82eb3a26..da65e77e5f9f8 100644 --- a/shell/platform/linux/fl_keyboard_manager.h +++ b/shell/platform/linux/fl_keyboard_manager.h @@ -16,11 +16,8 @@ * * The signature for a callback with which a #FlKeyboardManager redispatches * key events that are not handled by anyone. - * - * The #gdk_event is an opaque pointer. It will be GdkEvent* in actual - * applications, or a dummy pointer in unit tests. **/ -typedef void (*FlKeyboardManagerRedispatcher)(const gpointer gdk_event); +typedef void (*FlKeyboardManagerRedispatcher)(FlKeyEvent* event); G_BEGIN_DECLS @@ -63,7 +60,8 @@ G_DECLARE_FINAL_TYPE(FlKeyboardManager, * @text_input_plugin: the #FlTextInputPlugin to send key events to if the * framework doesn't handle them. * @redispatch_callback: how the events should be sent if no processing - * objects handle the event. Typically #gdk_event_put. + * objects handle the event. Typically a function that calls #gdk_event_put + * on #FlKeyEvent::origin. * * Create a new #FlKeyboardManager. The text input plugin must be specified * now, while the responders should be added later with diff --git a/shell/platform/linux/fl_keyboard_manager_test.cc b/shell/platform/linux/fl_keyboard_manager_test.cc index f6017b4959746..34ed598bcc854 100644 --- a/shell/platform/linux/fl_keyboard_manager_test.cc +++ b/shell/platform/linux/fl_keyboard_manager_test.cc @@ -8,6 +8,8 @@ #include "gtest/gtest.h" +#define FL_KEY_EVENT(target) reinterpret_cast(target) + namespace { typedef void (*CallbackHandler)(FlKeyResponderAsyncCallback callback, gpointer user_data); @@ -160,10 +162,10 @@ static int _origin_event; static FlKeyEvent _g_key_event; } // namespace -static FlKeyEvent* fl_fl_key_event_new_by_mock_by_mock(bool is_press, +static FlKeyEvent* fl_key_event_new_by_mock(bool is_press, guint keyval, guint16 keycode, - guint state, + int state, gboolean is_modifier) { _g_key_event.is_press = is_press; _g_key_event.time = 0; @@ -190,7 +192,7 @@ static GPtrArray* redispatched_events() { } return _g_redispatched_events; } -static void store_redispatched_event(const FlKeyEvent* event) { +static void store_redispatched_event(FlKeyEvent* event) { g_return_if_fail(event->origin == &_origin_event); FlKeyEvent* new_event = g_new(FlKeyEvent, 1); *new_event = *event; @@ -211,14 +213,15 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { // Dispatch a key event manager_handled = fl_keyboard_manager_handle_event( - manager, fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); + manager, + fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); EXPECT_EQ(manager_handled, true); EXPECT_EQ(redispatched_events()->len, 0u); EXPECT_EQ(call_records->len, 1u); record = FL_KEYBOARD_CALL_RECORD(g_ptr_array_index(call_records, 0)); EXPECT_EQ(record->responder->delegate_id, 1); EXPECT_EQ(record->event->keyval, 0x61u); - EXPECT_EQ(record->event->hardware_keycode, 0x26u); + EXPECT_EQ(record->event->keycode, 0x26u); record->callback(true, record->user_data); EXPECT_EQ(redispatched_events()->len, 0u); @@ -228,46 +231,48 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { /// Test 2: Two events that are unhandled by the framework manager_handled = fl_keyboard_manager_handle_event( - manager, fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); + manager, + fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); EXPECT_EQ(manager_handled, true); EXPECT_EQ(redispatched_events()->len, 0u); EXPECT_EQ(call_records->len, 1u); record = FL_KEYBOARD_CALL_RECORD(g_ptr_array_index(call_records, 0)); EXPECT_EQ(record->responder->delegate_id, 1); EXPECT_EQ(record->event->keyval, 0x61u); - EXPECT_EQ(record->event->hardware_keycode, 0x26u); + EXPECT_EQ(record->event->keycode, 0x26u); // Dispatch another key event manager_handled = fl_keyboard_manager_handle_event( - manager, fl_key_event_new_by_mock(true, GDK_KEY_b, kKeyCodeKeyB, 0x10, false)); + manager, + fl_key_event_new_by_mock(true, GDK_KEY_b, kKeyCodeKeyB, 0x10, false)); EXPECT_EQ(manager_handled, true); EXPECT_EQ(redispatched_events()->len, 0u); EXPECT_EQ(call_records->len, 2u); record = FL_KEYBOARD_CALL_RECORD(g_ptr_array_index(call_records, 1)); EXPECT_EQ(record->responder->delegate_id, 1); EXPECT_EQ(record->event->keyval, 0x62u); - EXPECT_EQ(record->event->hardware_keycode, 0x38u); + EXPECT_EQ(record->event->keycode, 0x38u); // Resolve the second event first to test out-of-order response record = FL_KEYBOARD_CALL_RECORD(g_ptr_array_index(call_records, 1)); record->callback(false, record->user_data); EXPECT_EQ(redispatched_events()->len, 1u); - EXPECT_EQ(g_ptr_array_last(redispatched_events())->keyval, + EXPECT_EQ(FL_KEY_EVENT(g_ptr_array_last(redispatched_events()))->keyval, 0x62u); record = FL_KEYBOARD_CALL_RECORD(g_ptr_array_index(call_records, 0)); record->callback(false, record->user_data); EXPECT_EQ(redispatched_events()->len, 2u); - EXPECT_EQ(g_ptr_array_last(redispatched_events())->keyval, + EXPECT_EQ(FL_KEY_EVENT(g_ptr_array_last(redispatched_events()))->keyval, 0x61u); g_ptr_array_clear(call_records); // Resolve redispatches manager_handled = fl_keyboard_manager_handle_event( - manager, g_ptr_array_index(redispatched_events(), 0)); + manager, FL_KEY_EVENT(g_ptr_array_index(redispatched_events(), 0))); EXPECT_EQ(manager_handled, false); manager_handled = fl_keyboard_manager_handle_event( - manager, g_ptr_array_index(redispatched_events(), 1)); + manager, FL_KEY_EVENT(g_ptr_array_index(redispatched_events(), 1))); EXPECT_EQ(manager_handled, false); EXPECT_EQ(call_records->len, 0u); @@ -277,7 +282,8 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { /// Test 3: Dispatch the same event again to ensure that prevention from /// redispatching only works once. manager_handled = fl_keyboard_manager_handle_event( - manager, fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); + manager, + fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); EXPECT_EQ(manager_handled, true); EXPECT_EQ(redispatched_events()->len, 0u); EXPECT_EQ(call_records->len, 1u); @@ -303,13 +309,14 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithSyncResponds) { // Dispatch a key event responder->callback_handler = respond_true; manager_handled = fl_keyboard_manager_handle_event( - manager, fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); + manager, + fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); EXPECT_EQ(manager_handled, true); EXPECT_EQ(call_records->len, 1u); record = FL_KEYBOARD_CALL_RECORD(g_ptr_array_index(call_records, 0)); EXPECT_EQ(record->responder->delegate_id, 1); EXPECT_EQ(record->event->keyval, 0x61u); - EXPECT_EQ(record->event->hardware_keycode, 0x26u); + EXPECT_EQ(record->event->keycode, 0x26u); EXPECT_EQ(redispatched_events()->len, 0u); EXPECT_TRUE(fl_keyboard_manager_is_state_clear(manager)); @@ -320,20 +327,21 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithSyncResponds) { /// Test 2: An event unhandled by the framework responder->callback_handler = respond_false; manager_handled = fl_keyboard_manager_handle_event( - manager, fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); + manager, + fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); EXPECT_EQ(manager_handled, true); EXPECT_EQ(call_records->len, 1u); record = FL_KEYBOARD_CALL_RECORD(g_ptr_array_index(call_records, 0)); EXPECT_EQ(record->responder->delegate_id, 1); EXPECT_EQ(record->event->keyval, 0x61u); - EXPECT_EQ(record->event->hardware_keycode, 0x26u); + EXPECT_EQ(record->event->keycode, 0x26u); EXPECT_EQ(redispatched_events()->len, 1u); g_ptr_array_clear(call_records); // Resolve redispatch manager_handled = fl_keyboard_manager_handle_event( - manager, g_ptr_array_index(redispatched_events(), 0)); + manager, FL_KEY_EVENT(g_ptr_array_index(redispatched_events(), 0))); EXPECT_EQ(manager_handled, false); EXPECT_EQ(call_records->len, 0u); @@ -356,7 +364,8 @@ TEST(FlKeyboardManagerTest, WithTwoAsyncDelegates) { /// Test 1: One delegate responds true, the other false manager_handled = fl_keyboard_manager_handle_event( - manager, fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); + manager, + fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); EXPECT_EQ(manager_handled, true); EXPECT_EQ(redispatched_events()->len, 0u); @@ -379,7 +388,8 @@ TEST(FlKeyboardManagerTest, WithTwoAsyncDelegates) { /// Test 2: All delegates respond false manager_handled = fl_keyboard_manager_handle_event( - manager, fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); + manager, + fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); EXPECT_EQ(manager_handled, true); EXPECT_EQ(redispatched_events()->len, 0u); @@ -396,7 +406,7 @@ TEST(FlKeyboardManagerTest, WithTwoAsyncDelegates) { // Resolve redispatch manager_handled = fl_keyboard_manager_handle_event( - manager, g_ptr_array_index(redispatched_events(), 0)); + manager, FL_KEY_EVENT(g_ptr_array_index(redispatched_events(), 0))); EXPECT_EQ(manager_handled, false); EXPECT_EQ(call_records->len, 0u); diff --git a/shell/platform/linux/fl_text_input_plugin.cc b/shell/platform/linux/fl_text_input_plugin.cc index ae6d41fa3e52c..dbf318e5bb7fd 100644 --- a/shell/platform/linux/fl_text_input_plugin.cc +++ b/shell/platform/linux/fl_text_input_plugin.cc @@ -61,6 +61,9 @@ struct FlTextInputPluginPrivate { // Input method. GtkIMContext* im_context; + // IM filter. + FlTextInputPluginImFilter im_filter; + flutter::TextInputModel* text_model; // The owning Flutter view. @@ -498,7 +501,7 @@ static gboolean fl_text_input_plugin_filter_keypress_default( return FALSE; } - if (gtk_im_context_filter_keypress(priv->im_context, reinterpret_cast(event->origin))) { + if (priv->im_filter(priv->im_context, event->origin)) { return TRUE; } @@ -590,9 +593,12 @@ static void fl_text_input_plugin_init(FlTextInputPlugin* self) { priv->text_model = new flutter::TextInputModel(); } -FlTextInputPlugin* fl_text_input_plugin_new(FlBinaryMessenger* messenger, - FlView* view) { +FlTextInputPlugin* fl_text_input_plugin_new( + FlBinaryMessenger* messenger, + FlView* view, + FlTextInputPluginImFilter im_filter) { g_return_val_if_fail(FL_IS_BINARY_MESSENGER(messenger), nullptr); + g_return_val_if_fail(im_filter != nullptr, nullptr); FlTextInputPlugin* self = FL_TEXT_INPUT_PLUGIN( g_object_new(fl_text_input_plugin_get_type(), nullptr)); @@ -605,6 +611,7 @@ FlTextInputPlugin* fl_text_input_plugin_new(FlBinaryMessenger* messenger, fl_method_channel_set_method_call_handler(priv->channel, method_call_cb, self, nullptr); priv->view = view; + priv->im_filter = im_filter; return self; } diff --git a/shell/platform/linux/fl_text_input_plugin.h b/shell/platform/linux/fl_text_input_plugin.h index df65e5712f90c..f8d92b58f24cf 100644 --- a/shell/platform/linux/fl_text_input_plugin.h +++ b/shell/platform/linux/fl_text_input_plugin.h @@ -11,6 +11,19 @@ #include "flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_view.h" +/** + * FlTextInputPluginImFilter: + * @event: the pointer to the GdkEventKey. + * + * The signature for a callback with which a #FlTextInputPlugin allow an input + * method to internally handle key press and release events. + * + * The #gdk_event is an opaque pointer. It will be GdkEvent* in actual + * applications, or a dummy pointer in unit tests. + **/ +typedef gboolean (*FlTextInputPluginImFilter)(GtkIMContext* im_context, + gpointer gdk_event); + G_BEGIN_DECLS G_DECLARE_DERIVABLE_TYPE(FlTextInputPlugin, @@ -39,14 +52,19 @@ struct _FlTextInputPluginClass { * fl_text_input_plugin_new: * @messenger: an #FlBinaryMessenger. * @view: the #FlView with which the text input plugin is associated. + * @im_filter: a function used to allow an input method to internally handle + * key press and release events. Typically a wrap of + * #gtk_im_context_filter_keypress. Must not be nullptr. * * Creates a new plugin that implements SystemChannels.textInput from the * Flutter services library. * * Returns: a new #FlTextInputPlugin. */ -FlTextInputPlugin* fl_text_input_plugin_new(FlBinaryMessenger* messenger, - FlView* view); +FlTextInputPlugin* fl_text_input_plugin_new( + FlBinaryMessenger* messenger, + FlView* view, + FlTextInputPluginImFilter im_filter); /** * fl_text_input_plugin_filter_keypress diff --git a/shell/platform/linux/fl_view.cc b/shell/platform/linux/fl_view.cc index 89a4e714b257e..af8a26d70c724 100644 --- a/shell/platform/linux/fl_view.cc +++ b/shell/platform/linux/fl_view.cc @@ -158,7 +158,10 @@ static void fl_view_plugin_registry_iface_init( iface->get_registrar_for_plugin = fl_view_get_registrar_for_plugin; } -static void redispatch_key_event(const gpointer* raw_event); +static void redispatch_key_event_by_gtk(FlKeyEvent* event); + +static gboolean text_input_im_filter_by_gtk(GtkIMContext* im_context, + gpointer gdk_event); static gboolean event_box_button_release_event(GtkWidget* widget, GdkEventButton* event, @@ -188,7 +191,8 @@ static void fl_view_constructed(GObject* object) { FlBinaryMessenger* messenger = fl_engine_get_binary_messenger(self->engine); self->accessibility_plugin = fl_accessibility_plugin_new(self); self->keyboard_manager = fl_keyboard_manager_new( - fl_text_input_plugin_new(messenger, self), redispatch_key_event); + fl_text_input_plugin_new(messenger, self, text_input_im_filter_by_gtk), + redispatch_key_event_by_gtk); // The embedder responder must be added before the channel responder. fl_keyboard_manager_add_responder( self->keyboard_manager, @@ -512,16 +516,18 @@ static gboolean event_box_motion_notify_event(GtkWidget* widget, static gboolean fl_view_key_press_event(GtkWidget* widget, GdkEventKey* event) { FlView* self = FL_VIEW(widget); - return fl_keyboard_manager_handle_event(self->keyboard_manager, - fl_key_event_new_from_gdk_event(gdk_event_copy(event))); + return fl_keyboard_manager_handle_event( + self->keyboard_manager, fl_key_event_new_from_gdk_event(gdk_event_copy( + reinterpret_cast(event)))); } // Implements GtkWidget::key_release_event. static gboolean fl_view_key_release_event(GtkWidget* widget, GdkEventKey* event) { FlView* self = FL_VIEW(widget); - return fl_keyboard_manager_handle_event(self->keyboard_manager, - fl_key_event_new_from_gdk_event(gdk_event_copy(event))); + return fl_keyboard_manager_handle_event( + self->keyboard_manager, fl_key_event_new_from_gdk_event(gdk_event_copy( + reinterpret_cast(event)))); } static void fl_view_put(FlView* self, @@ -748,9 +754,17 @@ void fl_view_end_frame(FlView* view) { gtk_widget_queue_draw(GTK_WIDGET(view)); } -static void redispatch_key_event(const gpointer* raw_event) { - const GdkEvent* event = reinterpret_cast(raw_event); - GdkEventType type = gdk_event_get_event_type(event); +static void redispatch_key_event_by_gtk(FlKeyEvent* event) { + GdkEvent* gdk_event = reinterpret_cast(event->origin); + GdkEventType type = gdk_event->type; g_return_if_fail(type == GDK_KEY_PRESS || type == GDK_KEY_RELEASE); - gdk_event_put(event); + gdk_event_put(gdk_event); +} + +static gboolean text_input_im_filter_by_gtk(GtkIMContext* im_context, + gpointer gdk_event) { + GdkEventKey* event = reinterpret_cast(gdk_event); + GdkEventType type = event->type; + g_return_val_if_fail(type == GDK_KEY_PRESS || type == GDK_KEY_RELEASE, false); + return gtk_im_context_filter_keypress(im_context, event); } diff --git a/shell/platform/linux/testing/mock_text_input_plugin.cc b/shell/platform/linux/testing/mock_text_input_plugin.cc index 92309fa0e1c7c..4a0fd0f1930d1 100644 --- a/shell/platform/linux/testing/mock_text_input_plugin.cc +++ b/shell/platform/linux/testing/mock_text_input_plugin.cc @@ -7,7 +7,7 @@ struct _FlMockTextInputPlugin { FlTextInputPlugin parent_instance; - gboolean (*filter_keypress)(FlTextInputPlugin* self, GdkEventKey* event); + gboolean (*filter_keypress)(FlTextInputPlugin* self, FlKeyEvent* event); }; G_DEFINE_TYPE(FlMockTextInputPlugin, @@ -15,7 +15,7 @@ G_DEFINE_TYPE(FlMockTextInputPlugin, fl_text_input_plugin_get_type()) static gboolean mock_text_input_plugin_filter_keypress(FlTextInputPlugin* self, - GdkEventKey* event) { + FlKeyEvent* event) { FlMockTextInputPlugin* mock_self = FL_MOCK_TEXT_INPUT_PLUGIN(self); if (mock_self->filter_keypress) { return mock_self->filter_keypress(self, event); @@ -31,9 +31,14 @@ static void fl_mock_text_input_plugin_class_init( static void fl_mock_text_input_plugin_init(FlMockTextInputPlugin* self) {} +// static gboolean text_input_im_filter_by_mock(GtkIMContext* im_context, +// gpointer gdk_event) { +// return true; +// } + // Creates a mock text_input_plugin FlMockTextInputPlugin* fl_mock_text_input_plugin_new( - gboolean (*filter_keypress)(FlTextInputPlugin* self, GdkEventKey* event)) { + gboolean (*filter_keypress)(FlTextInputPlugin* self, FlKeyEvent* event)) { FlMockTextInputPlugin* self = FL_MOCK_TEXT_INPUT_PLUGIN( g_object_new(fl_mock_text_input_plugin_get_type(), nullptr)); self->filter_keypress = filter_keypress; From 6aa9368c16f0afb9addc9cd15210f342218d5b63 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Fri, 14 May 2021 01:40:28 -0700 Subject: [PATCH 076/126] ATP --- .../linux/fl_key_channel_responder_test.cc | 12 ++-- .../linux/fl_key_embedder_responder_test.cc | 2 +- shell/platform/linux/fl_key_event.cc | 10 +-- shell/platform/linux/fl_key_event.h | 11 ++- shell/platform/linux/fl_keyboard_manager.cc | 31 ++++++-- shell/platform/linux/fl_keyboard_manager.h | 2 +- .../linux/fl_keyboard_manager_test.cc | 71 ++++++++++++------- shell/platform/linux/fl_view.cc | 6 +- 8 files changed, 93 insertions(+), 52 deletions(-) diff --git a/shell/platform/linux/fl_key_channel_responder_test.cc b/shell/platform/linux/fl_key_channel_responder_test.cc index 00beabd780c5f..acfa8f904140a 100644 --- a/shell/platform/linux/fl_key_channel_responder_test.cc +++ b/shell/platform/linux/fl_key_channel_responder_test.cc @@ -71,7 +71,7 @@ static FlKeyEvent* fl_key_event_new_by_mock(guint32 time_in_milliseconds, _g_key_event.string = clone_string(string, &_g_key_event.length); _g_key_event.keycode = keycode; _g_key_event.origin = &_origin_event; - _g_key_event.dispose_origin = nullptr; + _g_key_event.dispose = nullptr; return &_g_key_event; } @@ -90,7 +90,7 @@ TEST(FlKeyChannelResponderTest, SendKeyEvent) { fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(12345, true, 0x04, GDK_KEY_A, 0x0, "A", false), + fl_key_event_new_by_mock(12345, true, GDK_KEY_A, 0x04, 0x0, "A", false), responder_callback, loop); expected_value = "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, keyCode: 65, " @@ -102,7 +102,7 @@ TEST(FlKeyChannelResponderTest, SendKeyEvent) { fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(23456, false, 0x04, GDK_KEY_A, 0x0, "A", false), + fl_key_event_new_by_mock(23456, false, GDK_KEY_A, 0x04, 0x0, "A", false), responder_callback, loop); expected_value = "{type: keyup, keymap: linux, scanCode: 4, toolkit: gtk, keyCode: 65, " @@ -129,7 +129,7 @@ void test_lock_event(guint key_code, fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(12345, true, 0x04, key_code, 0x0, nullptr, + fl_key_event_new_by_mock(12345, true, key_code, 0x04, 0x0, nullptr, false), responder_callback, loop); expected_value = down_expected; @@ -142,7 +142,7 @@ void test_lock_event(guint key_code, expected_handled = FALSE; fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(12346, false, 0x04, key_code, 0x0, nullptr, + fl_key_event_new_by_mock(12346, false, key_code, 0x04, 0x0, nullptr, false), responder_callback, loop); @@ -191,7 +191,7 @@ TEST(FlKeyChannelResponderTest, TestKeyEventHandledByFramework) { fl_key_responder_handle_event( responder, - fl_key_event_new_by_mock(12345, true, 0x04, GDK_KEY_A, 0x0, nullptr, + fl_key_event_new_by_mock(12345, true, GDK_KEY_A, 0x04, 0x0, nullptr, false), responder_callback, loop); expected_handled = TRUE; diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index 39701d64d633a..ff2898d1c18bc 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -130,7 +130,7 @@ static FlKeyEvent* fl_key_event_new_by_mock(guint32 time_in_milliseconds, _g_key_event.string = nullptr; _g_key_event.keycode = keycode; _g_key_event.origin = &_origin_event; - _g_key_event.dispose_origin = nullptr; + _g_key_event.dispose = nullptr; return &_g_key_event; } diff --git a/shell/platform/linux/fl_key_event.cc b/shell/platform/linux/fl_key_event.cc index 8944df14ed4a7..02f70b00e8616 100644 --- a/shell/platform/linux/fl_key_event.cc +++ b/shell/platform/linux/fl_key_event.cc @@ -4,8 +4,8 @@ #include "flutter/shell/platform/linux/fl_key_event.h" -static void dispose_gdk_event(gpointer target) { - gdk_event_free(reinterpret_cast(target)); +static void dispose_from_gdk_event(FlKeyEvent* event) { + gdk_event_free(reinterpret_cast(event->origin)); } FlKeyEvent* fl_key_event_new_from_gdk_event(GdkEvent* raw_event) { @@ -22,14 +22,14 @@ FlKeyEvent* fl_key_event_new_from_gdk_event(GdkEvent* raw_event) { result->keyval = event->keyval; result->state = event->state; result->origin = event; - result->dispose_origin = dispose_gdk_event; + result->dispose = dispose_from_gdk_event; return result; } void fl_key_event_dispose(FlKeyEvent* event) { - if (event->dispose_origin != nullptr) { - event->dispose_origin(event->origin); + if (event->dispose != nullptr) { + event->dispose(event); } g_free(event); } diff --git a/shell/platform/linux/fl_key_event.h b/shell/platform/linux/fl_key_event.h index d8ce82c840102..83755cf51057c 100644 --- a/shell/platform/linux/fl_key_event.h +++ b/shell/platform/linux/fl_key_event.h @@ -7,7 +7,9 @@ #include -typedef void (*FlKeyEventDisposeOrigin)(gpointer); +typedef struct _FlKeyEvent FlKeyEvent; + +typedef void (*FlKeyEventDispose)(FlKeyEvent*); /** * FlKeyEvent: @@ -39,8 +41,11 @@ typedef struct _FlKeyEvent { // For native events, this is #GdkEvent pointer. // For unit tests, this is a dummy pointer. gpointer origin; - // A callback to free #origin, called when #FlKeyEvent is disposed. - FlKeyEventDisposeOrigin dispose_origin; + // A callback to free this #FlKeyEvent. + // + // If #dispose is nullptr, nothing will be performed when this event + // is no longer needed. + FlKeyEventDispose dispose; } FlKeyEvent; /** diff --git a/shell/platform/linux/fl_keyboard_manager.cc b/shell/platform/linux/fl_keyboard_manager.cc index 1966f319391ce..0781ad3895b3e 100644 --- a/shell/platform/linux/fl_keyboard_manager.cc +++ b/shell/platform/linux/fl_keyboard_manager.cc @@ -52,7 +52,7 @@ static void fl_keyboard_pending_event_dispose(GObject* object) { g_return_if_fail(FL_IS_KEYBOARD_PENDING_EVENT(object)); FlKeyboardPendingEvent* self = FL_KEYBOARD_PENDING_EVENT(object); - g_clear_pointer(&self->event, gdk_event_free); + fl_key_event_dispose(self->event); G_OBJECT_CLASS(fl_keyboard_pending_event_parent_class)->dispose(object); } @@ -278,10 +278,11 @@ static bool fl_keyboard_manager_remove_redispatched(FlKeyboardManager* self, self->pending_redispatches, static_cast(&hash), compare_pending_by_hash, &result_index); if (found) { - gpointer removed = - g_ptr_array_remove_index_fast(self->pending_redispatches, result_index); + FlKeyboardPendingEvent* removed = + FL_KEYBOARD_PENDING_EVENT(g_ptr_array_remove_index_fast( + self->pending_redispatches, result_index)); g_return_val_if_fail(removed != nullptr, TRUE); - fl_key_event_destroy_notify(removed); + g_object_unref(removed); return TRUE; } else { return FALSE; @@ -309,11 +310,19 @@ static void responder_handle_event_callback(bool handled, pending->any_handled = pending->any_handled || handled; // All responders have replied. if (pending->unreplied == 0) { + printf("5\n"); + fflush(stdout); g_object_unref(user_data_ptr); - g_ptr_array_remove_index_fast(self->pending_responds, result_index); + printf("6\n"); + fflush(stdout); + gpointer removed = + g_ptr_array_remove_index_fast(self->pending_responds, result_index); + g_return_if_fail(removed == pending); bool should_redispatch = false; if (!pending->any_handled) { // If no responders have handled, send it to text plugin. + printf("7\n"); + fflush(stdout); if (self->text_input_plugin == nullptr || !fl_text_input_plugin_filter_keypress(self->text_input_plugin, pending->event)) { @@ -321,11 +330,19 @@ static void responder_handle_event_callback(bool handled, should_redispatch = true; } } + printf("8 should %d\n", should_redispatch); + fflush(stdout); if (should_redispatch) { g_ptr_array_add(self->pending_redispatches, pending); - self->redispatch_callback(pending->event); + printf("9\n"); + fflush(stdout); + self->redispatch_callback(pending->event->origin); + printf("10\n"); + fflush(stdout); } else { - fl_key_event_destroy_notify(pending); + g_object_unref(pending); + printf("11\n"); + fflush(stdout); } } } diff --git a/shell/platform/linux/fl_keyboard_manager.h b/shell/platform/linux/fl_keyboard_manager.h index da65e77e5f9f8..6325942355623 100644 --- a/shell/platform/linux/fl_keyboard_manager.h +++ b/shell/platform/linux/fl_keyboard_manager.h @@ -17,7 +17,7 @@ * The signature for a callback with which a #FlKeyboardManager redispatches * key events that are not handled by anyone. **/ -typedef void (*FlKeyboardManagerRedispatcher)(FlKeyEvent* event); +typedef void (*FlKeyboardManagerRedispatcher)(gpointer event); G_BEGIN_DECLS diff --git a/shell/platform/linux/fl_keyboard_manager_test.cc b/shell/platform/linux/fl_keyboard_manager_test.cc index 34ed598bcc854..6edfd7fbf91ef 100644 --- a/shell/platform/linux/fl_keyboard_manager_test.cc +++ b/shell/platform/linux/fl_keyboard_manager_test.cc @@ -58,7 +58,7 @@ static void fl_keyboard_call_record_dispose(GObject* object) { g_return_if_fail(FL_IS_KEYBOARD_CALL_RECORD(object)); FlKeyboardCallRecord* self = FL_KEYBOARD_CALL_RECORD(object); - g_clear_pointer(&self->event, gdk_event_free); + fl_key_event_dispose(self->event); G_OBJECT_CLASS(fl_keyboard_call_record_parent_class)->dispose(object); } @@ -124,9 +124,13 @@ static void fl_key_mock_responder_handle_event( FlKeyResponderAsyncCallback callback, gpointer user_data) { FlKeyMockResponder* self = FL_KEY_MOCK_RESPONDER(responder); + FlKeyEvent* new_event = g_new(FlKeyEvent, 1); + *new_event = *event; + new_event->origin = new_event; // Arbitrary value. + new_event->dispose = nullptr; g_ptr_array_add(self->call_records, FL_KEYBOARD_CALL_RECORD(fl_keyboard_call_record_new( - self, event, callback, user_data))); + self, new_event, callback, user_data))); self->callback_handler(callback, user_data); } @@ -154,48 +158,48 @@ static gpointer g_ptr_array_last(GPtrArray* array) { return g_ptr_array_index(array, array->len - 1); } -namespace { -// A dummy object, whose pointer will be used as _g_key_event->origin. -static int _origin_event; -// A global variable to store new event. It is a global variable so that it can -// be returned by fl_key_event_new_by_mock for easy use. -static FlKeyEvent _g_key_event; -} // namespace - +static void fl_key_event_new_by_mock(FlKeyEvent* event) { + g_free(event->origin); +} static FlKeyEvent* fl_key_event_new_by_mock(bool is_press, guint keyval, guint16 keycode, int state, gboolean is_modifier) { - _g_key_event.is_press = is_press; - _g_key_event.time = 0; - _g_key_event.state = state; - _g_key_event.keyval = keyval; - _g_key_event.length = 0; - _g_key_event.string = nullptr; - _g_key_event.keycode = keycode; - _g_key_event.origin = &_origin_event; - _g_key_event.dispose_origin = nullptr; - return &_g_key_event; + FlKeyEvent* event = g_new(FlKeyEvent, 1); + event->is_press = is_press; + event->time = 0; + event->state = state; + event->keyval = keyval; + event->length = 0; + event->string = nullptr; + event->keycode = keycode; + FlKeyEvent* origin_event = g_new(FlKeyEvent, 1); + *origin_event = *event; + origin_event->origin = origin_event; // Arbitrary value. + origin_event->dispose = nullptr; + event->origin = origin_event; + event->dispose = fl_key_event_new_by_mock; + return event; } namespace { -// A global variable to store redispatched scancode. It is a global variable so +// A global variable to store redispatched #FlKeyEvent. It is a global variable so // that it can be used in a function without user_data. +// +// This array does not free elements upon removal. GPtrArray* _g_redispatched_events; } // namespace static GPtrArray* redispatched_events() { if (_g_redispatched_events == nullptr) { - _g_redispatched_events = - g_ptr_array_new_with_free_func(fl_key_event_destroy_notify); + _g_redispatched_events = g_ptr_array_new(); } return _g_redispatched_events; } -static void store_redispatched_event(FlKeyEvent* event) { - g_return_if_fail(event->origin == &_origin_event); +static void store_redispatched_event(gpointer event) { FlKeyEvent* new_event = g_new(FlKeyEvent, 1); - *new_event = *event; + *new_event = *reinterpret_cast(event); g_ptr_array_add(redispatched_events(), new_event); } @@ -206,23 +210,31 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { gboolean manager_handled = false; g_autoptr(FlKeyboardManager) manager = fl_keyboard_manager_new(nullptr, store_redispatched_event); + printf("x1\n"); + fflush(stdout); fl_keyboard_manager_add_responder( manager, FL_KEY_RESPONDER(fl_key_mock_responder_new(call_records, 1))); /// Test 1: One event that is handled by the framework // Dispatch a key event + printf("x2\n"); + fflush(stdout); manager_handled = fl_keyboard_manager_handle_event( manager, fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); EXPECT_EQ(manager_handled, true); EXPECT_EQ(redispatched_events()->len, 0u); EXPECT_EQ(call_records->len, 1u); + printf("x3\n"); + fflush(stdout); record = FL_KEYBOARD_CALL_RECORD(g_ptr_array_index(call_records, 0)); EXPECT_EQ(record->responder->delegate_id, 1); EXPECT_EQ(record->event->keyval, 0x61u); EXPECT_EQ(record->event->keycode, 0x26u); + printf("x4\n"); + fflush(stdout); record->callback(true, record->user_data); EXPECT_EQ(redispatched_events()->len, 0u); @@ -230,6 +242,8 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { g_ptr_array_clear(call_records); /// Test 2: Two events that are unhandled by the framework + printf("x5\n"); + fflush(stdout); manager_handled = fl_keyboard_manager_handle_event( manager, fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); @@ -242,6 +256,7 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { EXPECT_EQ(record->event->keycode, 0x26u); // Dispatch another key event + printf("x6\n"); manager_handled = fl_keyboard_manager_handle_event( manager, fl_key_event_new_by_mock(true, GDK_KEY_b, kKeyCodeKeyB, 0x10, false)); @@ -252,6 +267,7 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { EXPECT_EQ(record->responder->delegate_id, 1); EXPECT_EQ(record->event->keyval, 0x62u); EXPECT_EQ(record->event->keycode, 0x38u); + printf("x7\n");fflush(stdout); // Resolve the second event first to test out-of-order response record = FL_KEYBOARD_CALL_RECORD(g_ptr_array_index(call_records, 1)); @@ -268,9 +284,11 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { g_ptr_array_clear(call_records); // Resolve redispatches + printf("x8\n");fflush(stdout); manager_handled = fl_keyboard_manager_handle_event( manager, FL_KEY_EVENT(g_ptr_array_index(redispatched_events(), 0))); EXPECT_EQ(manager_handled, false); + printf("x8.1\n");fflush(stdout); manager_handled = fl_keyboard_manager_handle_event( manager, FL_KEY_EVENT(g_ptr_array_index(redispatched_events(), 1))); EXPECT_EQ(manager_handled, false); @@ -281,6 +299,7 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { /// Test 3: Dispatch the same event again to ensure that prevention from /// redispatching only works once. + printf("x9\n");fflush(stdout); manager_handled = fl_keyboard_manager_handle_event( manager, fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); diff --git a/shell/platform/linux/fl_view.cc b/shell/platform/linux/fl_view.cc index af8a26d70c724..0897654e28bc3 100644 --- a/shell/platform/linux/fl_view.cc +++ b/shell/platform/linux/fl_view.cc @@ -158,7 +158,7 @@ static void fl_view_plugin_registry_iface_init( iface->get_registrar_for_plugin = fl_view_get_registrar_for_plugin; } -static void redispatch_key_event_by_gtk(FlKeyEvent* event); +static void redispatch_key_event_by_gtk(gpointer gdk_event); static gboolean text_input_im_filter_by_gtk(GtkIMContext* im_context, gpointer gdk_event); @@ -754,8 +754,8 @@ void fl_view_end_frame(FlView* view) { gtk_widget_queue_draw(GTK_WIDGET(view)); } -static void redispatch_key_event_by_gtk(FlKeyEvent* event) { - GdkEvent* gdk_event = reinterpret_cast(event->origin); +static void redispatch_key_event_by_gtk(gpointer raw_event) { + GdkEvent* gdk_event = reinterpret_cast(raw_event); GdkEventType type = gdk_event->type; g_return_if_fail(type == GDK_KEY_PRESS || type == GDK_KEY_RELEASE); gdk_event_put(gdk_event); From fafadbbea155fc03dcfaa7e3c66a4076efb466b2 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Fri, 14 May 2021 02:01:18 -0700 Subject: [PATCH 077/126] Better format --- shell/platform/linux/fl_key_event.cc | 4 -- shell/platform/linux/fl_key_event.h | 35 +++++++------- shell/platform/linux/fl_keyboard_manager.cc | 19 ++------ .../linux/fl_keyboard_manager_test.cc | 48 ++++++++----------- 4 files changed, 43 insertions(+), 63 deletions(-) diff --git a/shell/platform/linux/fl_key_event.cc b/shell/platform/linux/fl_key_event.cc index 02f70b00e8616..e9a4723effc6b 100644 --- a/shell/platform/linux/fl_key_event.cc +++ b/shell/platform/linux/fl_key_event.cc @@ -33,7 +33,3 @@ void fl_key_event_dispose(FlKeyEvent* event) { } g_free(event); } - -void fl_key_event_destroy_notify(gpointer event) { - fl_key_event_dispose(reinterpret_cast(event)); -} diff --git a/shell/platform/linux/fl_key_event.h b/shell/platform/linux/fl_key_event.h index 83755cf51057c..6f54be24ba174 100644 --- a/shell/platform/linux/fl_key_event.h +++ b/shell/platform/linux/fl_key_event.h @@ -9,7 +9,14 @@ typedef struct _FlKeyEvent FlKeyEvent; -typedef void (*FlKeyEventDispose)(FlKeyEvent*); +/** + * FlKeyEventDispose: + * @self: the self pointer to dispose. + * + * The signature for a callback with which a #FlKeyEvent performs + * before being freed. + **/ +typedef void (*FlKeyEventDispose)(FlKeyEvent* self); /** * FlKeyEvent: @@ -37,38 +44,32 @@ typedef struct _FlKeyEvent { size_t length; // An opaque pointer to the original event. // - // This is used when dispatching. - // For native events, this is #GdkEvent pointer. - // For unit tests, this is a dummy pointer. + // This is used when dispatching. For native events, this is #GdkEvent + // pointer. For unit tests, this is a dummy pointer. gpointer origin; - // A callback to free this #FlKeyEvent. + // Extra steps before freeing this #FlKeyEvent. // - // If #dispose is nullptr, nothing will be performed when this event - // is no longer needed. + // Usually a function that frees origin. Can be nullptr. FlKeyEventDispose dispose; } FlKeyEvent; /** * fl_key_event_new_from_gdk_event: - * @event: the #GdkEvent this #FlKeyEvent is based on. The #event be a + * @event: the #GdkEvent this #FlKeyEvent is based on. The #event must be a * #GdkEventKey, and will be destroyed by #fl_key_event_dispose. * - * Create a new #FlKeyEvent based on a #GdkEventKey. + * Create a new #FlKeyEvent based on a #GdkEvent. * - * Returns: a new #FlKeyEvent. Must be freed with #free (or #g_free). + * Returns: a new #FlKeyEvent. Must be freed with #fl_key_event_dispose. */ FlKeyEvent* fl_key_event_new_from_gdk_event(GdkEvent* event); /** - * fl_key_event_copy: - * @source: the source to copy from. + * fl_key_event_dispose: + * @event: the event to dispose. * - * Allocates a new event with all properties shallow copied from source. - * - * Returns: a cloned #FlKeyEvent. Must be freed with #free (or #g_free). + * Properly disposes the content of #event and then the pointer. */ void fl_key_event_dispose(FlKeyEvent* event); -void fl_key_event_destroy_notify(gpointer event); - #endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_KEY_EVENT_H_ diff --git a/shell/platform/linux/fl_keyboard_manager.cc b/shell/platform/linux/fl_keyboard_manager.cc index 0781ad3895b3e..d42118ac06fab 100644 --- a/shell/platform/linux/fl_keyboard_manager.cc +++ b/shell/platform/linux/fl_keyboard_manager.cc @@ -208,6 +208,7 @@ static void fl_keyboard_manager_class_init(FlKeyboardManagerClass* klass) { static void fl_keyboard_manager_init(FlKeyboardManager* self) {} +static void fl_key_event_destroy_notify(gpointer event); static void fl_keyboard_manager_dispose(GObject* object) { FlKeyboardManager* self = FL_KEYBOARD_MANAGER(object); @@ -310,19 +311,13 @@ static void responder_handle_event_callback(bool handled, pending->any_handled = pending->any_handled || handled; // All responders have replied. if (pending->unreplied == 0) { - printf("5\n"); - fflush(stdout); g_object_unref(user_data_ptr); - printf("6\n"); - fflush(stdout); gpointer removed = g_ptr_array_remove_index_fast(self->pending_responds, result_index); g_return_if_fail(removed == pending); bool should_redispatch = false; if (!pending->any_handled) { // If no responders have handled, send it to text plugin. - printf("7\n"); - fflush(stdout); if (self->text_input_plugin == nullptr || !fl_text_input_plugin_filter_keypress(self->text_input_plugin, pending->event)) { @@ -330,19 +325,11 @@ static void responder_handle_event_callback(bool handled, should_redispatch = true; } } - printf("8 should %d\n", should_redispatch); - fflush(stdout); if (should_redispatch) { g_ptr_array_add(self->pending_redispatches, pending); - printf("9\n"); - fflush(stdout); self->redispatch_callback(pending->event->origin); - printf("10\n"); - fflush(stdout); } else { g_object_unref(pending); - printf("11\n"); - fflush(stdout); } } } @@ -419,3 +406,7 @@ gboolean fl_keyboard_manager_is_state_clear(FlKeyboardManager* self) { return self->pending_responds->len == 0 && self->pending_redispatches->len == 0; } + +static void fl_key_event_destroy_notify(gpointer event) { + fl_key_event_dispose(reinterpret_cast(event)); +} diff --git a/shell/platform/linux/fl_keyboard_manager_test.cc b/shell/platform/linux/fl_keyboard_manager_test.cc index 6edfd7fbf91ef..86025dd259992 100644 --- a/shell/platform/linux/fl_keyboard_manager_test.cc +++ b/shell/platform/linux/fl_keyboard_manager_test.cc @@ -118,19 +118,25 @@ static void fl_key_mock_responder_iface_init(FlKeyResponderInterface* iface) { iface->handle_event = fl_key_mock_responder_handle_event; } +// Return a newly allocated #FlKeyEvent that is a clone to the given #event +// but with #origin and #dispose set to 0. +static FlKeyEvent* fl_key_event_clone_information_only(FlKeyEvent* event) { + FlKeyEvent* new_event = g_new(FlKeyEvent, 1); + *new_event = *event; + new_event->origin = nullptr; + new_event->dispose = nullptr; + return new_event; +} static void fl_key_mock_responder_handle_event( FlKeyResponder* responder, FlKeyEvent* event, FlKeyResponderAsyncCallback callback, gpointer user_data) { FlKeyMockResponder* self = FL_KEY_MOCK_RESPONDER(responder); - FlKeyEvent* new_event = g_new(FlKeyEvent, 1); - *new_event = *event; - new_event->origin = new_event; // Arbitrary value. - new_event->dispose = nullptr; g_ptr_array_add(self->call_records, FL_KEYBOARD_CALL_RECORD(fl_keyboard_call_record_new( - self, new_event, callback, user_data))); + self, fl_key_event_clone_information_only(event), + callback, user_data))); self->callback_handler(callback, user_data); } @@ -158,9 +164,13 @@ static gpointer g_ptr_array_last(GPtrArray* array) { return g_ptr_array_index(array, array->len - 1); } -static void fl_key_event_new_by_mock(FlKeyEvent* event) { +static void fl_key_event_free_by_mock(FlKeyEvent* event) { g_free(event->origin); } +// Create a new #FlKeyEvent with the given information. +// +// The #origin will be another #FlKeyEvent with the exact information, +// so that it can be used to redispatch, and is freed by #dispose. static FlKeyEvent* fl_key_event_new_by_mock(bool is_press, guint keyval, guint16 keycode, @@ -174,18 +184,15 @@ static FlKeyEvent* fl_key_event_new_by_mock(bool is_press, event->length = 0; event->string = nullptr; event->keycode = keycode; - FlKeyEvent* origin_event = g_new(FlKeyEvent, 1); - *origin_event = *event; - origin_event->origin = origin_event; // Arbitrary value. - origin_event->dispose = nullptr; + FlKeyEvent* origin_event = fl_key_event_clone_information_only(event); event->origin = origin_event; - event->dispose = fl_key_event_new_by_mock; + event->dispose = fl_key_event_free_by_mock; return event; } namespace { -// A global variable to store redispatched #FlKeyEvent. It is a global variable so -// that it can be used in a function without user_data. +// A global variable to store redispatched #FlKeyEvent. It is a global variable +// so that it can be used in a function without user_data. // // This array does not free elements upon removal. GPtrArray* _g_redispatched_events; @@ -210,31 +217,23 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { gboolean manager_handled = false; g_autoptr(FlKeyboardManager) manager = fl_keyboard_manager_new(nullptr, store_redispatched_event); - printf("x1\n"); - fflush(stdout); fl_keyboard_manager_add_responder( manager, FL_KEY_RESPONDER(fl_key_mock_responder_new(call_records, 1))); /// Test 1: One event that is handled by the framework // Dispatch a key event - printf("x2\n"); - fflush(stdout); manager_handled = fl_keyboard_manager_handle_event( manager, fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); EXPECT_EQ(manager_handled, true); EXPECT_EQ(redispatched_events()->len, 0u); EXPECT_EQ(call_records->len, 1u); - printf("x3\n"); - fflush(stdout); record = FL_KEYBOARD_CALL_RECORD(g_ptr_array_index(call_records, 0)); EXPECT_EQ(record->responder->delegate_id, 1); EXPECT_EQ(record->event->keyval, 0x61u); EXPECT_EQ(record->event->keycode, 0x26u); - printf("x4\n"); - fflush(stdout); record->callback(true, record->user_data); EXPECT_EQ(redispatched_events()->len, 0u); @@ -242,8 +241,6 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { g_ptr_array_clear(call_records); /// Test 2: Two events that are unhandled by the framework - printf("x5\n"); - fflush(stdout); manager_handled = fl_keyboard_manager_handle_event( manager, fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); @@ -256,7 +253,6 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { EXPECT_EQ(record->event->keycode, 0x26u); // Dispatch another key event - printf("x6\n"); manager_handled = fl_keyboard_manager_handle_event( manager, fl_key_event_new_by_mock(true, GDK_KEY_b, kKeyCodeKeyB, 0x10, false)); @@ -267,7 +263,6 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { EXPECT_EQ(record->responder->delegate_id, 1); EXPECT_EQ(record->event->keyval, 0x62u); EXPECT_EQ(record->event->keycode, 0x38u); - printf("x7\n");fflush(stdout); // Resolve the second event first to test out-of-order response record = FL_KEYBOARD_CALL_RECORD(g_ptr_array_index(call_records, 1)); @@ -284,11 +279,9 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { g_ptr_array_clear(call_records); // Resolve redispatches - printf("x8\n");fflush(stdout); manager_handled = fl_keyboard_manager_handle_event( manager, FL_KEY_EVENT(g_ptr_array_index(redispatched_events(), 0))); EXPECT_EQ(manager_handled, false); - printf("x8.1\n");fflush(stdout); manager_handled = fl_keyboard_manager_handle_event( manager, FL_KEY_EVENT(g_ptr_array_index(redispatched_events(), 1))); EXPECT_EQ(manager_handled, false); @@ -299,7 +292,6 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { /// Test 3: Dispatch the same event again to ensure that prevention from /// redispatching only works once. - printf("x9\n");fflush(stdout); manager_handled = fl_keyboard_manager_handle_event( manager, fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA, 0x10, false)); From 321e9f013a99f502dc47882d80f5bd59a03bcfc3 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Fri, 14 May 2021 02:26:09 -0700 Subject: [PATCH 078/126] Update licenses_flutter --- ci/licenses_golden/licenses_flutter | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 4e585efdb5492..a7dcf93135f56 100755 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1460,6 +1460,8 @@ FILE: ../../../flutter/shell/platform/linux/fl_key_embedder_responder.cc FILE: ../../../flutter/shell/platform/linux/fl_key_embedder_responder.h FILE: ../../../flutter/shell/platform/linux/fl_key_embedder_responder_private.h FILE: ../../../flutter/shell/platform/linux/fl_key_embedder_responder_test.cc +FILE: ../../../flutter/shell/platform/linux/fl_key_event.cc +FILE: ../../../flutter/shell/platform/linux/fl_key_event.h FILE: ../../../flutter/shell/platform/linux/fl_key_responder.cc FILE: ../../../flutter/shell/platform/linux/fl_key_responder.h FILE: ../../../flutter/shell/platform/linux/fl_keyboard_manager.cc From 41481dcf215a2edf13a126b6e806b679862117ed Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Fri, 14 May 2021 04:31:34 -0700 Subject: [PATCH 079/126] test text input plugin --- .../linux/fl_keyboard_manager_test.cc | 68 +++++++++++++++++++ .../linux/testing/mock_text_input_plugin.h | 9 ++- 2 files changed, 76 insertions(+), 1 deletion(-) diff --git a/shell/platform/linux/fl_keyboard_manager_test.cc b/shell/platform/linux/fl_keyboard_manager_test.cc index 86025dd259992..33afa1e79ba01 100644 --- a/shell/platform/linux/fl_keyboard_manager_test.cc +++ b/shell/platform/linux/fl_keyboard_manager_test.cc @@ -6,6 +6,7 @@ #include +#include "flutter/shell/platform/linux/testing/mock_text_input_plugin.h" #include "gtest/gtest.h" #define FL_KEY_EVENT(target) reinterpret_cast(target) @@ -100,6 +101,15 @@ static void respond_false(FlKeyResponderAsyncCallback callback, callback(false, user_data); } +static gboolean filter_keypress_returns_true(FlTextInputPlugin* self, FlKeyEvent* event) { + return TRUE; +} + +static gboolean filter_keypress_returns_false(FlTextInputPlugin* self, + FlKeyEvent* event) { + return FALSE; +} + static void fl_key_mock_responder_iface_init(FlKeyResponderInterface* iface); G_DEFINE_TYPE_WITH_CODE(FlKeyMockResponder, @@ -427,4 +437,62 @@ TEST(FlKeyboardManagerTest, WithTwoAsyncDelegates) { g_ptr_array_clear(redispatched_events()); } +TEST(FlKeyboardManagerTest, TextInputPluginReturnsFalse) { + GPtrArray* call_records = g_ptr_array_new_with_free_func(g_object_unref); + + gboolean manager_handled = false; + // The text input plugin doesn't handle events. + g_autoptr(FlMockTextInputPlugin) text_input_plugin = + fl_mock_text_input_plugin_new(filter_keypress_returns_false); + g_autoptr(FlKeyboardManager) manager = fl_keyboard_manager_new( + FL_TEXT_INPUT_PLUGIN(text_input_plugin), store_redispatched_event); + + // The responder never handles events. + FlKeyMockResponder* responder = fl_key_mock_responder_new(call_records, 1); + fl_keyboard_manager_add_responder(manager, FL_KEY_RESPONDER(responder)); + responder->callback_handler = respond_false; + + // Dispatch a key event. + manager_handled = fl_keyboard_manager_handle_event( + manager, + fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA, 0, false)); + EXPECT_EQ(manager_handled, true); + // The event was redispatched because no one handles it. + EXPECT_EQ(redispatched_events()->len, 1u); + + // Resolve redispatched event. + manager_handled = fl_keyboard_manager_handle_event( + manager, FL_KEY_EVENT(g_ptr_array_index(redispatched_events(), 0))); + EXPECT_EQ(manager_handled, false); + + g_ptr_array_clear(redispatched_events()); + EXPECT_TRUE(fl_keyboard_manager_is_state_clear(manager)); +} + +TEST(FlKeyboardManagerTest, TextInputPluginReturnsTrue) { + GPtrArray* call_records = g_ptr_array_new_with_free_func(g_object_unref); + + gboolean manager_handled = false; + // The text input plugin handles events. + g_autoptr(FlMockTextInputPlugin) text_input_plugin = + fl_mock_text_input_plugin_new(filter_keypress_returns_true); + g_autoptr(FlKeyboardManager) manager = fl_keyboard_manager_new( + FL_TEXT_INPUT_PLUGIN(text_input_plugin), store_redispatched_event); + + // The responder never handles events. + FlKeyMockResponder* responder = fl_key_mock_responder_new(call_records, 1); + fl_keyboard_manager_add_responder(manager, FL_KEY_RESPONDER(responder)); + responder->callback_handler = respond_false; + + // Dispatch a key event. + manager_handled = fl_keyboard_manager_handle_event( + manager, + fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA, 0, false)); + EXPECT_EQ(manager_handled, true); + // The event was not redispatched because text input plugin handles it. + EXPECT_EQ(redispatched_events()->len, 0u); + + EXPECT_TRUE(fl_keyboard_manager_is_state_clear(manager)); +} + } // namespace diff --git a/shell/platform/linux/testing/mock_text_input_plugin.h b/shell/platform/linux/testing/mock_text_input_plugin.h index 64b079e2c9d08..7d97f1ad88fb6 100644 --- a/shell/platform/linux/testing/mock_text_input_plugin.h +++ b/shell/platform/linux/testing/mock_text_input_plugin.h @@ -2,6 +2,11 @@ // 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_TESTING_MOCK_TEXT_INPUT_PLUGIN_H_ +#define FLUTTER_SHELL_PLATFORM_LINUX_TESTING_MOCK_TEXT_INPUT_PLUGIN_H_ + +#include + #include "flutter/shell/platform/linux/fl_text_input_plugin.h" G_BEGIN_DECLS @@ -13,6 +18,8 @@ G_DECLARE_FINAL_TYPE(FlMockTextInputPlugin, FlTextInputPlugin) FlMockTextInputPlugin* fl_mock_text_input_plugin_new( - gboolean (*filter_keypress)(FlTextInputPlugin* self, GdkEventKey* event)); + gboolean (*filter_keypress)(FlTextInputPlugin* self, FlKeyEvent* event)); G_END_DECLS + +#endif // FLUTTER_SHELL_PLATFORM_LINUX_TESTING_MOCK_TEXT_INPUT_PLUGIN_H_ From 7511427f4376ddb97797288ab63ac82bce739e75 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Fri, 14 May 2021 04:32:33 -0700 Subject: [PATCH 080/126] Format --- shell/platform/linux/fl_keyboard_manager_test.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shell/platform/linux/fl_keyboard_manager_test.cc b/shell/platform/linux/fl_keyboard_manager_test.cc index 33afa1e79ba01..010f025870110 100644 --- a/shell/platform/linux/fl_keyboard_manager_test.cc +++ b/shell/platform/linux/fl_keyboard_manager_test.cc @@ -101,7 +101,8 @@ static void respond_false(FlKeyResponderAsyncCallback callback, callback(false, user_data); } -static gboolean filter_keypress_returns_true(FlTextInputPlugin* self, FlKeyEvent* event) { +static gboolean filter_keypress_returns_true(FlTextInputPlugin* self, + FlKeyEvent* event) { return TRUE; } From 3ecc134bc68f96b01e2dd3fd921e4c4406db454f Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Fri, 14 May 2021 05:32:42 -0700 Subject: [PATCH 081/126] Fix test --- .../platform/linux/fl_key_embedder_responder_test.cc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index ff2898d1c18bc..6e514535a4973 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -868,9 +868,9 @@ TEST(FlKeyEmbedderResponderTest, IgnoreDuplicateDownEvent) { invoke_record_callback_and_verify(record, TRUE, &user_data); g_ptr_array_clear(g_call_records); - // Press KeyA again (with different logical key, not necessarily but for - // coverage). - g_expected_handled = true; + // Press KeyA again (with different logical key, which is not necessari but + // for coverage). + g_expected_handled = true; // The ignored event is always handled. fl_key_responder_handle_event( responder, fl_key_event_new_by_mock(102, kPress, GDK_KEY_q, kKeyCodeKeyA, 0, @@ -903,7 +903,7 @@ TEST(FlKeyEmbedderResponderTest, IgnoreAbruptUpEvent) { int user_data = 123; // Arbitrary user data // Release KeyA before it was even pressed. - g_expected_handled = true; + g_expected_handled = true; // The ignored event is always handled. fl_key_responder_handle_event( responder, fl_key_event_new_by_mock(103, kRelease, GDK_KEY_q, kKeyCodeKeyA, 0, @@ -1461,7 +1461,8 @@ TEST(FlKeyEmbedderResponderTest, SynthesizationOccursOnIgnoredEvents) { // The NumLock is desynchronized by being enabled, and Control is pressed. guint state = GDK_MOD2_MASK | GDK_CONTROL_MASK; - // Send a KeyA up event, which will be ignored + // Send a KeyA up event, which will be ignored. + g_expected_handled = true; // The ignored event is always handled. fl_key_responder_handle_event( responder, fl_key_event_new_by_mock(101, kRelease, GDK_KEY_a, kKeyCodeKeyA, state, From 76a166a753149b8025a13ae1cbb9f5e0ab160591 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Fri, 14 May 2021 17:36:46 -0700 Subject: [PATCH 082/126] Apply suggestions from code review Co-authored-by: Greg Spencer --- shell/platform/linux/fl_key_channel_responder.cc | 2 +- shell/platform/linux/fl_key_channel_responder_test.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/shell/platform/linux/fl_key_channel_responder.cc b/shell/platform/linux/fl_key_channel_responder.cc index 76c080e0d2c69..5039580212d44 100644 --- a/shell/platform/linux/fl_key_channel_responder.cc +++ b/shell/platform/linux/fl_key_channel_responder.cc @@ -175,7 +175,7 @@ static void fl_key_channel_responder_class_init( static void fl_key_channel_responder_init(FlKeyChannelResponder* self) {} // Creates a new FlKeyChannelResponder instance, with a messenger used to send -// messages to the framework, an FlTextInputPlugin used to handle key events +// messages to the framework, and an FlTextInputPlugin that is used to handle key events // that the framework doesn't handle. Mainly for testing purposes, it also takes // an optional callback to call when a response is received, and an optional // channel name to use when sending messages. diff --git a/shell/platform/linux/fl_key_channel_responder_test.cc b/shell/platform/linux/fl_key_channel_responder_test.cc index acfa8f904140a..0150fa43ab771 100644 --- a/shell/platform/linux/fl_key_channel_responder_test.cc +++ b/shell/platform/linux/fl_key_channel_responder_test.cc @@ -37,7 +37,7 @@ static int _origin_event; static FlKeyEvent _g_key_event; } // namespace -// Clone #string onto the heap. +// Clone string onto the heap. // // If #string is nullptr, returns nullptr. Otherwise, the returned pointer must // be freed with g_free. The #out_length must not be nullptr, and is used to From bdb678ae5b295e065d10f0325ad7858c17ac154d Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Fri, 14 May 2021 17:39:34 -0700 Subject: [PATCH 083/126] Review --- shell/platform/linux/fl_key_channel_responder.cc | 3 --- shell/platform/linux/fl_keyboard_manager.cc | 9 ++++----- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/shell/platform/linux/fl_key_channel_responder.cc b/shell/platform/linux/fl_key_channel_responder.cc index 5039580212d44..1cf2633ab409b 100644 --- a/shell/platform/linux/fl_key_channel_responder.cc +++ b/shell/platform/linux/fl_key_channel_responder.cc @@ -232,9 +232,6 @@ static void fl_key_channel_responder_handle_event( // does modifier key syncing in the framework, and will turn on/off these keys // as being "pressed" whenever the lock is on, which breaks a lot of // interactions (for example, if shift-lock is on, tab traversal is broken). - // - // TODO(gspencergoog): get rid of this tracked state when we are tracking the - // state of all keys and sending sync/cancel events when focus is gained/lost. // Remove lock states from state mask. guint state = event->state & ~(GDK_LOCK_MASK | GDK_MOD2_MASK); diff --git a/shell/platform/linux/fl_keyboard_manager.cc b/shell/platform/linux/fl_keyboard_manager.cc index d42118ac06fab..1d0c9c679433f 100644 --- a/shell/platform/linux/fl_keyboard_manager.cc +++ b/shell/platform/linux/fl_keyboard_manager.cc @@ -70,12 +70,11 @@ static uint64_t fl_keyboard_manager_get_event_hash(FlKeyEvent* event) { // (scan code) of the event to come up with a unique id for this event that // can be derived solely from the event data itself, so that we can identify // whether or not we have seen this event already. + guint64 type = static_cast(event->is_press ? GDK_KEY_PRESS : GDK_KEY_RELEASE); + guint64 keycode = static_cast(event->keycode); return (event->time & 0xffffffff) | - (static_cast(event->is_press ? GDK_KEY_PRESS - : GDK_KEY_RELEASE) & - 0xffff) - << 32 | - (static_cast(event->keycode) & 0xffff) << 48; + ((type & 0xffff) << 32) | + ((keycode & 0xffff) << 48); } // Create a new FlKeyboardPendingEvent by providing the target event, From c8140c55713ba41d91c9256bdb160c923bd1bc20 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Fri, 14 May 2021 17:40:45 -0700 Subject: [PATCH 084/126] Format --- shell/platform/linux/fl_key_channel_responder.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/shell/platform/linux/fl_key_channel_responder.cc b/shell/platform/linux/fl_key_channel_responder.cc index 5039580212d44..039873bbf284e 100644 --- a/shell/platform/linux/fl_key_channel_responder.cc +++ b/shell/platform/linux/fl_key_channel_responder.cc @@ -175,10 +175,10 @@ static void fl_key_channel_responder_class_init( static void fl_key_channel_responder_init(FlKeyChannelResponder* self) {} // Creates a new FlKeyChannelResponder instance, with a messenger used to send -// messages to the framework, and an FlTextInputPlugin that is used to handle key events -// that the framework doesn't handle. Mainly for testing purposes, it also takes -// an optional callback to call when a response is received, and an optional -// channel name to use when sending messages. +// messages to the framework, and an FlTextInputPlugin that is used to handle +// key events that the framework doesn't handle. Mainly for testing purposes, it +// also takes an optional callback to call when a response is received, and an +// optional channel name to use when sending messages. FlKeyChannelResponder* fl_key_channel_responder_new( FlBinaryMessenger* messenger, FlKeyChannelResponderMock* mock) { From 8ce3c694d97cf4d5b10556b4d42ad8d0b8cd28dc Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Fri, 14 May 2021 18:28:41 -0700 Subject: [PATCH 085/126] Use std::map for two maps --- .../linux/fl_key_embedder_responder.cc | 52 +- shell/platform/linux/key_mapping.cc | 984 +++++++++++------- shell/platform/linux/key_mapping.h | 11 +- 3 files changed, 598 insertions(+), 449 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index 5cb4b2bca61e4..225d376bcdf0f 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -28,15 +28,6 @@ static uint64_t lookup_hash_table(GHashTable* table, uint64_t key) { g_hash_table_lookup(table, uint64_to_gpointer(key))); } -static uint64_t event_to_physical_key(const FlKeyEvent* event, - GHashTable* table) { - uint64_t record = lookup_hash_table(table, event->keycode); - if (record != 0) { - return record; - } - return kGtkKeyIdPlane | event->keycode; -} - static uint64_t to_lower(uint64_t n) { constexpr uint64_t lower_a = 0x61; constexpr uint64_t upper_a = 0x41; @@ -169,18 +160,6 @@ struct _FlKeyEmbedderResponder { // For more information, see #update_caps_lock_state_logic_inferrence. StateLogicInferrence caps_lock_state_logic_inferrence; - // A static map from XKB code to Flutter's physical key code. - // - // Both keys and values are directly stored uint64s. This table is freed by - // the responder. - GHashTable* xkb_to_physical_key; - - // A static map from GTK keyval to Flutter's logical key code - // - // Both keys and values are directly stored uint64s. This table is freed by - // the responder. - GHashTable* keyval_to_logical_key; - // A static map from GTK modifier bits to #FlKeyEmbedderCheckedKey to // configure the modifier keys that needs to be tracked and kept synchronous // on. @@ -242,8 +221,6 @@ static void fl_key_embedder_responder_dispose(GObject* object) { FlKeyEmbedderResponder* self = FL_KEY_EMBEDDER_RESPONDER(object); g_clear_pointer(&self->pressing_records, g_hash_table_unref); - g_clear_pointer(&self->xkb_to_physical_key, g_hash_table_unref); - g_clear_pointer(&self->keyval_to_logical_key, g_hash_table_unref); g_clear_pointer(&self->modifier_bit_to_checked_keys, g_hash_table_unref); g_clear_pointer(&self->lock_bit_to_checked_keys, g_hash_table_unref); @@ -283,12 +260,6 @@ FlKeyEmbedderResponder* fl_key_embedder_responder_new(FlEngine* engine) { self->lock_records = 0; self->caps_lock_state_logic_inferrence = kStateLogicUndecided; - self->xkb_to_physical_key = g_hash_table_new(g_direct_hash, g_direct_equal); - initialize_xkb_to_physical_key(self->xkb_to_physical_key); - - self->keyval_to_logical_key = g_hash_table_new(g_direct_hash, g_direct_equal); - initialize_gtk_keyval_to_logical_key(self->keyval_to_logical_key); - self->modifier_bit_to_checked_keys = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free); initialize_modifier_bit_to_checked_keys(self->modifier_bit_to_checked_keys); @@ -308,12 +279,19 @@ FlKeyEmbedderResponder* fl_key_embedder_responder_new(FlEngine* engine) { /* Implement FlKeyEmbedderUserData */ -static uint64_t event_to_logical_key(const FlKeyEvent* event, - GHashTable* table) { +static uint64_t event_to_physical_key(const FlKeyEvent* event) { + auto found = xkb_to_physical_key_map[event->keycode]; + if (found != xkb_to_physical_key_map.end()) { + return found->second; + } + return kGtkKeyIdPlane | event->keycode; +} + +static uint64_t event_to_logical_key(const FlKeyEvent* event) { guint keyval = event->keyval; - uint64_t record = lookup_hash_table(table, keyval); - if (record != 0) { - return record; + auto found = gtk_keyval_to_logical_key_map[keyval]; + if (found != gtk_keyval_to_logical_key_map.end()) { + return found->second; } // EASCII range if (keyval < 256) { @@ -710,10 +688,8 @@ static void fl_key_embedder_responder_handle_event( g_return_if_fail(event != nullptr); g_return_if_fail(callback != nullptr); - const uint64_t physical_key = - event_to_physical_key(event, self->xkb_to_physical_key); - const uint64_t logical_key = - event_to_logical_key(event, self->keyval_to_logical_key); + const uint64_t physical_key = event_to_physical_key(event); + const uint64_t logical_key = event_to_logical_key(event); const double timestamp = event_to_timestamp(event); const bool is_down_event = event->is_press; diff --git a/shell/platform/linux/key_mapping.cc b/shell/platform/linux/key_mapping.cc index 4e4be1478206e..b1f0d1634cf9b 100644 --- a/shell/platform/linux/key_mapping.cc +++ b/shell/platform/linux/key_mapping.cc @@ -7,8 +7,6 @@ #include #include -#include "flutter/shell/platform/linux/fl_key_embedder_responder_private.h" - // DO NOT EDIT -- DO NOT EDIT -- DO NOT EDIT // This file is generated by // flutter/flutter@dev/tools/gen_keycodes/bin/gen_keycodes.dart and should not @@ -25,397 +23,573 @@ static bool insert_record(GHashTable* table, guint64 xkb, guint64 fl_key) { uint64_to_gpointer(fl_key)); } -void initialize_xkb_to_physical_key(GHashTable* table) { - insert_record(table, 0x00000009, 0x00070029); // escape - insert_record(table, 0x0000000a, 0x0007001e); // digit1 - insert_record(table, 0x0000000b, 0x0007001f); // digit2 - insert_record(table, 0x0000000c, 0x00070020); // digit3 - insert_record(table, 0x0000000d, 0x00070021); // digit4 - insert_record(table, 0x0000000e, 0x00070022); // digit5 - insert_record(table, 0x0000000f, 0x00070023); // digit6 - insert_record(table, 0x00000010, 0x00070024); // digit7 - insert_record(table, 0x00000011, 0x00070025); // digit8 - insert_record(table, 0x00000012, 0x00070026); // digit9 - insert_record(table, 0x00000013, 0x00070027); // digit0 - insert_record(table, 0x00000014, 0x0007002d); // minus - insert_record(table, 0x00000015, 0x0007002e); // equal - insert_record(table, 0x00000016, 0x0007002a); // backspace - insert_record(table, 0x00000017, 0x0007002b); // tab - insert_record(table, 0x00000018, 0x00070014); // keyQ - insert_record(table, 0x00000019, 0x0007001a); // keyW - insert_record(table, 0x0000001a, 0x00070008); // keyE - insert_record(table, 0x0000001b, 0x00070015); // keyR - insert_record(table, 0x0000001c, 0x00070017); // keyT - insert_record(table, 0x0000001d, 0x0007001c); // keyY - insert_record(table, 0x0000001e, 0x00070018); // keyU - insert_record(table, 0x0000001f, 0x0007000c); // keyI - insert_record(table, 0x00000020, 0x00070012); // keyO - insert_record(table, 0x00000021, 0x00070013); // keyP - insert_record(table, 0x00000022, 0x0007002f); // bracketLeft - insert_record(table, 0x00000023, 0x00070030); // bracketRight - insert_record(table, 0x00000024, 0x00070028); // enter - insert_record(table, 0x00000025, 0x000700e0); // controlLeft - insert_record(table, 0x00000026, 0x00070004); // keyA - insert_record(table, 0x00000027, 0x00070016); // keyS - insert_record(table, 0x00000028, 0x00070007); // keyD - insert_record(table, 0x00000029, 0x00070009); // keyF - insert_record(table, 0x0000002a, 0x0007000a); // keyG - insert_record(table, 0x0000002b, 0x0007000b); // keyH - insert_record(table, 0x0000002c, 0x0007000d); // keyJ - insert_record(table, 0x0000002d, 0x0007000e); // keyK - insert_record(table, 0x0000002e, 0x0007000f); // keyL - insert_record(table, 0x0000002f, 0x00070033); // semicolon - insert_record(table, 0x00000030, 0x00070034); // quote - insert_record(table, 0x00000031, 0x00070035); // backquote - insert_record(table, 0x00000032, 0x000700e1); // shiftLeft - insert_record(table, 0x00000033, 0x00070031); // backslash - insert_record(table, 0x00000034, 0x0007001d); // keyZ - insert_record(table, 0x00000035, 0x0007001b); // keyX - insert_record(table, 0x00000036, 0x00070006); // keyC - insert_record(table, 0x00000037, 0x00070019); // keyV - insert_record(table, 0x00000038, 0x00070005); // keyB - insert_record(table, 0x00000039, 0x00070011); // keyN - insert_record(table, 0x0000003a, 0x00070010); // keyM - insert_record(table, 0x0000003b, 0x00070036); // comma - insert_record(table, 0x0000003c, 0x00070037); // period - insert_record(table, 0x0000003d, 0x00070038); // slash - insert_record(table, 0x0000003e, 0x000700e5); // shiftRight - insert_record(table, 0x0000003f, 0x00070055); // numpadMultiply - insert_record(table, 0x00000040, 0x000700e2); // altLeft - insert_record(table, 0x00000041, 0x0007002c); // space - insert_record(table, 0x00000042, 0x00070039); // capsLock - insert_record(table, 0x00000043, 0x0007003a); // f1 - insert_record(table, 0x00000044, 0x0007003b); // f2 - insert_record(table, 0x00000045, 0x0007003c); // f3 - insert_record(table, 0x00000046, 0x0007003d); // f4 - insert_record(table, 0x00000047, 0x0007003e); // f5 - insert_record(table, 0x00000048, 0x0007003f); // f6 - insert_record(table, 0x00000049, 0x00070040); // f7 - insert_record(table, 0x0000004a, 0x00070041); // f8 - insert_record(table, 0x0000004b, 0x00070042); // f9 - insert_record(table, 0x0000004c, 0x00070043); // f10 - insert_record(table, 0x0000004d, 0x00070053); // numLock - insert_record(table, 0x0000004e, 0x00070047); // scrollLock - insert_record(table, 0x0000004f, 0x0007005f); // numpad7 - insert_record(table, 0x00000050, 0x00070060); // numpad8 - insert_record(table, 0x00000051, 0x00070061); // numpad9 - insert_record(table, 0x00000052, 0x00070056); // numpadSubtract - insert_record(table, 0x00000053, 0x0007005c); // numpad4 - insert_record(table, 0x00000054, 0x0007005d); // numpad5 - insert_record(table, 0x00000055, 0x0007005e); // numpad6 - insert_record(table, 0x00000056, 0x00070057); // numpadAdd - insert_record(table, 0x00000057, 0x00070059); // numpad1 - insert_record(table, 0x00000058, 0x0007005a); // numpad2 - insert_record(table, 0x00000059, 0x0007005b); // numpad3 - insert_record(table, 0x0000005a, 0x00070062); // numpad0 - insert_record(table, 0x0000005b, 0x00070063); // numpadDecimal - insert_record(table, 0x0000005d, 0x00070094); // lang5 - insert_record(table, 0x0000005e, 0x00070064); // intlBackslash - insert_record(table, 0x0000005f, 0x00070044); // f11 - insert_record(table, 0x00000060, 0x00070045); // f12 - insert_record(table, 0x00000061, 0x00070087); // intlRo - insert_record(table, 0x00000062, 0x00070092); // lang3 - insert_record(table, 0x00000063, 0x00070093); // lang4 - insert_record(table, 0x00000064, 0x0007008a); // convert - insert_record(table, 0x00000065, 0x00070088); // kanaMode - insert_record(table, 0x00000066, 0x0007008b); // nonConvert - insert_record(table, 0x00000068, 0x00070058); // numpadEnter - insert_record(table, 0x00000069, 0x000700e4); // controlRight - insert_record(table, 0x0000006a, 0x00070054); // numpadDivide - insert_record(table, 0x0000006b, 0x00070046); // printScreen - insert_record(table, 0x0000006c, 0x000700e6); // altRight - insert_record(table, 0x0000006e, 0x0007004a); // home - insert_record(table, 0x0000006f, 0x00070052); // arrowUp - insert_record(table, 0x00000070, 0x0007004b); // pageUp - insert_record(table, 0x00000071, 0x00070050); // arrowLeft - insert_record(table, 0x00000072, 0x0007004f); // arrowRight - insert_record(table, 0x00000073, 0x0007004d); // end - insert_record(table, 0x00000074, 0x00070051); // arrowDown - insert_record(table, 0x00000075, 0x0007004e); // pageDown - insert_record(table, 0x00000076, 0x00070049); // insert - insert_record(table, 0x00000077, 0x0007004c); // delete - insert_record(table, 0x00000079, 0x0007007f); // audioVolumeMute - insert_record(table, 0x0000007a, 0x00070081); // audioVolumeDown - insert_record(table, 0x0000007b, 0x00070080); // audioVolumeUp - insert_record(table, 0x0000007c, 0x00070066); // power - insert_record(table, 0x0000007d, 0x00070067); // numpadEqual - insert_record(table, 0x0000007e, 0x000700d7); // numpadSignChange - insert_record(table, 0x0000007f, 0x00070048); // pause - insert_record(table, 0x00000080, 0x000c029f); // showAllWindows - insert_record(table, 0x00000081, 0x00070085); // numpadComma - insert_record(table, 0x00000082, 0x00070090); // lang1 - insert_record(table, 0x00000083, 0x00070091); // lang2 - insert_record(table, 0x00000084, 0x00070089); // intlYen - insert_record(table, 0x00000085, 0x000700e3); // metaLeft - insert_record(table, 0x00000086, 0x000700e7); // metaRight - insert_record(table, 0x00000087, 0x00070065); // contextMenu - insert_record(table, 0x00000088, 0x000c0226); // browserStop - insert_record(table, 0x00000089, 0x00070079); // again - insert_record(table, 0x0000008b, 0x0007007a); // undo - insert_record(table, 0x0000008c, 0x00070077); // select - insert_record(table, 0x0000008d, 0x0007007c); // copy - insert_record(table, 0x0000008e, 0x00070074); // open - insert_record(table, 0x0000008f, 0x0007007d); // paste - insert_record(table, 0x00000090, 0x0007007e); // find - insert_record(table, 0x00000091, 0x0007007b); // cut - insert_record(table, 0x00000092, 0x00070075); // help - insert_record(table, 0x00000094, 0x000c0192); // launchApp2 - insert_record(table, 0x00000096, 0x00010082); // sleep - insert_record(table, 0x00000097, 0x00010083); // wakeUp - insert_record(table, 0x00000098, 0x000c0194); // launchApp1 - insert_record(table, 0x0000009e, 0x000c0196); // launchInternetBrowser - insert_record(table, 0x000000a0, 0x000c019e); // lockScreen - insert_record(table, 0x000000a3, 0x000c018a); // launchMail - insert_record(table, 0x000000a4, 0x000c022a); // browserFavorites - insert_record(table, 0x000000a6, 0x000c0224); // browserBack - insert_record(table, 0x000000a7, 0x000c0225); // browserForward - insert_record(table, 0x000000a9, 0x000c00b8); // eject - insert_record(table, 0x000000ab, 0x000c00b5); // mediaTrackNext - insert_record(table, 0x000000ac, 0x000c00cd); // mediaPlayPause - insert_record(table, 0x000000ad, 0x000c00b6); // mediaTrackPrevious - insert_record(table, 0x000000ae, 0x000c00b7); // mediaStop - insert_record(table, 0x000000af, 0x000c00b2); // mediaRecord - insert_record(table, 0x000000b0, 0x000c00b4); // mediaRewind - insert_record(table, 0x000000b1, 0x000c008c); // launchPhone - insert_record(table, 0x000000b3, 0x000c0183); // mediaSelect - insert_record(table, 0x000000b4, 0x000c0223); // browserHome - insert_record(table, 0x000000b5, 0x000c0227); // browserRefresh - insert_record(table, 0x000000b6, 0x000c0094); // exit - insert_record(table, 0x000000bb, 0x000700b6); // numpadParenLeft - insert_record(table, 0x000000bc, 0x000700b7); // numpadParenRight - insert_record(table, 0x000000bd, 0x000c0201); // newKey - insert_record(table, 0x000000be, 0x000c0279); // redo - insert_record(table, 0x000000bf, 0x00070068); // f13 - insert_record(table, 0x000000c0, 0x00070069); // f14 - insert_record(table, 0x000000c1, 0x0007006a); // f15 - insert_record(table, 0x000000c2, 0x0007006b); // f16 - insert_record(table, 0x000000c3, 0x0007006c); // f17 - insert_record(table, 0x000000c4, 0x0007006d); // f18 - insert_record(table, 0x000000c5, 0x0007006e); // f19 - insert_record(table, 0x000000c6, 0x0007006f); // f20 - insert_record(table, 0x000000c7, 0x00070070); // f21 - insert_record(table, 0x000000c8, 0x00070071); // f22 - insert_record(table, 0x000000c9, 0x00070072); // f23 - insert_record(table, 0x000000ca, 0x00070073); // f24 - insert_record(table, 0x000000d1, 0x000c00b1); // mediaPause - insert_record(table, 0x000000d6, 0x000c0203); // close - insert_record(table, 0x000000d7, 0x000c00b0); // mediaPlay - insert_record(table, 0x000000d8, 0x000c00b3); // mediaFastForward - insert_record(table, 0x000000d9, 0x000c00e5); // bassBoost - insert_record(table, 0x000000da, 0x000c0208); // print - insert_record(table, 0x000000e1, 0x000c0221); // browserSearch - insert_record(table, 0x000000e8, 0x000c0070); // brightnessDown - insert_record(table, 0x000000e9, 0x000c006f); // brightnessUp - insert_record(table, 0x000000eb, 0x000100b5); // displayToggleIntExt - insert_record(table, 0x000000ed, 0x000c007a); // kbdIllumDown - insert_record(table, 0x000000ee, 0x000c0079); // kbdIllumUp - insert_record(table, 0x000000ef, 0x000c028c); // mailSend - insert_record(table, 0x000000f0, 0x000c0289); // mailReply - insert_record(table, 0x000000f1, 0x000c028b); // mailForward - insert_record(table, 0x000000f2, 0x000c0207); // save - insert_record(table, 0x000000f3, 0x000c01a7); // launchDocuments - insert_record(table, 0x000000fc, 0x000c0075); // brightnessAuto - insert_record(table, 0x0000016e, 0x000c0060); // info - insert_record(table, 0x00000172, 0x000c008d); // programGuide - insert_record(table, 0x0000017a, 0x000c0061); // closedCaptionToggle - insert_record(table, 0x0000017c, 0x000c0232); // zoomToggle - insert_record(table, 0x0000017e, 0x000c01ae); // launchKeyboardLayout - insert_record(table, 0x00000190, 0x000c01b7); // launchAudioBrowser - insert_record(table, 0x00000195, 0x000c018e); // launchCalendar - insert_record(table, 0x0000019d, 0x000c0083); // mediaLast - insert_record(table, 0x000001a2, 0x000c009c); // channelUp - insert_record(table, 0x000001a3, 0x000c009d); // channelDown - insert_record(table, 0x000001aa, 0x000c022d); // zoomIn - insert_record(table, 0x000001ab, 0x000c022e); // zoomOut - insert_record(table, 0x000001ad, 0x000c0184); // launchWordProcessor - insert_record(table, 0x000001af, 0x000c0186); // launchSpreadsheet - insert_record(table, 0x000001b5, 0x000c018d); // launchContacts - insert_record(table, 0x000001b7, 0x000c0072); // brightnessToggle - insert_record(table, 0x000001b8, 0x000c01ab); // spellCheck - insert_record(table, 0x000001b9, 0x000c019c); // logOff - insert_record(table, 0x0000024b, 0x000c019f); // launchControlPanel - insert_record(table, 0x0000024c, 0x000c01a2); // selectTask - insert_record(table, 0x0000024d, 0x000c01b1); // launchScreenSaver - insert_record(table, 0x0000024e, 0x000c00cf); // speechInputToggle - insert_record(table, 0x0000024f, 0x000c01cb); // launchAssistant - insert_record(table, 0x00000250, 0x000c029d); // keyboardLayoutSelect - insert_record(table, 0x00000258, 0x000c0073); // brightnessMinimum - insert_record(table, 0x00000259, 0x000c0074); // brightnessMaximum - insert_record(table, 0x00000281, 0x00000017); // privacyScreenToggle -} +std::map xkb_to_physical_key_map = + { + {0x00000009, 0x00070029}, // escape + {0x0000000a, 0x0007001e}, // digit1 + {0x0000000b, 0x0007001f}, // digit2 + {0x0000000c, 0x00070020}, // digit3 + {0x0000000d, 0x00070021}, // digit4 + {0x0000000e, 0x00070022}, // digit5 + {0x0000000f, 0x00070023}, // digit6 + {0x00000010, 0x00070024}, // digit7 + {0x00000011, 0x00070025}, // digit8 + {0x00000012, 0x00070026}, // digit9 + {0x00000013, 0x00070027}, // digit0 + {0x00000014, 0x0007002d}, // minus + {0x00000015, 0x0007002e}, // equal + {0x00000016, 0x0007002a}, // backspace + {0x00000017, 0x0007002b}, // tab + {0x00000018, 0x00070014}, // keyQ + {0x00000019, 0x0007001a}, // keyW + {0x0000001a, 0x00070008}, // keyE + {0x0000001b, 0x00070015}, // keyR + {0x0000001c, 0x00070017}, // keyT + {0x0000001d, 0x0007001c}, // keyY + {0x0000001e, 0x00070018}, // keyU + {0x0000001f, 0x0007000c}, // keyI + {0x00000020, 0x00070012}, // keyO + {0x00000021, 0x00070013}, // keyP + {0x00000022, 0x0007002f}, // bracketLeft + {0x00000023, 0x00070030}, // bracketRight + {0x00000024, 0x00070028}, // enter + {0x00000025, 0x000700e0}, // controlLeft + {0x00000026, 0x00070004}, // keyA + {0x00000027, 0x00070016}, // keyS + {0x00000028, 0x00070007}, // keyD + {0x00000029, 0x00070009}, // keyF + {0x0000002a, 0x0007000a}, // keyG + {0x0000002b, 0x0007000b}, // keyH + {0x0000002c, 0x0007000d}, // keyJ + {0x0000002d, 0x0007000e}, // keyK + {0x0000002e, 0x0007000f}, // keyL + {0x0000002f, 0x00070033}, // semicolon + {0x00000030, 0x00070034}, // quote + {0x00000031, 0x00070035}, // backquote + {0x00000032, 0x000700e1}, // shiftLeft + {0x00000033, 0x00070031}, // backslash + {0x00000034, 0x0007001d}, // keyZ + {0x00000035, 0x0007001b}, // keyX + {0x00000036, 0x00070006}, // keyC + {0x00000037, 0x00070019}, // keyV + {0x00000038, 0x00070005}, // keyB + {0x00000039, 0x00070011}, // keyN + {0x0000003a, 0x00070010}, // keyM + {0x0000003b, 0x00070036}, // comma + {0x0000003c, 0x00070037}, // period + {0x0000003d, 0x00070038}, // slash + {0x0000003e, 0x000700e5}, // shiftRight + {0x0000003f, 0x00070055}, // numpadMultiply + {0x00000040, 0x000700e2}, // altLeft + {0x00000041, 0x0007002c}, // space + {0x00000042, 0x00070039}, // capsLock + {0x00000043, 0x0007003a}, // f1 + {0x00000044, 0x0007003b}, // f2 + {0x00000045, 0x0007003c}, // f3 + {0x00000046, 0x0007003d}, // f4 + {0x00000047, 0x0007003e}, // f5 + {0x00000048, 0x0007003f}, // f6 + {0x00000049, 0x00070040}, // f7 + {0x0000004a, 0x00070041}, // f8 + {0x0000004b, 0x00070042}, // f9 + {0x0000004c, 0x00070043}, // f10 + {0x0000004d, 0x00070053}, // numLock + {0x0000004e, 0x00070047}, // scrollLock + {0x0000004f, 0x0007005f}, // numpad7 + {0x00000050, 0x00070060}, // numpad8 + {0x00000051, 0x00070061}, // numpad9 + {0x00000052, 0x00070056}, // numpadSubtract + {0x00000053, 0x0007005c}, // numpad4 + {0x00000054, 0x0007005d}, // numpad5 + {0x00000055, 0x0007005e}, // numpad6 + {0x00000056, 0x00070057}, // numpadAdd + {0x00000057, 0x00070059}, // numpad1 + {0x00000058, 0x0007005a}, // numpad2 + {0x00000059, 0x0007005b}, // numpad3 + {0x0000005a, 0x00070062}, // numpad0 + {0x0000005b, 0x00070063}, // numpadDecimal + {0x0000005d, 0x00070094}, // lang5 + {0x0000005e, 0x00070064}, // intlBackslash + {0x0000005f, 0x00070044}, // f11 + {0x00000060, 0x00070045}, // f12 + {0x00000061, 0x00070087}, // intlRo + {0x00000062, 0x00070092}, // lang3 + {0x00000063, 0x00070093}, // lang4 + {0x00000064, 0x0007008a}, // convert + {0x00000065, 0x00070088}, // kanaMode + {0x00000066, 0x0007008b}, // nonConvert + {0x00000068, 0x00070058}, // numpadEnter + {0x00000069, 0x000700e4}, // controlRight + {0x0000006a, 0x00070054}, // numpadDivide + {0x0000006b, 0x00070046}, // printScreen + {0x0000006c, 0x000700e6}, // altRight + {0x0000006e, 0x0007004a}, // home + {0x0000006f, 0x00070052}, // arrowUp + {0x00000070, 0x0007004b}, // pageUp + {0x00000071, 0x00070050}, // arrowLeft + {0x00000072, 0x0007004f}, // arrowRight + {0x00000073, 0x0007004d}, // end + {0x00000074, 0x00070051}, // arrowDown + {0x00000075, 0x0007004e}, // pageDown + {0x00000076, 0x00070049}, // insert + {0x00000077, 0x0007004c}, // delete + {0x00000079, 0x0007007f}, // audioVolumeMute + {0x0000007a, 0x00070081}, // audioVolumeDown + {0x0000007b, 0x00070080}, // audioVolumeUp + {0x0000007c, 0x00070066}, // power + {0x0000007d, 0x00070067}, // numpadEqual + {0x0000007e, 0x000700d7}, // numpadSignChange + {0x0000007f, 0x00070048}, // pause + {0x00000080, 0x000c029f}, // showAllWindows + {0x00000081, 0x00070085}, // numpadComma + {0x00000082, 0x00070090}, // lang1 + {0x00000083, 0x00070091}, // lang2 + {0x00000084, 0x00070089}, // intlYen + {0x00000085, 0x000700e3}, // metaLeft + {0x00000086, 0x000700e7}, // metaRight + {0x00000087, 0x00070065}, // contextMenu + {0x00000088, 0x000c0226}, // browserStop + {0x00000089, 0x00070079}, // again + {0x0000008b, 0x0007007a}, // undo + {0x0000008c, 0x00070077}, // select + {0x0000008d, 0x0007007c}, // copy + {0x0000008e, 0x00070074}, // open + {0x0000008f, 0x0007007d}, // paste + {0x00000090, 0x0007007e}, // find + {0x00000091, 0x0007007b}, // cut + {0x00000092, 0x00070075}, // help + {0x00000094, 0x000c0192}, // launchApp2 + {0x00000096, 0x00010082}, // sleep + {0x00000097, 0x00010083}, // wakeUp + {0x00000098, 0x000c0194}, // launchApp1 + {0x0000009e, 0x000c0196}, // launchInternetBrowser + {0x000000a0, 0x000c019e}, // lockScreen + {0x000000a3, 0x000c018a}, // launchMail + {0x000000a4, 0x000c022a}, // browserFavorites + {0x000000a6, 0x000c0224}, // browserBack + {0x000000a7, 0x000c0225}, // browserForward + {0x000000a9, 0x000c00b8}, // eject + {0x000000ab, 0x000c00b5}, // mediaTrackNext + {0x000000ac, 0x000c00cd}, // mediaPlayPause + {0x000000ad, 0x000c00b6}, // mediaTrackPrevious + {0x000000ae, 0x000c00b7}, // mediaStop + {0x000000af, 0x000c00b2}, // mediaRecord + {0x000000b0, 0x000c00b4}, // mediaRewind + {0x000000b1, 0x000c008c}, // launchPhone + {0x000000b3, 0x000c0183}, // mediaSelect + {0x000000b4, 0x000c0223}, // browserHome + {0x000000b5, 0x000c0227}, // browserRefresh + {0x000000b6, 0x000c0094}, // exit + {0x000000bb, 0x000700b6}, // numpadParenLeft + {0x000000bc, 0x000700b7}, // numpadParenRight + {0x000000bd, 0x000c0201}, // newKey + {0x000000be, 0x000c0279}, // redo + {0x000000bf, 0x00070068}, // f13 + {0x000000c0, 0x00070069}, // f14 + {0x000000c1, 0x0007006a}, // f15 + {0x000000c2, 0x0007006b}, // f16 + {0x000000c3, 0x0007006c}, // f17 + {0x000000c4, 0x0007006d}, // f18 + {0x000000c5, 0x0007006e}, // f19 + {0x000000c6, 0x0007006f}, // f20 + {0x000000c7, 0x00070070}, // f21 + {0x000000c8, 0x00070071}, // f22 + {0x000000c9, 0x00070072}, // f23 + {0x000000ca, 0x00070073}, // f24 + {0x000000d1, 0x000c00b1}, // mediaPause + {0x000000d6, 0x000c0203}, // close + {0x000000d7, 0x000c00b0}, // mediaPlay + {0x000000d8, 0x000c00b3}, // mediaFastForward + {0x000000d9, 0x000c00e5}, // bassBoost + {0x000000da, 0x000c0208}, // print + {0x000000e1, 0x000c0221}, // browserSearch + {0x000000e8, 0x000c0070}, // brightnessDown + {0x000000e9, 0x000c006f}, // brightnessUp + {0x000000eb, 0x000100b5}, // displayToggleIntExt + {0x000000ed, 0x000c007a}, // kbdIllumDown + {0x000000ee, 0x000c0079}, // kbdIllumUp + {0x000000ef, 0x000c028c}, // mailSend + {0x000000f0, 0x000c0289}, // mailReply + {0x000000f1, 0x000c028b}, // mailForward + {0x000000f2, 0x000c0207}, // save + {0x000000f3, 0x000c01a7}, // launchDocuments + {0x000000fc, 0x000c0075}, // brightnessAuto + {0x0000016e, 0x000c0060}, // info + {0x00000172, 0x000c008d}, // programGuide + {0x0000017a, 0x000c0061}, // closedCaptionToggle + {0x0000017c, 0x000c0232}, // zoomToggle + {0x0000017e, 0x000c01ae}, // launchKeyboardLayout + {0x00000190, 0x000c01b7}, // launchAudioBrowser + {0x00000195, 0x000c018e}, // launchCalendar + {0x0000019d, 0x000c0083}, // mediaLast + {0x000001a2, 0x000c009c}, // channelUp + {0x000001a3, 0x000c009d}, // channelDown + {0x000001aa, 0x000c022d}, // zoomIn + {0x000001ab, 0x000c022e}, // zoomOut + {0x000001ad, 0x000c0184}, // launchWordProcessor + {0x000001af, 0x000c0186}, // launchSpreadsheet + {0x000001b5, 0x000c018d}, // launchContacts + {0x000001b7, 0x000c0072}, // brightnessToggle + {0x000001b8, 0x000c01ab}, // spellCheck + {0x000001b9, 0x000c019c}, // logOff + {0x0000024b, 0x000c019f}, // launchControlPanel + {0x0000024c, 0x000c01a2}, // selectTask + {0x0000024d, 0x000c01b1}, // launchScreenSaver + {0x0000024e, 0x000c00cf}, // speechInputToggle + {0x0000024f, 0x000c01cb}, // launchAssistant + {0x00000250, 0x000c029d}, // keyboardLayoutSelect + {0x00000258, 0x000c0073}, // brightnessMinimum + {0x00000259, 0x000c0074}, // brightnessMaximum + {0x00000281, 0x00000017}, // privacyScreenToggle + } + +std::map gtk_keyval_to_logical_key_map = + { + {0x000000a5, 0x01100070089}, // yen + {0x0000fd06, 0x01000000405}, // 3270_EraseEOF + {0x0000fd0e, 0x01000000503}, // 3270_Attn + {0x0000fd15, 0x01000000402}, // 3270_Copy + {0x0000fd16, 0x01000000d2f}, // 3270_Play + {0x0000fd1b, 0x01000000406}, // 3270_ExSelect + {0x0000fd1d, 0x01000000608}, // 3270_PrintScreen + {0x0000fd1e, 0x0100000000d}, // 3270_Enter + {0x0000fe03, 0x40000000102}, // ISO_Level3_Shift + {0x0000fe08, 0x01000000709}, // ISO_Next_Group + {0x0000fe0a, 0x0100000070a}, // ISO_Prev_Group + {0x0000fe0c, 0x01000000707}, // ISO_First_Group + {0x0000fe0e, 0x01000000708}, // ISO_Last_Group + {0x0000fe20, 0x01000000009}, // ISO_Left_Tab + {0x0000fe34, 0x0100000000d}, // ISO_Enter + {0x0000ff08, 0x01000000008}, // BackSpace + {0x0000ff09, 0x01000000009}, // Tab + {0x0000ff0b, 0x01000000401}, // Clear + {0x0000ff0d, 0x0100000000d}, // Return + {0x0000ff13, 0x01000000509}, // Pause + {0x0000ff14, 0x0100000010c}, // Scroll_Lock + {0x0000ff1b, 0x0100000001b}, // Escape + {0x0000ff21, 0x01000000719}, // Kanji + {0x0000ff24, 0x0100000071b}, // Romaji + {0x0000ff25, 0x01000000716}, // Hiragana + {0x0000ff26, 0x0100000071a}, // Katakana + {0x0000ff27, 0x01000000717}, // Hiragana_Katakana + {0x0000ff28, 0x0100000071c}, // Zenkaku + {0x0000ff29, 0x01000000715}, // Hankaku + {0x0000ff2a, 0x0100000071d}, // Zenkaku_Hankaku + {0x0000ff2f, 0x01000000714}, // Eisu_Shift + {0x0000ff31, 0x01000000711}, // Hangul + {0x0000ff34, 0x01000000712}, // Hangul_Hanja + {0x0000ff37, 0x01000000703}, // Codeinput + {0x0000ff3c, 0x01000000710}, // SingleCandidate + {0x0000ff3e, 0x0100000070e}, // PreviousCandidate + {0x0000ff50, 0x01000000306}, // Home + {0x0000ff51, 0x01000000302}, // Left + {0x0000ff52, 0x01000000304}, // Up + {0x0000ff53, 0x01000000303}, // Right + {0x0000ff54, 0x01000000301}, // Down + {0x0000ff55, 0x01000000308}, // Page_Up + {0x0000ff56, 0x01000000307}, // Page_Down + {0x0000ff57, 0x01000000305}, // End + {0x0000ff60, 0x0100000050c}, // Select + {0x0000ff61, 0x01000000a0c}, // Print + {0x0000ff62, 0x01000000506}, // Execute + {0x0000ff63, 0x01000000407}, // Insert + {0x0000ff65, 0x0100000040a}, // Undo + {0x0000ff66, 0x01000000409}, // Redo + {0x0000ff67, 0x01000000505}, // Menu + {0x0000ff68, 0x01000000507}, // Find + {0x0000ff69, 0x01000000504}, // Cancel + {0x0000ff6a, 0x01000000508}, // Help + {0x0000ff7e, 0x0100000070b}, // Mode_switch + {0x0000ff7f, 0x0100000010a}, // Num_Lock + {0x0000ff80, 0x00000000020}, // KP_Space + {0x0000ff89, 0x01000000009}, // KP_Tab + {0x0000ff8d, 0x5000000000d}, // KP_Enter + {0x0000ff91, 0x01000000801}, // KP_F1 + {0x0000ff92, 0x01000000802}, // KP_F2 + {0x0000ff93, 0x01000000803}, // KP_F3 + {0x0000ff94, 0x01000000804}, // KP_F4 + {0x0000ff95, 0x50000000037}, // KP_Home + {0x0000ff96, 0x50000000034}, // KP_Left + {0x0000ff97, 0x50000000038}, // KP_Up + {0x0000ff98, 0x50000000036}, // KP_Right + {0x0000ff99, 0x50000000032}, // KP_Down + {0x0000ff9a, 0x50000000039}, // KP_Page_Up + {0x0000ff9b, 0x50000000033}, // KP_Page_Down + {0x0000ff9c, 0x50000000031}, // KP_End + {0x0000ff9e, 0x50000000030}, // KP_Insert + {0x0000ff9f, 0x5000000002e}, // KP_Delete + {0x0000ffaa, 0x5000000002a}, // KP_Multiply + {0x0000ffab, 0x5000000002b}, // KP_Add + {0x0000ffad, 0x5000000002d}, // KP_Subtract + {0x0000ffae, 0x0000000002e}, // KP_Decimal + {0x0000ffaf, 0x5000000002f}, // KP_Divide + {0x0000ffb0, 0x50000000030}, // KP_0 + {0x0000ffb1, 0x50000000031}, // KP_1 + {0x0000ffb2, 0x50000000032}, // KP_2 + {0x0000ffb3, 0x50000000033}, // KP_3 + {0x0000ffb4, 0x50000000034}, // KP_4 + {0x0000ffb5, 0x50000000035}, // KP_5 + {0x0000ffb6, 0x50000000036}, // KP_6 + {0x0000ffb7, 0x50000000037}, // KP_7 + {0x0000ffb8, 0x50000000038}, // KP_8 + {0x0000ffb9, 0x50000000039}, // KP_9 + {0x0000ffbd, 0x5000000003d}, // KP_Equal + {0x0000ffbe, 0x01000000801}, // F1 + {0x0000ffbf, 0x01000000802}, // F2 + {0x0000ffc0, 0x01000000803}, // F3 + {0x0000ffc1, 0x01000000804}, // F4 + {0x0000ffc2, 0x01000000805}, // F5 + {0x0000ffc3, 0x01000000806}, // F6 + {0x0000ffc4, 0x01000000807}, // F7 + {0x0000ffc5, 0x01000000808}, // F8 + {0x0000ffc6, 0x01000000809}, // F9 + {0x0000ffc7, 0x0100000080a}, // F10 + {0x0000ffc8, 0x0100000080b}, // F11 + {0x0000ffc9, 0x0100000080c}, // F12 + {0x0000ffca, 0x0100000080d}, // F13 + {0x0000ffcb, 0x0100000080e}, // F14 + {0x0000ffcc, 0x0100000080f}, // F15 + {0x0000ffcd, 0x01000000810}, // F16 + {0x0000ffce, 0x01000000811}, // F17 + {0x0000ffcf, 0x01000000812}, // F18 + {0x0000ffd0, 0x01000000813}, // F19 + {0x0000ffd1, 0x01000000814}, // F20 + {0x0000ffd2, 0x01000000815}, // F21 + {0x0000ffd3, 0x01000000816}, // F22 + {0x0000ffd4, 0x01000000817}, // F23 + {0x0000ffd5, 0x01000000818}, // F24 + {0x0000ffe1, 0x3000000010d}, // Shift_L + {0x0000ffe2, 0x4000000010d}, // Shift_R + {0x0000ffe3, 0x30000000105}, // Control_L + {0x0000ffe4, 0x40000000105}, // Control_R + {0x0000ffe5, 0x01000000104}, // Caps_Lock + {0x0000ffe7, 0x30000000109}, // Meta_L + {0x0000ffe8, 0x40000000109}, // Meta_R + {0x0000ffe9, 0x30000000102}, // Alt_L + {0x0000ffea, 0x40000000102}, // Alt_R + {0x0000ffeb, 0x0100000010e}, // Super_L + {0x0000ffec, 0x0100000010e}, // Super_R + {0x0000ffed, 0x01000000108}, // Hyper_L + {0x0000ffee, 0x01000000108}, // Hyper_R + {0x0000ffff, 0x0100000007f}, // Delete + {0x1008ff02, 0x01000000602}, // MonBrightnessUp + {0x1008ff03, 0x01000000601}, // MonBrightnessDown + {0x1008ff10, 0x0100000060a}, // Standby + {0x1008ff11, 0x01000000a0f}, // AudioLowerVolume + {0x1008ff12, 0x01000000a11}, // AudioMute + {0x1008ff13, 0x01000000a10}, // AudioRaiseVolume + {0x1008ff14, 0x01000000d2f}, // AudioPlay + {0x1008ff15, 0x01000000a07}, // AudioStop + {0x1008ff16, 0x01000000a09}, // AudioPrev + {0x1008ff17, 0x01000000a08}, // AudioNext + {0x1008ff18, 0x01000000c04}, // HomePage + {0x1008ff19, 0x01000000b03}, // Mail + {0x1008ff1b, 0x01000000c06}, // Search + {0x1008ff1c, 0x01000000d30}, // AudioRecord + {0x1008ff20, 0x01000000b02}, // Calendar + {0x1008ff26, 0x01000000c01}, // Back + {0x1008ff27, 0x01000000c03}, // Forward + {0x1008ff28, 0x01000000c07}, // Stop + {0x1008ff29, 0x01000000c05}, // Refresh + {0x1008ff2a, 0x01000000607}, // PowerOff + {0x1008ff2b, 0x0100000060b}, // WakeUp + {0x1008ff2c, 0x01000000604}, // Eject + {0x1008ff2d, 0x01000000b07}, // ScreenSaver + {0x1008ff2f, 0x01100010082}, // Sleep + {0x1008ff30, 0x01000000c02}, // Favorites + {0x1008ff31, 0x01000000d2e}, // AudioPause + {0x1008ff3e, 0x01000000d31}, // AudioRewind + {0x1008ff56, 0x01000000a01}, // Close + {0x1008ff57, 0x01000000402}, // Copy + {0x1008ff58, 0x01000000404}, // Cut + {0x1008ff61, 0x01000000605}, // LogOff + {0x1008ff68, 0x01000000a0a}, // New + {0x1008ff6b, 0x01000000a0b}, // Open + {0x1008ff6d, 0x01000000408}, // Paste + {0x1008ff6e, 0x01000000b0d}, // Phone + {0x1008ff72, 0x01000000a03}, // Reply + {0x1008ff77, 0x01000000a0d}, // Save + {0x1008ff7b, 0x01000000a04}, // Send + {0x1008ff7c, 0x01000000a0e}, // Spell + {0x1008ff8b, 0x0100000050d}, // ZoomIn + {0x1008ff8c, 0x0100000050e}, // ZoomOut + {0x1008ff90, 0x01000000a02}, // MailForward + {0x1008ff97, 0x01000000d2c}, // AudioForward + {0x1008ffa7, 0x01100000014}, // Suspend + } void initialize_gtk_keyval_to_logical_key(GHashTable* table) { - insert_record(table, 0x000000a5, 0x01100070089); // yen - insert_record(table, 0x0000fd06, 0x01000000405); // 3270_EraseEOF - insert_record(table, 0x0000fd0e, 0x01000000503); // 3270_Attn - insert_record(table, 0x0000fd15, 0x01000000402); // 3270_Copy - insert_record(table, 0x0000fd16, 0x01000000d2f); // 3270_Play - insert_record(table, 0x0000fd1b, 0x01000000406); // 3270_ExSelect - insert_record(table, 0x0000fd1d, 0x01000000608); // 3270_PrintScreen - insert_record(table, 0x0000fd1e, 0x0100000000d); // 3270_Enter - insert_record(table, 0x0000fe03, 0x40000000102); // ISO_Level3_Shift - insert_record(table, 0x0000fe08, 0x01000000709); // ISO_Next_Group - insert_record(table, 0x0000fe0a, 0x0100000070a); // ISO_Prev_Group - insert_record(table, 0x0000fe0c, 0x01000000707); // ISO_First_Group - insert_record(table, 0x0000fe0e, 0x01000000708); // ISO_Last_Group - insert_record(table, 0x0000fe20, 0x01000000009); // ISO_Left_Tab - insert_record(table, 0x0000fe34, 0x0100000000d); // ISO_Enter - insert_record(table, 0x0000ff08, 0x01000000008); // BackSpace - insert_record(table, 0x0000ff09, 0x01000000009); // Tab - insert_record(table, 0x0000ff0b, 0x01000000401); // Clear - insert_record(table, 0x0000ff0d, 0x0100000000d); // Return - insert_record(table, 0x0000ff13, 0x01000000509); // Pause - insert_record(table, 0x0000ff14, 0x0100000010c); // Scroll_Lock - insert_record(table, 0x0000ff1b, 0x0100000001b); // Escape - insert_record(table, 0x0000ff21, 0x01000000719); // Kanji - insert_record(table, 0x0000ff24, 0x0100000071b); // Romaji - insert_record(table, 0x0000ff25, 0x01000000716); // Hiragana - insert_record(table, 0x0000ff26, 0x0100000071a); // Katakana - insert_record(table, 0x0000ff27, 0x01000000717); // Hiragana_Katakana - insert_record(table, 0x0000ff28, 0x0100000071c); // Zenkaku - insert_record(table, 0x0000ff29, 0x01000000715); // Hankaku - insert_record(table, 0x0000ff2a, 0x0100000071d); // Zenkaku_Hankaku - insert_record(table, 0x0000ff2f, 0x01000000714); // Eisu_Shift - insert_record(table, 0x0000ff31, 0x01000000711); // Hangul - insert_record(table, 0x0000ff34, 0x01000000712); // Hangul_Hanja - insert_record(table, 0x0000ff37, 0x01000000703); // Codeinput - insert_record(table, 0x0000ff3c, 0x01000000710); // SingleCandidate - insert_record(table, 0x0000ff3e, 0x0100000070e); // PreviousCandidate - insert_record(table, 0x0000ff50, 0x01000000306); // Home - insert_record(table, 0x0000ff51, 0x01000000302); // Left - insert_record(table, 0x0000ff52, 0x01000000304); // Up - insert_record(table, 0x0000ff53, 0x01000000303); // Right - insert_record(table, 0x0000ff54, 0x01000000301); // Down - insert_record(table, 0x0000ff55, 0x01000000308); // Page_Up - insert_record(table, 0x0000ff56, 0x01000000307); // Page_Down - insert_record(table, 0x0000ff57, 0x01000000305); // End - insert_record(table, 0x0000ff60, 0x0100000050c); // Select - insert_record(table, 0x0000ff61, 0x01000000a0c); // Print - insert_record(table, 0x0000ff62, 0x01000000506); // Execute - insert_record(table, 0x0000ff63, 0x01000000407); // Insert - insert_record(table, 0x0000ff65, 0x0100000040a); // Undo - insert_record(table, 0x0000ff66, 0x01000000409); // Redo - insert_record(table, 0x0000ff67, 0x01000000505); // Menu - insert_record(table, 0x0000ff68, 0x01000000507); // Find - insert_record(table, 0x0000ff69, 0x01000000504); // Cancel - insert_record(table, 0x0000ff6a, 0x01000000508); // Help - insert_record(table, 0x0000ff7e, 0x0100000070b); // Mode_switch - insert_record(table, 0x0000ff7f, 0x0100000010a); // Num_Lock - insert_record(table, 0x0000ff80, 0x00000000020); // KP_Space - insert_record(table, 0x0000ff89, 0x01000000009); // KP_Tab - insert_record(table, 0x0000ff8d, 0x5000000000d); // KP_Enter - insert_record(table, 0x0000ff91, 0x01000000801); // KP_F1 - insert_record(table, 0x0000ff92, 0x01000000802); // KP_F2 - insert_record(table, 0x0000ff93, 0x01000000803); // KP_F3 - insert_record(table, 0x0000ff94, 0x01000000804); // KP_F4 - insert_record(table, 0x0000ff95, 0x50000000037); // KP_Home - insert_record(table, 0x0000ff96, 0x50000000034); // KP_Left - insert_record(table, 0x0000ff97, 0x50000000038); // KP_Up - insert_record(table, 0x0000ff98, 0x50000000036); // KP_Right - insert_record(table, 0x0000ff99, 0x50000000032); // KP_Down - insert_record(table, 0x0000ff9a, 0x50000000039); // KP_Page_Up - insert_record(table, 0x0000ff9b, 0x50000000033); // KP_Page_Down - insert_record(table, 0x0000ff9c, 0x50000000031); // KP_End - insert_record(table, 0x0000ff9e, 0x50000000030); // KP_Insert - insert_record(table, 0x0000ff9f, 0x5000000002e); // KP_Delete - insert_record(table, 0x0000ffaa, 0x5000000002a); // KP_Multiply - insert_record(table, 0x0000ffab, 0x5000000002b); // KP_Add - insert_record(table, 0x0000ffad, 0x5000000002d); // KP_Subtract - insert_record(table, 0x0000ffae, 0x0000000002e); // KP_Decimal - insert_record(table, 0x0000ffaf, 0x5000000002f); // KP_Divide - insert_record(table, 0x0000ffb0, 0x50000000030); // KP_0 - insert_record(table, 0x0000ffb1, 0x50000000031); // KP_1 - insert_record(table, 0x0000ffb2, 0x50000000032); // KP_2 - insert_record(table, 0x0000ffb3, 0x50000000033); // KP_3 - insert_record(table, 0x0000ffb4, 0x50000000034); // KP_4 - insert_record(table, 0x0000ffb5, 0x50000000035); // KP_5 - insert_record(table, 0x0000ffb6, 0x50000000036); // KP_6 - insert_record(table, 0x0000ffb7, 0x50000000037); // KP_7 - insert_record(table, 0x0000ffb8, 0x50000000038); // KP_8 - insert_record(table, 0x0000ffb9, 0x50000000039); // KP_9 - insert_record(table, 0x0000ffbd, 0x5000000003d); // KP_Equal - insert_record(table, 0x0000ffbe, 0x01000000801); // F1 - insert_record(table, 0x0000ffbf, 0x01000000802); // F2 - insert_record(table, 0x0000ffc0, 0x01000000803); // F3 - insert_record(table, 0x0000ffc1, 0x01000000804); // F4 - insert_record(table, 0x0000ffc2, 0x01000000805); // F5 - insert_record(table, 0x0000ffc3, 0x01000000806); // F6 - insert_record(table, 0x0000ffc4, 0x01000000807); // F7 - insert_record(table, 0x0000ffc5, 0x01000000808); // F8 - insert_record(table, 0x0000ffc6, 0x01000000809); // F9 - insert_record(table, 0x0000ffc7, 0x0100000080a); // F10 - insert_record(table, 0x0000ffc8, 0x0100000080b); // F11 - insert_record(table, 0x0000ffc9, 0x0100000080c); // F12 - insert_record(table, 0x0000ffca, 0x0100000080d); // F13 - insert_record(table, 0x0000ffcb, 0x0100000080e); // F14 - insert_record(table, 0x0000ffcc, 0x0100000080f); // F15 - insert_record(table, 0x0000ffcd, 0x01000000810); // F16 - insert_record(table, 0x0000ffce, 0x01000000811); // F17 - insert_record(table, 0x0000ffcf, 0x01000000812); // F18 - insert_record(table, 0x0000ffd0, 0x01000000813); // F19 - insert_record(table, 0x0000ffd1, 0x01000000814); // F20 - insert_record(table, 0x0000ffd2, 0x01000000815); // F21 - insert_record(table, 0x0000ffd3, 0x01000000816); // F22 - insert_record(table, 0x0000ffd4, 0x01000000817); // F23 - insert_record(table, 0x0000ffd5, 0x01000000818); // F24 - insert_record(table, 0x0000ffe1, 0x3000000010d); // Shift_L - insert_record(table, 0x0000ffe2, 0x4000000010d); // Shift_R - insert_record(table, 0x0000ffe3, 0x30000000105); // Control_L - insert_record(table, 0x0000ffe4, 0x40000000105); // Control_R - insert_record(table, 0x0000ffe5, 0x01000000104); // Caps_Lock - insert_record(table, 0x0000ffe7, 0x30000000109); // Meta_L - insert_record(table, 0x0000ffe8, 0x40000000109); // Meta_R - insert_record(table, 0x0000ffe9, 0x30000000102); // Alt_L - insert_record(table, 0x0000ffea, 0x40000000102); // Alt_R - insert_record(table, 0x0000ffeb, 0x0100000010e); // Super_L - insert_record(table, 0x0000ffec, 0x0100000010e); // Super_R - insert_record(table, 0x0000ffed, 0x01000000108); // Hyper_L - insert_record(table, 0x0000ffee, 0x01000000108); // Hyper_R - insert_record(table, 0x0000ffff, 0x0100000007f); // Delete - insert_record(table, 0x1008ff02, 0x01000000602); // MonBrightnessUp - insert_record(table, 0x1008ff03, 0x01000000601); // MonBrightnessDown - insert_record(table, 0x1008ff10, 0x0100000060a); // Standby - insert_record(table, 0x1008ff11, 0x01000000a0f); // AudioLowerVolume - insert_record(table, 0x1008ff12, 0x01000000a11); // AudioMute - insert_record(table, 0x1008ff13, 0x01000000a10); // AudioRaiseVolume - insert_record(table, 0x1008ff14, 0x01000000d2f); // AudioPlay - insert_record(table, 0x1008ff15, 0x01000000a07); // AudioStop - insert_record(table, 0x1008ff16, 0x01000000a09); // AudioPrev - insert_record(table, 0x1008ff17, 0x01000000a08); // AudioNext - insert_record(table, 0x1008ff18, 0x01000000c04); // HomePage - insert_record(table, 0x1008ff19, 0x01000000b03); // Mail - insert_record(table, 0x1008ff1b, 0x01000000c06); // Search - insert_record(table, 0x1008ff1c, 0x01000000d30); // AudioRecord - insert_record(table, 0x1008ff20, 0x01000000b02); // Calendar - insert_record(table, 0x1008ff26, 0x01000000c01); // Back - insert_record(table, 0x1008ff27, 0x01000000c03); // Forward - insert_record(table, 0x1008ff28, 0x01000000c07); // Stop - insert_record(table, 0x1008ff29, 0x01000000c05); // Refresh - insert_record(table, 0x1008ff2a, 0x01000000607); // PowerOff - insert_record(table, 0x1008ff2b, 0x0100000060b); // WakeUp - insert_record(table, 0x1008ff2c, 0x01000000604); // Eject - insert_record(table, 0x1008ff2d, 0x01000000b07); // ScreenSaver - insert_record(table, 0x1008ff2f, 0x01100010082); // Sleep - insert_record(table, 0x1008ff30, 0x01000000c02); // Favorites - insert_record(table, 0x1008ff31, 0x01000000d2e); // AudioPause - insert_record(table, 0x1008ff3e, 0x01000000d31); // AudioRewind - insert_record(table, 0x1008ff56, 0x01000000a01); // Close - insert_record(table, 0x1008ff57, 0x01000000402); // Copy - insert_record(table, 0x1008ff58, 0x01000000404); // Cut - insert_record(table, 0x1008ff61, 0x01000000605); // LogOff - insert_record(table, 0x1008ff68, 0x01000000a0a); // New - insert_record(table, 0x1008ff6b, 0x01000000a0b); // Open - insert_record(table, 0x1008ff6d, 0x01000000408); // Paste - insert_record(table, 0x1008ff6e, 0x01000000b0d); // Phone - insert_record(table, 0x1008ff72, 0x01000000a03); // Reply - insert_record(table, 0x1008ff77, 0x01000000a0d); // Save - insert_record(table, 0x1008ff7b, 0x01000000a04); // Send - insert_record(table, 0x1008ff7c, 0x01000000a0e); // Spell - insert_record(table, 0x1008ff8b, 0x0100000050d); // ZoomIn - insert_record(table, 0x1008ff8c, 0x0100000050e); // ZoomOut - insert_record(table, 0x1008ff90, 0x01000000a02); // MailForward - insert_record(table, 0x1008ff97, 0x01000000d2c); // AudioForward - insert_record(table, 0x1008ffa7, 0x01100000014); // Suspend + {0x000000a5, 0x01100070089}, // yen + {0x0000fd06, 0x01000000405}, // 3270_EraseEOF + {0x0000fd0e, 0x01000000503}, // 3270_Attn + {0x0000fd15, 0x01000000402}, // 3270_Copy + {0x0000fd16, 0x01000000d2f}, // 3270_Play + {0x0000fd1b, 0x01000000406}, // 3270_ExSelect + {0x0000fd1d, 0x01000000608}, // 3270_PrintScreen + {0x0000fd1e, 0x0100000000d}, // 3270_Enter + {0x0000fe03, 0x40000000102}, // ISO_Level3_Shift + {0x0000fe08, 0x01000000709}, // ISO_Next_Group + {0x0000fe0a, 0x0100000070a}, // ISO_Prev_Group + {0x0000fe0c, 0x01000000707}, // ISO_First_Group + {0x0000fe0e, 0x01000000708}, // ISO_Last_Group + {0x0000fe20, 0x01000000009}, // ISO_Left_Tab + {0x0000fe34, 0x0100000000d}, // ISO_Enter + {0x0000ff08, 0x01000000008}, // BackSpace + {0x0000ff09, 0x01000000009}, // Tab + {0x0000ff0b, 0x01000000401}, // Clear + {0x0000ff0d, 0x0100000000d}, // Return + {0x0000ff13, 0x01000000509}, // Pause + {0x0000ff14, 0x0100000010c}, // Scroll_Lock + {0x0000ff1b, 0x0100000001b}, // Escape + {0x0000ff21, 0x01000000719}, // Kanji + {0x0000ff24, 0x0100000071b}, // Romaji + {0x0000ff25, 0x01000000716}, // Hiragana + {0x0000ff26, 0x0100000071a}, // Katakana + {0x0000ff27, 0x01000000717}, // Hiragana_Katakana + {0x0000ff28, 0x0100000071c}, // Zenkaku + {0x0000ff29, 0x01000000715}, // Hankaku + {0x0000ff2a, 0x0100000071d}, // Zenkaku_Hankaku + {0x0000ff2f, 0x01000000714}, // Eisu_Shift + {0x0000ff31, 0x01000000711}, // Hangul + {0x0000ff34, 0x01000000712}, // Hangul_Hanja + {0x0000ff37, 0x01000000703}, // Codeinput + {0x0000ff3c, 0x01000000710}, // SingleCandidate + {0x0000ff3e, 0x0100000070e}, // PreviousCandidate + {0x0000ff50, 0x01000000306}, // Home + {0x0000ff51, 0x01000000302}, // Left + {0x0000ff52, 0x01000000304}, // Up + {0x0000ff53, 0x01000000303}, // Right + {0x0000ff54, 0x01000000301}, // Down + {0x0000ff55, 0x01000000308}, // Page_Up + {0x0000ff56, 0x01000000307}, // Page_Down + {0x0000ff57, 0x01000000305}, // End + {0x0000ff60, 0x0100000050c}, // Select + {0x0000ff61, 0x01000000a0c}, // Print + {0x0000ff62, 0x01000000506}, // Execute + {0x0000ff63, 0x01000000407}, // Insert + {0x0000ff65, 0x0100000040a}, // Undo + {0x0000ff66, 0x01000000409}, // Redo + {0x0000ff67, 0x01000000505}, // Menu + {0x0000ff68, 0x01000000507}, // Find + {0x0000ff69, 0x01000000504}, // Cancel + {0x0000ff6a, 0x01000000508}, // Help + {0x0000ff7e, 0x0100000070b}, // Mode_switch + {0x0000ff7f, 0x0100000010a}, // Num_Lock + {0x0000ff80, 0x00000000020}, // KP_Space + {0x0000ff89, 0x01000000009}, // KP_Tab + {0x0000ff8d, 0x5000000000d}, // KP_Enter + {0x0000ff91, 0x01000000801}, // KP_F1 + {0x0000ff92, 0x01000000802}, // KP_F2 + {0x0000ff93, 0x01000000803}, // KP_F3 + {0x0000ff94, 0x01000000804}, // KP_F4 + {0x0000ff95, 0x50000000037}, // KP_Home + {0x0000ff96, 0x50000000034}, // KP_Left + {0x0000ff97, 0x50000000038}, // KP_Up + {0x0000ff98, 0x50000000036}, // KP_Right + {0x0000ff99, 0x50000000032}, // KP_Down + {0x0000ff9a, 0x50000000039}, // KP_Page_Up + {0x0000ff9b, 0x50000000033}, // KP_Page_Down + {0x0000ff9c, 0x50000000031}, // KP_End + {0x0000ff9e, 0x50000000030}, // KP_Insert + {0x0000ff9f, 0x5000000002e}, // KP_Delete + {0x0000ffaa, 0x5000000002a}, // KP_Multiply + {0x0000ffab, 0x5000000002b}, // KP_Add + {0x0000ffad, 0x5000000002d}, // KP_Subtract + {0x0000ffae, 0x0000000002e}, // KP_Decimal + {0x0000ffaf, 0x5000000002f}, // KP_Divide + {0x0000ffb0, 0x50000000030}, // KP_0 + {0x0000ffb1, 0x50000000031}, // KP_1 + {0x0000ffb2, 0x50000000032}, // KP_2 + {0x0000ffb3, 0x50000000033}, // KP_3 + {0x0000ffb4, 0x50000000034}, // KP_4 + {0x0000ffb5, 0x50000000035}, // KP_5 + {0x0000ffb6, 0x50000000036}, // KP_6 + {0x0000ffb7, 0x50000000037}, // KP_7 + {0x0000ffb8, 0x50000000038}, // KP_8 + {0x0000ffb9, 0x50000000039}, // KP_9 + {0x0000ffbd, 0x5000000003d}, // KP_Equal + {0x0000ffbe, 0x01000000801}, // F1 + {0x0000ffbf, 0x01000000802}, // F2 + {0x0000ffc0, 0x01000000803}, // F3 + {0x0000ffc1, 0x01000000804}, // F4 + {0x0000ffc2, 0x01000000805}, // F5 + {0x0000ffc3, 0x01000000806}, // F6 + {0x0000ffc4, 0x01000000807}, // F7 + {0x0000ffc5, 0x01000000808}, // F8 + {0x0000ffc6, 0x01000000809}, // F9 + {0x0000ffc7, 0x0100000080a}, // F10 + {0x0000ffc8, 0x0100000080b}, // F11 + {0x0000ffc9, 0x0100000080c}, // F12 + {0x0000ffca, 0x0100000080d}, // F13 + {0x0000ffcb, 0x0100000080e}, // F14 + {0x0000ffcc, 0x0100000080f}, // F15 + {0x0000ffcd, 0x01000000810}, // F16 + {0x0000ffce, 0x01000000811}, // F17 + {0x0000ffcf, 0x01000000812}, // F18 + {0x0000ffd0, 0x01000000813}, // F19 + {0x0000ffd1, 0x01000000814}, // F20 + {0x0000ffd2, 0x01000000815}, // F21 + {0x0000ffd3, 0x01000000816}, // F22 + {0x0000ffd4, 0x01000000817}, // F23 + {0x0000ffd5, 0x01000000818}, // F24 + {0x0000ffe1, 0x3000000010d}, // Shift_L + {0x0000ffe2, 0x4000000010d}, // Shift_R + {0x0000ffe3, 0x30000000105}, // Control_L + {0x0000ffe4, 0x40000000105}, // Control_R + {0x0000ffe5, 0x01000000104}, // Caps_Lock + {0x0000ffe7, 0x30000000109}, // Meta_L + {0x0000ffe8, 0x40000000109}, // Meta_R + {0x0000ffe9, 0x30000000102}, // Alt_L + {0x0000ffea, 0x40000000102}, // Alt_R + {0x0000ffeb, 0x0100000010e}, // Super_L + {0x0000ffec, 0x0100000010e}, // Super_R + {0x0000ffed, 0x01000000108}, // Hyper_L + {0x0000ffee, 0x01000000108}, // Hyper_R + {0x0000ffff, 0x0100000007f}, // Delete + {0x1008ff02, 0x01000000602}, // MonBrightnessUp + {0x1008ff03, 0x01000000601}, // MonBrightnessDown + {0x1008ff10, 0x0100000060a}, // Standby + {0x1008ff11, 0x01000000a0f}, // AudioLowerVolume + {0x1008ff12, 0x01000000a11}, // AudioMute + {0x1008ff13, 0x01000000a10}, // AudioRaiseVolume + {0x1008ff14, 0x01000000d2f}, // AudioPlay + {0x1008ff15, 0x01000000a07}, // AudioStop + {0x1008ff16, 0x01000000a09}, // AudioPrev + {0x1008ff17, 0x01000000a08}, // AudioNext + {0x1008ff18, 0x01000000c04}, // HomePage + {0x1008ff19, 0x01000000b03}, // Mail + {0x1008ff1b, 0x01000000c06}, // Search + {0x1008ff1c, 0x01000000d30}, // AudioRecord + {0x1008ff20, 0x01000000b02}, // Calendar + {0x1008ff26, 0x01000000c01}, // Back + {0x1008ff27, 0x01000000c03}, // Forward + {0x1008ff28, 0x01000000c07}, // Stop + {0x1008ff29, 0x01000000c05}, // Refresh + {0x1008ff2a, 0x01000000607}, // PowerOff + {0x1008ff2b, 0x0100000060b}, // WakeUp + {0x1008ff2c, 0x01000000604}, // Eject + {0x1008ff2d, 0x01000000b07}, // ScreenSaver + {0x1008ff2f, 0x01100010082}, // Sleep + {0x1008ff30, 0x01000000c02}, // Favorites + {0x1008ff31, 0x01000000d2e}, // AudioPause + {0x1008ff3e, 0x01000000d31}, // AudioRewind + {0x1008ff56, 0x01000000a01}, // Close + {0x1008ff57, 0x01000000402}, // Copy + {0x1008ff58, 0x01000000404}, // Cut + {0x1008ff61, 0x01000000605}, // LogOff + {0x1008ff68, 0x01000000a0a}, // New + {0x1008ff6b, 0x01000000a0b}, // Open + {0x1008ff6d, 0x01000000408}, // Paste + {0x1008ff6e, 0x01000000b0d}, // Phone + {0x1008ff72, 0x01000000a03}, // Reply + {0x1008ff77, 0x01000000a0d}, // Save + {0x1008ff7b, 0x01000000a04}, // Send + {0x1008ff7c, 0x01000000a0e}, // Spell + {0x1008ff8b, 0x0100000050d}, // ZoomIn + {0x1008ff8c, 0x0100000050e}, // ZoomOut + {0x1008ff90, 0x01000000a02}, // MailForward + {0x1008ff97, 0x01000000d2c}, // AudioForward + {0x1008ffa7, 0x01100000014}, // Suspend } void initialize_modifier_bit_to_checked_keys(GHashTable* table) { @@ -424,30 +598,30 @@ void initialize_modifier_bit_to_checked_keys(GHashTable* table) { data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_SHIFT_MASK), data); data->is_caps_lock = false; - data->primary_physical_key = 0x0000700e1; // shiftLeft - data->primary_logical_key = 0x3000000010d; // shiftLeft - data->secondary_logical_key = 0x4000000010d; // shiftRight + data->primary_logical_key = 0x3000000010d; // shiftLeft + data->primary_physical_key = 0x0000700e1; // shiftLeft + data->secondary_physical_key = 0x0000700e5; // shiftRight data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_CONTROL_MASK), data); data->is_caps_lock = false; - data->primary_physical_key = 0x0000700e0; // controlLeft - data->primary_logical_key = 0x30000000105; // controlLeft - data->secondary_logical_key = 0x40000000105; // controlRight + data->primary_logical_key = 0x30000000105; // controlLeft + data->primary_physical_key = 0x0000700e0; // controlLeft + data->secondary_physical_key = 0x0000700e4; // controlRight data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_MOD1_MASK), data); data->is_caps_lock = false; - data->primary_physical_key = 0x0000700e2; // altLeft - data->primary_logical_key = 0x30000000102; // altLeft - data->secondary_logical_key = 0x40000000102; // altRight + data->primary_logical_key = 0x30000000102; // altLeft + data->primary_physical_key = 0x0000700e2; // altLeft + data->secondary_physical_key = 0x0000700e6; // altRight data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_META_MASK), data); data->is_caps_lock = false; - data->primary_physical_key = 0x0000700e3; // metaLeft - data->primary_logical_key = 0x30000000109; // metaLeft - data->secondary_logical_key = 0x40000000109; // metaRight + data->primary_logical_key = 0x30000000109; // metaLeft + data->primary_physical_key = 0x0000700e3; // metaLeft + data->secondary_physical_key = 0x0000700e7; // metaRight } void initialize_lock_bit_to_checked_keys(GHashTable* table) { @@ -456,12 +630,12 @@ void initialize_lock_bit_to_checked_keys(GHashTable* table) { data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_LOCK_MASK), data); data->is_caps_lock = true; - data->primary_physical_key = 0x000070039; // capsLock data->primary_logical_key = 0x01000000104; // capsLock + data->primary_physical_key = 0x000070039; // capsLock data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_MOD2_MASK), data); data->is_caps_lock = false; - data->primary_physical_key = 0x000070053; // numLock data->primary_logical_key = 0x0100000010a; // numLock + data->primary_physical_key = 0x000070053; // numLock } diff --git a/shell/platform/linux/key_mapping.h b/shell/platform/linux/key_mapping.h index 3f75ecfc68615..c537102e04168 100644 --- a/shell/platform/linux/key_mapping.h +++ b/shell/platform/linux/key_mapping.h @@ -7,6 +7,7 @@ #include #include +#include inline uint64_t gpointer_to_uint64(gpointer pointer) { return pointer == nullptr ? 0 : reinterpret_cast(pointer); @@ -16,13 +17,11 @@ inline gpointer uint64_to_gpointer(uint64_t number) { return reinterpret_cast(number); } -// Initialize a hashtable that maps XKB specific key code values to -// Flutter's physical key code values. -void initialize_xkb_to_physical_key(GHashTable* table); +// Maps XKB specific key code values to Flutter's physical key code values. +extern std::map xkb_to_physical_key_map; -// Initialize a hashtable that maps GDK keyval values to -// Flutter's logical key code values. -void initialize_gtk_keyval_to_logical_key(GHashTable* table); +// Maps GDK keyval values to Flutter's logical key code values. +extern std::map gtk_keyval_to_logical_key_map; void initialize_modifier_bit_to_checked_keys(GHashTable* table); From 20d6e56cf107db38ace2d8124d7b91191c7ffabb Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Fri, 14 May 2021 19:01:21 -0700 Subject: [PATCH 086/126] ATP --- .../linux/fl_key_embedder_responder.cc | 4 +- shell/platform/linux/fl_keyboard_manager.cc | 6 +- shell/platform/linux/key_mapping.cc | 996 +++++++----------- 3 files changed, 412 insertions(+), 594 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index 225d376bcdf0f..3bafe66b980e2 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -280,7 +280,7 @@ FlKeyEmbedderResponder* fl_key_embedder_responder_new(FlEngine* engine) { /* Implement FlKeyEmbedderUserData */ static uint64_t event_to_physical_key(const FlKeyEvent* event) { - auto found = xkb_to_physical_key_map[event->keycode]; + auto found = xkb_to_physical_key_map.find(event->keycode); if (found != xkb_to_physical_key_map.end()) { return found->second; } @@ -289,7 +289,7 @@ static uint64_t event_to_physical_key(const FlKeyEvent* event) { static uint64_t event_to_logical_key(const FlKeyEvent* event) { guint keyval = event->keyval; - auto found = gtk_keyval_to_logical_key_map[keyval]; + auto found = gtk_keyval_to_logical_key_map.find(keyval); if (found != gtk_keyval_to_logical_key_map.end()) { return found->second; } diff --git a/shell/platform/linux/fl_keyboard_manager.cc b/shell/platform/linux/fl_keyboard_manager.cc index 1d0c9c679433f..4c25f1cf90ae1 100644 --- a/shell/platform/linux/fl_keyboard_manager.cc +++ b/shell/platform/linux/fl_keyboard_manager.cc @@ -70,10 +70,10 @@ static uint64_t fl_keyboard_manager_get_event_hash(FlKeyEvent* event) { // (scan code) of the event to come up with a unique id for this event that // can be derived solely from the event data itself, so that we can identify // whether or not we have seen this event already. - guint64 type = static_cast(event->is_press ? GDK_KEY_PRESS : GDK_KEY_RELEASE); + guint64 type = + static_cast(event->is_press ? GDK_KEY_PRESS : GDK_KEY_RELEASE); guint64 keycode = static_cast(event->keycode); - return (event->time & 0xffffffff) | - ((type & 0xffff) << 32) | + return (event->time & 0xffffffff) | ((type & 0xffff) << 32) | ((keycode & 0xffff) << 48); } diff --git a/shell/platform/linux/key_mapping.cc b/shell/platform/linux/key_mapping.cc index b1f0d1634cf9b..c43249705e7ee 100644 --- a/shell/platform/linux/key_mapping.cc +++ b/shell/platform/linux/key_mapping.cc @@ -7,6 +7,8 @@ #include #include +#include "flutter/shell/platform/linux/fl_key_embedder_responder_private.h" + // DO NOT EDIT -- DO NOT EDIT -- DO NOT EDIT // This file is generated by // flutter/flutter@dev/tools/gen_keycodes/bin/gen_keycodes.dart and should not @@ -15,582 +17,398 @@ // Edit the template dev/tools/gen_keycodes/data/gtk_key_mapping_cc.tmpl // instead. See dev/tools/gen_keycodes/README.md for more information. -// Insert a new entry into a hashtable from uint64 to uint64. -// -// Returns whether the newly added value was already in the hash table or not. -static bool insert_record(GHashTable* table, guint64 xkb, guint64 fl_key) { - return g_hash_table_insert(table, uint64_to_gpointer(xkb), - uint64_to_gpointer(fl_key)); -} - -std::map xkb_to_physical_key_map = - { - {0x00000009, 0x00070029}, // escape - {0x0000000a, 0x0007001e}, // digit1 - {0x0000000b, 0x0007001f}, // digit2 - {0x0000000c, 0x00070020}, // digit3 - {0x0000000d, 0x00070021}, // digit4 - {0x0000000e, 0x00070022}, // digit5 - {0x0000000f, 0x00070023}, // digit6 - {0x00000010, 0x00070024}, // digit7 - {0x00000011, 0x00070025}, // digit8 - {0x00000012, 0x00070026}, // digit9 - {0x00000013, 0x00070027}, // digit0 - {0x00000014, 0x0007002d}, // minus - {0x00000015, 0x0007002e}, // equal - {0x00000016, 0x0007002a}, // backspace - {0x00000017, 0x0007002b}, // tab - {0x00000018, 0x00070014}, // keyQ - {0x00000019, 0x0007001a}, // keyW - {0x0000001a, 0x00070008}, // keyE - {0x0000001b, 0x00070015}, // keyR - {0x0000001c, 0x00070017}, // keyT - {0x0000001d, 0x0007001c}, // keyY - {0x0000001e, 0x00070018}, // keyU - {0x0000001f, 0x0007000c}, // keyI - {0x00000020, 0x00070012}, // keyO - {0x00000021, 0x00070013}, // keyP - {0x00000022, 0x0007002f}, // bracketLeft - {0x00000023, 0x00070030}, // bracketRight - {0x00000024, 0x00070028}, // enter - {0x00000025, 0x000700e0}, // controlLeft - {0x00000026, 0x00070004}, // keyA - {0x00000027, 0x00070016}, // keyS - {0x00000028, 0x00070007}, // keyD - {0x00000029, 0x00070009}, // keyF - {0x0000002a, 0x0007000a}, // keyG - {0x0000002b, 0x0007000b}, // keyH - {0x0000002c, 0x0007000d}, // keyJ - {0x0000002d, 0x0007000e}, // keyK - {0x0000002e, 0x0007000f}, // keyL - {0x0000002f, 0x00070033}, // semicolon - {0x00000030, 0x00070034}, // quote - {0x00000031, 0x00070035}, // backquote - {0x00000032, 0x000700e1}, // shiftLeft - {0x00000033, 0x00070031}, // backslash - {0x00000034, 0x0007001d}, // keyZ - {0x00000035, 0x0007001b}, // keyX - {0x00000036, 0x00070006}, // keyC - {0x00000037, 0x00070019}, // keyV - {0x00000038, 0x00070005}, // keyB - {0x00000039, 0x00070011}, // keyN - {0x0000003a, 0x00070010}, // keyM - {0x0000003b, 0x00070036}, // comma - {0x0000003c, 0x00070037}, // period - {0x0000003d, 0x00070038}, // slash - {0x0000003e, 0x000700e5}, // shiftRight - {0x0000003f, 0x00070055}, // numpadMultiply - {0x00000040, 0x000700e2}, // altLeft - {0x00000041, 0x0007002c}, // space - {0x00000042, 0x00070039}, // capsLock - {0x00000043, 0x0007003a}, // f1 - {0x00000044, 0x0007003b}, // f2 - {0x00000045, 0x0007003c}, // f3 - {0x00000046, 0x0007003d}, // f4 - {0x00000047, 0x0007003e}, // f5 - {0x00000048, 0x0007003f}, // f6 - {0x00000049, 0x00070040}, // f7 - {0x0000004a, 0x00070041}, // f8 - {0x0000004b, 0x00070042}, // f9 - {0x0000004c, 0x00070043}, // f10 - {0x0000004d, 0x00070053}, // numLock - {0x0000004e, 0x00070047}, // scrollLock - {0x0000004f, 0x0007005f}, // numpad7 - {0x00000050, 0x00070060}, // numpad8 - {0x00000051, 0x00070061}, // numpad9 - {0x00000052, 0x00070056}, // numpadSubtract - {0x00000053, 0x0007005c}, // numpad4 - {0x00000054, 0x0007005d}, // numpad5 - {0x00000055, 0x0007005e}, // numpad6 - {0x00000056, 0x00070057}, // numpadAdd - {0x00000057, 0x00070059}, // numpad1 - {0x00000058, 0x0007005a}, // numpad2 - {0x00000059, 0x0007005b}, // numpad3 - {0x0000005a, 0x00070062}, // numpad0 - {0x0000005b, 0x00070063}, // numpadDecimal - {0x0000005d, 0x00070094}, // lang5 - {0x0000005e, 0x00070064}, // intlBackslash - {0x0000005f, 0x00070044}, // f11 - {0x00000060, 0x00070045}, // f12 - {0x00000061, 0x00070087}, // intlRo - {0x00000062, 0x00070092}, // lang3 - {0x00000063, 0x00070093}, // lang4 - {0x00000064, 0x0007008a}, // convert - {0x00000065, 0x00070088}, // kanaMode - {0x00000066, 0x0007008b}, // nonConvert - {0x00000068, 0x00070058}, // numpadEnter - {0x00000069, 0x000700e4}, // controlRight - {0x0000006a, 0x00070054}, // numpadDivide - {0x0000006b, 0x00070046}, // printScreen - {0x0000006c, 0x000700e6}, // altRight - {0x0000006e, 0x0007004a}, // home - {0x0000006f, 0x00070052}, // arrowUp - {0x00000070, 0x0007004b}, // pageUp - {0x00000071, 0x00070050}, // arrowLeft - {0x00000072, 0x0007004f}, // arrowRight - {0x00000073, 0x0007004d}, // end - {0x00000074, 0x00070051}, // arrowDown - {0x00000075, 0x0007004e}, // pageDown - {0x00000076, 0x00070049}, // insert - {0x00000077, 0x0007004c}, // delete - {0x00000079, 0x0007007f}, // audioVolumeMute - {0x0000007a, 0x00070081}, // audioVolumeDown - {0x0000007b, 0x00070080}, // audioVolumeUp - {0x0000007c, 0x00070066}, // power - {0x0000007d, 0x00070067}, // numpadEqual - {0x0000007e, 0x000700d7}, // numpadSignChange - {0x0000007f, 0x00070048}, // pause - {0x00000080, 0x000c029f}, // showAllWindows - {0x00000081, 0x00070085}, // numpadComma - {0x00000082, 0x00070090}, // lang1 - {0x00000083, 0x00070091}, // lang2 - {0x00000084, 0x00070089}, // intlYen - {0x00000085, 0x000700e3}, // metaLeft - {0x00000086, 0x000700e7}, // metaRight - {0x00000087, 0x00070065}, // contextMenu - {0x00000088, 0x000c0226}, // browserStop - {0x00000089, 0x00070079}, // again - {0x0000008b, 0x0007007a}, // undo - {0x0000008c, 0x00070077}, // select - {0x0000008d, 0x0007007c}, // copy - {0x0000008e, 0x00070074}, // open - {0x0000008f, 0x0007007d}, // paste - {0x00000090, 0x0007007e}, // find - {0x00000091, 0x0007007b}, // cut - {0x00000092, 0x00070075}, // help - {0x00000094, 0x000c0192}, // launchApp2 - {0x00000096, 0x00010082}, // sleep - {0x00000097, 0x00010083}, // wakeUp - {0x00000098, 0x000c0194}, // launchApp1 - {0x0000009e, 0x000c0196}, // launchInternetBrowser - {0x000000a0, 0x000c019e}, // lockScreen - {0x000000a3, 0x000c018a}, // launchMail - {0x000000a4, 0x000c022a}, // browserFavorites - {0x000000a6, 0x000c0224}, // browserBack - {0x000000a7, 0x000c0225}, // browserForward - {0x000000a9, 0x000c00b8}, // eject - {0x000000ab, 0x000c00b5}, // mediaTrackNext - {0x000000ac, 0x000c00cd}, // mediaPlayPause - {0x000000ad, 0x000c00b6}, // mediaTrackPrevious - {0x000000ae, 0x000c00b7}, // mediaStop - {0x000000af, 0x000c00b2}, // mediaRecord - {0x000000b0, 0x000c00b4}, // mediaRewind - {0x000000b1, 0x000c008c}, // launchPhone - {0x000000b3, 0x000c0183}, // mediaSelect - {0x000000b4, 0x000c0223}, // browserHome - {0x000000b5, 0x000c0227}, // browserRefresh - {0x000000b6, 0x000c0094}, // exit - {0x000000bb, 0x000700b6}, // numpadParenLeft - {0x000000bc, 0x000700b7}, // numpadParenRight - {0x000000bd, 0x000c0201}, // newKey - {0x000000be, 0x000c0279}, // redo - {0x000000bf, 0x00070068}, // f13 - {0x000000c0, 0x00070069}, // f14 - {0x000000c1, 0x0007006a}, // f15 - {0x000000c2, 0x0007006b}, // f16 - {0x000000c3, 0x0007006c}, // f17 - {0x000000c4, 0x0007006d}, // f18 - {0x000000c5, 0x0007006e}, // f19 - {0x000000c6, 0x0007006f}, // f20 - {0x000000c7, 0x00070070}, // f21 - {0x000000c8, 0x00070071}, // f22 - {0x000000c9, 0x00070072}, // f23 - {0x000000ca, 0x00070073}, // f24 - {0x000000d1, 0x000c00b1}, // mediaPause - {0x000000d6, 0x000c0203}, // close - {0x000000d7, 0x000c00b0}, // mediaPlay - {0x000000d8, 0x000c00b3}, // mediaFastForward - {0x000000d9, 0x000c00e5}, // bassBoost - {0x000000da, 0x000c0208}, // print - {0x000000e1, 0x000c0221}, // browserSearch - {0x000000e8, 0x000c0070}, // brightnessDown - {0x000000e9, 0x000c006f}, // brightnessUp - {0x000000eb, 0x000100b5}, // displayToggleIntExt - {0x000000ed, 0x000c007a}, // kbdIllumDown - {0x000000ee, 0x000c0079}, // kbdIllumUp - {0x000000ef, 0x000c028c}, // mailSend - {0x000000f0, 0x000c0289}, // mailReply - {0x000000f1, 0x000c028b}, // mailForward - {0x000000f2, 0x000c0207}, // save - {0x000000f3, 0x000c01a7}, // launchDocuments - {0x000000fc, 0x000c0075}, // brightnessAuto - {0x0000016e, 0x000c0060}, // info - {0x00000172, 0x000c008d}, // programGuide - {0x0000017a, 0x000c0061}, // closedCaptionToggle - {0x0000017c, 0x000c0232}, // zoomToggle - {0x0000017e, 0x000c01ae}, // launchKeyboardLayout - {0x00000190, 0x000c01b7}, // launchAudioBrowser - {0x00000195, 0x000c018e}, // launchCalendar - {0x0000019d, 0x000c0083}, // mediaLast - {0x000001a2, 0x000c009c}, // channelUp - {0x000001a3, 0x000c009d}, // channelDown - {0x000001aa, 0x000c022d}, // zoomIn - {0x000001ab, 0x000c022e}, // zoomOut - {0x000001ad, 0x000c0184}, // launchWordProcessor - {0x000001af, 0x000c0186}, // launchSpreadsheet - {0x000001b5, 0x000c018d}, // launchContacts - {0x000001b7, 0x000c0072}, // brightnessToggle - {0x000001b8, 0x000c01ab}, // spellCheck - {0x000001b9, 0x000c019c}, // logOff - {0x0000024b, 0x000c019f}, // launchControlPanel - {0x0000024c, 0x000c01a2}, // selectTask - {0x0000024d, 0x000c01b1}, // launchScreenSaver - {0x0000024e, 0x000c00cf}, // speechInputToggle - {0x0000024f, 0x000c01cb}, // launchAssistant - {0x00000250, 0x000c029d}, // keyboardLayoutSelect - {0x00000258, 0x000c0073}, // brightnessMinimum - {0x00000259, 0x000c0074}, // brightnessMaximum - {0x00000281, 0x00000017}, // privacyScreenToggle - } - -std::map gtk_keyval_to_logical_key_map = - { - {0x000000a5, 0x01100070089}, // yen - {0x0000fd06, 0x01000000405}, // 3270_EraseEOF - {0x0000fd0e, 0x01000000503}, // 3270_Attn - {0x0000fd15, 0x01000000402}, // 3270_Copy - {0x0000fd16, 0x01000000d2f}, // 3270_Play - {0x0000fd1b, 0x01000000406}, // 3270_ExSelect - {0x0000fd1d, 0x01000000608}, // 3270_PrintScreen - {0x0000fd1e, 0x0100000000d}, // 3270_Enter - {0x0000fe03, 0x40000000102}, // ISO_Level3_Shift - {0x0000fe08, 0x01000000709}, // ISO_Next_Group - {0x0000fe0a, 0x0100000070a}, // ISO_Prev_Group - {0x0000fe0c, 0x01000000707}, // ISO_First_Group - {0x0000fe0e, 0x01000000708}, // ISO_Last_Group - {0x0000fe20, 0x01000000009}, // ISO_Left_Tab - {0x0000fe34, 0x0100000000d}, // ISO_Enter - {0x0000ff08, 0x01000000008}, // BackSpace - {0x0000ff09, 0x01000000009}, // Tab - {0x0000ff0b, 0x01000000401}, // Clear - {0x0000ff0d, 0x0100000000d}, // Return - {0x0000ff13, 0x01000000509}, // Pause - {0x0000ff14, 0x0100000010c}, // Scroll_Lock - {0x0000ff1b, 0x0100000001b}, // Escape - {0x0000ff21, 0x01000000719}, // Kanji - {0x0000ff24, 0x0100000071b}, // Romaji - {0x0000ff25, 0x01000000716}, // Hiragana - {0x0000ff26, 0x0100000071a}, // Katakana - {0x0000ff27, 0x01000000717}, // Hiragana_Katakana - {0x0000ff28, 0x0100000071c}, // Zenkaku - {0x0000ff29, 0x01000000715}, // Hankaku - {0x0000ff2a, 0x0100000071d}, // Zenkaku_Hankaku - {0x0000ff2f, 0x01000000714}, // Eisu_Shift - {0x0000ff31, 0x01000000711}, // Hangul - {0x0000ff34, 0x01000000712}, // Hangul_Hanja - {0x0000ff37, 0x01000000703}, // Codeinput - {0x0000ff3c, 0x01000000710}, // SingleCandidate - {0x0000ff3e, 0x0100000070e}, // PreviousCandidate - {0x0000ff50, 0x01000000306}, // Home - {0x0000ff51, 0x01000000302}, // Left - {0x0000ff52, 0x01000000304}, // Up - {0x0000ff53, 0x01000000303}, // Right - {0x0000ff54, 0x01000000301}, // Down - {0x0000ff55, 0x01000000308}, // Page_Up - {0x0000ff56, 0x01000000307}, // Page_Down - {0x0000ff57, 0x01000000305}, // End - {0x0000ff60, 0x0100000050c}, // Select - {0x0000ff61, 0x01000000a0c}, // Print - {0x0000ff62, 0x01000000506}, // Execute - {0x0000ff63, 0x01000000407}, // Insert - {0x0000ff65, 0x0100000040a}, // Undo - {0x0000ff66, 0x01000000409}, // Redo - {0x0000ff67, 0x01000000505}, // Menu - {0x0000ff68, 0x01000000507}, // Find - {0x0000ff69, 0x01000000504}, // Cancel - {0x0000ff6a, 0x01000000508}, // Help - {0x0000ff7e, 0x0100000070b}, // Mode_switch - {0x0000ff7f, 0x0100000010a}, // Num_Lock - {0x0000ff80, 0x00000000020}, // KP_Space - {0x0000ff89, 0x01000000009}, // KP_Tab - {0x0000ff8d, 0x5000000000d}, // KP_Enter - {0x0000ff91, 0x01000000801}, // KP_F1 - {0x0000ff92, 0x01000000802}, // KP_F2 - {0x0000ff93, 0x01000000803}, // KP_F3 - {0x0000ff94, 0x01000000804}, // KP_F4 - {0x0000ff95, 0x50000000037}, // KP_Home - {0x0000ff96, 0x50000000034}, // KP_Left - {0x0000ff97, 0x50000000038}, // KP_Up - {0x0000ff98, 0x50000000036}, // KP_Right - {0x0000ff99, 0x50000000032}, // KP_Down - {0x0000ff9a, 0x50000000039}, // KP_Page_Up - {0x0000ff9b, 0x50000000033}, // KP_Page_Down - {0x0000ff9c, 0x50000000031}, // KP_End - {0x0000ff9e, 0x50000000030}, // KP_Insert - {0x0000ff9f, 0x5000000002e}, // KP_Delete - {0x0000ffaa, 0x5000000002a}, // KP_Multiply - {0x0000ffab, 0x5000000002b}, // KP_Add - {0x0000ffad, 0x5000000002d}, // KP_Subtract - {0x0000ffae, 0x0000000002e}, // KP_Decimal - {0x0000ffaf, 0x5000000002f}, // KP_Divide - {0x0000ffb0, 0x50000000030}, // KP_0 - {0x0000ffb1, 0x50000000031}, // KP_1 - {0x0000ffb2, 0x50000000032}, // KP_2 - {0x0000ffb3, 0x50000000033}, // KP_3 - {0x0000ffb4, 0x50000000034}, // KP_4 - {0x0000ffb5, 0x50000000035}, // KP_5 - {0x0000ffb6, 0x50000000036}, // KP_6 - {0x0000ffb7, 0x50000000037}, // KP_7 - {0x0000ffb8, 0x50000000038}, // KP_8 - {0x0000ffb9, 0x50000000039}, // KP_9 - {0x0000ffbd, 0x5000000003d}, // KP_Equal - {0x0000ffbe, 0x01000000801}, // F1 - {0x0000ffbf, 0x01000000802}, // F2 - {0x0000ffc0, 0x01000000803}, // F3 - {0x0000ffc1, 0x01000000804}, // F4 - {0x0000ffc2, 0x01000000805}, // F5 - {0x0000ffc3, 0x01000000806}, // F6 - {0x0000ffc4, 0x01000000807}, // F7 - {0x0000ffc5, 0x01000000808}, // F8 - {0x0000ffc6, 0x01000000809}, // F9 - {0x0000ffc7, 0x0100000080a}, // F10 - {0x0000ffc8, 0x0100000080b}, // F11 - {0x0000ffc9, 0x0100000080c}, // F12 - {0x0000ffca, 0x0100000080d}, // F13 - {0x0000ffcb, 0x0100000080e}, // F14 - {0x0000ffcc, 0x0100000080f}, // F15 - {0x0000ffcd, 0x01000000810}, // F16 - {0x0000ffce, 0x01000000811}, // F17 - {0x0000ffcf, 0x01000000812}, // F18 - {0x0000ffd0, 0x01000000813}, // F19 - {0x0000ffd1, 0x01000000814}, // F20 - {0x0000ffd2, 0x01000000815}, // F21 - {0x0000ffd3, 0x01000000816}, // F22 - {0x0000ffd4, 0x01000000817}, // F23 - {0x0000ffd5, 0x01000000818}, // F24 - {0x0000ffe1, 0x3000000010d}, // Shift_L - {0x0000ffe2, 0x4000000010d}, // Shift_R - {0x0000ffe3, 0x30000000105}, // Control_L - {0x0000ffe4, 0x40000000105}, // Control_R - {0x0000ffe5, 0x01000000104}, // Caps_Lock - {0x0000ffe7, 0x30000000109}, // Meta_L - {0x0000ffe8, 0x40000000109}, // Meta_R - {0x0000ffe9, 0x30000000102}, // Alt_L - {0x0000ffea, 0x40000000102}, // Alt_R - {0x0000ffeb, 0x0100000010e}, // Super_L - {0x0000ffec, 0x0100000010e}, // Super_R - {0x0000ffed, 0x01000000108}, // Hyper_L - {0x0000ffee, 0x01000000108}, // Hyper_R - {0x0000ffff, 0x0100000007f}, // Delete - {0x1008ff02, 0x01000000602}, // MonBrightnessUp - {0x1008ff03, 0x01000000601}, // MonBrightnessDown - {0x1008ff10, 0x0100000060a}, // Standby - {0x1008ff11, 0x01000000a0f}, // AudioLowerVolume - {0x1008ff12, 0x01000000a11}, // AudioMute - {0x1008ff13, 0x01000000a10}, // AudioRaiseVolume - {0x1008ff14, 0x01000000d2f}, // AudioPlay - {0x1008ff15, 0x01000000a07}, // AudioStop - {0x1008ff16, 0x01000000a09}, // AudioPrev - {0x1008ff17, 0x01000000a08}, // AudioNext - {0x1008ff18, 0x01000000c04}, // HomePage - {0x1008ff19, 0x01000000b03}, // Mail - {0x1008ff1b, 0x01000000c06}, // Search - {0x1008ff1c, 0x01000000d30}, // AudioRecord - {0x1008ff20, 0x01000000b02}, // Calendar - {0x1008ff26, 0x01000000c01}, // Back - {0x1008ff27, 0x01000000c03}, // Forward - {0x1008ff28, 0x01000000c07}, // Stop - {0x1008ff29, 0x01000000c05}, // Refresh - {0x1008ff2a, 0x01000000607}, // PowerOff - {0x1008ff2b, 0x0100000060b}, // WakeUp - {0x1008ff2c, 0x01000000604}, // Eject - {0x1008ff2d, 0x01000000b07}, // ScreenSaver - {0x1008ff2f, 0x01100010082}, // Sleep - {0x1008ff30, 0x01000000c02}, // Favorites - {0x1008ff31, 0x01000000d2e}, // AudioPause - {0x1008ff3e, 0x01000000d31}, // AudioRewind - {0x1008ff56, 0x01000000a01}, // Close - {0x1008ff57, 0x01000000402}, // Copy - {0x1008ff58, 0x01000000404}, // Cut - {0x1008ff61, 0x01000000605}, // LogOff - {0x1008ff68, 0x01000000a0a}, // New - {0x1008ff6b, 0x01000000a0b}, // Open - {0x1008ff6d, 0x01000000408}, // Paste - {0x1008ff6e, 0x01000000b0d}, // Phone - {0x1008ff72, 0x01000000a03}, // Reply - {0x1008ff77, 0x01000000a0d}, // Save - {0x1008ff7b, 0x01000000a04}, // Send - {0x1008ff7c, 0x01000000a0e}, // Spell - {0x1008ff8b, 0x0100000050d}, // ZoomIn - {0x1008ff8c, 0x0100000050e}, // ZoomOut - {0x1008ff90, 0x01000000a02}, // MailForward - {0x1008ff97, 0x01000000d2c}, // AudioForward - {0x1008ffa7, 0x01100000014}, // Suspend - } +std::map xkb_to_physical_key_map = { + {0x00000009, 0x00070029}, // escape + {0x0000000a, 0x0007001e}, // digit1 + {0x0000000b, 0x0007001f}, // digit2 + {0x0000000c, 0x00070020}, // digit3 + {0x0000000d, 0x00070021}, // digit4 + {0x0000000e, 0x00070022}, // digit5 + {0x0000000f, 0x00070023}, // digit6 + {0x00000010, 0x00070024}, // digit7 + {0x00000011, 0x00070025}, // digit8 + {0x00000012, 0x00070026}, // digit9 + {0x00000013, 0x00070027}, // digit0 + {0x00000014, 0x0007002d}, // minus + {0x00000015, 0x0007002e}, // equal + {0x00000016, 0x0007002a}, // backspace + {0x00000017, 0x0007002b}, // tab + {0x00000018, 0x00070014}, // keyQ + {0x00000019, 0x0007001a}, // keyW + {0x0000001a, 0x00070008}, // keyE + {0x0000001b, 0x00070015}, // keyR + {0x0000001c, 0x00070017}, // keyT + {0x0000001d, 0x0007001c}, // keyY + {0x0000001e, 0x00070018}, // keyU + {0x0000001f, 0x0007000c}, // keyI + {0x00000020, 0x00070012}, // keyO + {0x00000021, 0x00070013}, // keyP + {0x00000022, 0x0007002f}, // bracketLeft + {0x00000023, 0x00070030}, // bracketRight + {0x00000024, 0x00070028}, // enter + {0x00000025, 0x000700e0}, // controlLeft + {0x00000026, 0x00070004}, // keyA + {0x00000027, 0x00070016}, // keyS + {0x00000028, 0x00070007}, // keyD + {0x00000029, 0x00070009}, // keyF + {0x0000002a, 0x0007000a}, // keyG + {0x0000002b, 0x0007000b}, // keyH + {0x0000002c, 0x0007000d}, // keyJ + {0x0000002d, 0x0007000e}, // keyK + {0x0000002e, 0x0007000f}, // keyL + {0x0000002f, 0x00070033}, // semicolon + {0x00000030, 0x00070034}, // quote + {0x00000031, 0x00070035}, // backquote + {0x00000032, 0x000700e1}, // shiftLeft + {0x00000033, 0x00070031}, // backslash + {0x00000034, 0x0007001d}, // keyZ + {0x00000035, 0x0007001b}, // keyX + {0x00000036, 0x00070006}, // keyC + {0x00000037, 0x00070019}, // keyV + {0x00000038, 0x00070005}, // keyB + {0x00000039, 0x00070011}, // keyN + {0x0000003a, 0x00070010}, // keyM + {0x0000003b, 0x00070036}, // comma + {0x0000003c, 0x00070037}, // period + {0x0000003d, 0x00070038}, // slash + {0x0000003e, 0x000700e5}, // shiftRight + {0x0000003f, 0x00070055}, // numpadMultiply + {0x00000040, 0x000700e2}, // altLeft + {0x00000041, 0x0007002c}, // space + {0x00000042, 0x00070039}, // capsLock + {0x00000043, 0x0007003a}, // f1 + {0x00000044, 0x0007003b}, // f2 + {0x00000045, 0x0007003c}, // f3 + {0x00000046, 0x0007003d}, // f4 + {0x00000047, 0x0007003e}, // f5 + {0x00000048, 0x0007003f}, // f6 + {0x00000049, 0x00070040}, // f7 + {0x0000004a, 0x00070041}, // f8 + {0x0000004b, 0x00070042}, // f9 + {0x0000004c, 0x00070043}, // f10 + {0x0000004d, 0x00070053}, // numLock + {0x0000004e, 0x00070047}, // scrollLock + {0x0000004f, 0x0007005f}, // numpad7 + {0x00000050, 0x00070060}, // numpad8 + {0x00000051, 0x00070061}, // numpad9 + {0x00000052, 0x00070056}, // numpadSubtract + {0x00000053, 0x0007005c}, // numpad4 + {0x00000054, 0x0007005d}, // numpad5 + {0x00000055, 0x0007005e}, // numpad6 + {0x00000056, 0x00070057}, // numpadAdd + {0x00000057, 0x00070059}, // numpad1 + {0x00000058, 0x0007005a}, // numpad2 + {0x00000059, 0x0007005b}, // numpad3 + {0x0000005a, 0x00070062}, // numpad0 + {0x0000005b, 0x00070063}, // numpadDecimal + {0x0000005d, 0x00070094}, // lang5 + {0x0000005e, 0x00070064}, // intlBackslash + {0x0000005f, 0x00070044}, // f11 + {0x00000060, 0x00070045}, // f12 + {0x00000061, 0x00070087}, // intlRo + {0x00000062, 0x00070092}, // lang3 + {0x00000063, 0x00070093}, // lang4 + {0x00000064, 0x0007008a}, // convert + {0x00000065, 0x00070088}, // kanaMode + {0x00000066, 0x0007008b}, // nonConvert + {0x00000068, 0x00070058}, // numpadEnter + {0x00000069, 0x000700e4}, // controlRight + {0x0000006a, 0x00070054}, // numpadDivide + {0x0000006b, 0x00070046}, // printScreen + {0x0000006c, 0x000700e6}, // altRight + {0x0000006e, 0x0007004a}, // home + {0x0000006f, 0x00070052}, // arrowUp + {0x00000070, 0x0007004b}, // pageUp + {0x00000071, 0x00070050}, // arrowLeft + {0x00000072, 0x0007004f}, // arrowRight + {0x00000073, 0x0007004d}, // end + {0x00000074, 0x00070051}, // arrowDown + {0x00000075, 0x0007004e}, // pageDown + {0x00000076, 0x00070049}, // insert + {0x00000077, 0x0007004c}, // delete + {0x00000079, 0x0007007f}, // audioVolumeMute + {0x0000007a, 0x00070081}, // audioVolumeDown + {0x0000007b, 0x00070080}, // audioVolumeUp + {0x0000007c, 0x00070066}, // power + {0x0000007d, 0x00070067}, // numpadEqual + {0x0000007e, 0x000700d7}, // numpadSignChange + {0x0000007f, 0x00070048}, // pause + {0x00000080, 0x000c029f}, // showAllWindows + {0x00000081, 0x00070085}, // numpadComma + {0x00000082, 0x00070090}, // lang1 + {0x00000083, 0x00070091}, // lang2 + {0x00000084, 0x00070089}, // intlYen + {0x00000085, 0x000700e3}, // metaLeft + {0x00000086, 0x000700e7}, // metaRight + {0x00000087, 0x00070065}, // contextMenu + {0x00000088, 0x000c0226}, // browserStop + {0x00000089, 0x00070079}, // again + {0x0000008b, 0x0007007a}, // undo + {0x0000008c, 0x00070077}, // select + {0x0000008d, 0x0007007c}, // copy + {0x0000008e, 0x00070074}, // open + {0x0000008f, 0x0007007d}, // paste + {0x00000090, 0x0007007e}, // find + {0x00000091, 0x0007007b}, // cut + {0x00000092, 0x00070075}, // help + {0x00000094, 0x000c0192}, // launchApp2 + {0x00000096, 0x00010082}, // sleep + {0x00000097, 0x00010083}, // wakeUp + {0x00000098, 0x000c0194}, // launchApp1 + {0x0000009e, 0x000c0196}, // launchInternetBrowser + {0x000000a0, 0x000c019e}, // lockScreen + {0x000000a3, 0x000c018a}, // launchMail + {0x000000a4, 0x000c022a}, // browserFavorites + {0x000000a6, 0x000c0224}, // browserBack + {0x000000a7, 0x000c0225}, // browserForward + {0x000000a9, 0x000c00b8}, // eject + {0x000000ab, 0x000c00b5}, // mediaTrackNext + {0x000000ac, 0x000c00cd}, // mediaPlayPause + {0x000000ad, 0x000c00b6}, // mediaTrackPrevious + {0x000000ae, 0x000c00b7}, // mediaStop + {0x000000af, 0x000c00b2}, // mediaRecord + {0x000000b0, 0x000c00b4}, // mediaRewind + {0x000000b1, 0x000c008c}, // launchPhone + {0x000000b3, 0x000c0183}, // mediaSelect + {0x000000b4, 0x000c0223}, // browserHome + {0x000000b5, 0x000c0227}, // browserRefresh + {0x000000b6, 0x000c0094}, // exit + {0x000000bb, 0x000700b6}, // numpadParenLeft + {0x000000bc, 0x000700b7}, // numpadParenRight + {0x000000bd, 0x000c0201}, // newKey + {0x000000be, 0x000c0279}, // redo + {0x000000bf, 0x00070068}, // f13 + {0x000000c0, 0x00070069}, // f14 + {0x000000c1, 0x0007006a}, // f15 + {0x000000c2, 0x0007006b}, // f16 + {0x000000c3, 0x0007006c}, // f17 + {0x000000c4, 0x0007006d}, // f18 + {0x000000c5, 0x0007006e}, // f19 + {0x000000c6, 0x0007006f}, // f20 + {0x000000c7, 0x00070070}, // f21 + {0x000000c8, 0x00070071}, // f22 + {0x000000c9, 0x00070072}, // f23 + {0x000000ca, 0x00070073}, // f24 + {0x000000d1, 0x000c00b1}, // mediaPause + {0x000000d6, 0x000c0203}, // close + {0x000000d7, 0x000c00b0}, // mediaPlay + {0x000000d8, 0x000c00b3}, // mediaFastForward + {0x000000d9, 0x000c00e5}, // bassBoost + {0x000000da, 0x000c0208}, // print + {0x000000e1, 0x000c0221}, // browserSearch + {0x000000e8, 0x000c0070}, // brightnessDown + {0x000000e9, 0x000c006f}, // brightnessUp + {0x000000eb, 0x000100b5}, // displayToggleIntExt + {0x000000ed, 0x000c007a}, // kbdIllumDown + {0x000000ee, 0x000c0079}, // kbdIllumUp + {0x000000ef, 0x000c028c}, // mailSend + {0x000000f0, 0x000c0289}, // mailReply + {0x000000f1, 0x000c028b}, // mailForward + {0x000000f2, 0x000c0207}, // save + {0x000000f3, 0x000c01a7}, // launchDocuments + {0x000000fc, 0x000c0075}, // brightnessAuto + {0x0000016e, 0x000c0060}, // info + {0x00000172, 0x000c008d}, // programGuide + {0x0000017a, 0x000c0061}, // closedCaptionToggle + {0x0000017c, 0x000c0232}, // zoomToggle + {0x0000017e, 0x000c01ae}, // launchKeyboardLayout + {0x00000190, 0x000c01b7}, // launchAudioBrowser + {0x00000195, 0x000c018e}, // launchCalendar + {0x0000019d, 0x000c0083}, // mediaLast + {0x000001a2, 0x000c009c}, // channelUp + {0x000001a3, 0x000c009d}, // channelDown + {0x000001aa, 0x000c022d}, // zoomIn + {0x000001ab, 0x000c022e}, // zoomOut + {0x000001ad, 0x000c0184}, // launchWordProcessor + {0x000001af, 0x000c0186}, // launchSpreadsheet + {0x000001b5, 0x000c018d}, // launchContacts + {0x000001b7, 0x000c0072}, // brightnessToggle + {0x000001b8, 0x000c01ab}, // spellCheck + {0x000001b9, 0x000c019c}, // logOff + {0x0000024b, 0x000c019f}, // launchControlPanel + {0x0000024c, 0x000c01a2}, // selectTask + {0x0000024d, 0x000c01b1}, // launchScreenSaver + {0x0000024e, 0x000c00cf}, // speechInputToggle + {0x0000024f, 0x000c01cb}, // launchAssistant + {0x00000250, 0x000c029d}, // keyboardLayoutSelect + {0x00000258, 0x000c0073}, // brightnessMinimum + {0x00000259, 0x000c0074}, // brightnessMaximum + {0x00000281, 0x00000017}, // privacyScreenToggle +}; -void initialize_gtk_keyval_to_logical_key(GHashTable* table) { - {0x000000a5, 0x01100070089}, // yen - {0x0000fd06, 0x01000000405}, // 3270_EraseEOF - {0x0000fd0e, 0x01000000503}, // 3270_Attn - {0x0000fd15, 0x01000000402}, // 3270_Copy - {0x0000fd16, 0x01000000d2f}, // 3270_Play - {0x0000fd1b, 0x01000000406}, // 3270_ExSelect - {0x0000fd1d, 0x01000000608}, // 3270_PrintScreen - {0x0000fd1e, 0x0100000000d}, // 3270_Enter - {0x0000fe03, 0x40000000102}, // ISO_Level3_Shift - {0x0000fe08, 0x01000000709}, // ISO_Next_Group - {0x0000fe0a, 0x0100000070a}, // ISO_Prev_Group - {0x0000fe0c, 0x01000000707}, // ISO_First_Group - {0x0000fe0e, 0x01000000708}, // ISO_Last_Group - {0x0000fe20, 0x01000000009}, // ISO_Left_Tab - {0x0000fe34, 0x0100000000d}, // ISO_Enter - {0x0000ff08, 0x01000000008}, // BackSpace - {0x0000ff09, 0x01000000009}, // Tab - {0x0000ff0b, 0x01000000401}, // Clear - {0x0000ff0d, 0x0100000000d}, // Return - {0x0000ff13, 0x01000000509}, // Pause - {0x0000ff14, 0x0100000010c}, // Scroll_Lock - {0x0000ff1b, 0x0100000001b}, // Escape - {0x0000ff21, 0x01000000719}, // Kanji - {0x0000ff24, 0x0100000071b}, // Romaji - {0x0000ff25, 0x01000000716}, // Hiragana - {0x0000ff26, 0x0100000071a}, // Katakana - {0x0000ff27, 0x01000000717}, // Hiragana_Katakana - {0x0000ff28, 0x0100000071c}, // Zenkaku - {0x0000ff29, 0x01000000715}, // Hankaku - {0x0000ff2a, 0x0100000071d}, // Zenkaku_Hankaku - {0x0000ff2f, 0x01000000714}, // Eisu_Shift - {0x0000ff31, 0x01000000711}, // Hangul - {0x0000ff34, 0x01000000712}, // Hangul_Hanja - {0x0000ff37, 0x01000000703}, // Codeinput - {0x0000ff3c, 0x01000000710}, // SingleCandidate - {0x0000ff3e, 0x0100000070e}, // PreviousCandidate - {0x0000ff50, 0x01000000306}, // Home - {0x0000ff51, 0x01000000302}, // Left - {0x0000ff52, 0x01000000304}, // Up - {0x0000ff53, 0x01000000303}, // Right - {0x0000ff54, 0x01000000301}, // Down - {0x0000ff55, 0x01000000308}, // Page_Up - {0x0000ff56, 0x01000000307}, // Page_Down - {0x0000ff57, 0x01000000305}, // End - {0x0000ff60, 0x0100000050c}, // Select - {0x0000ff61, 0x01000000a0c}, // Print - {0x0000ff62, 0x01000000506}, // Execute - {0x0000ff63, 0x01000000407}, // Insert - {0x0000ff65, 0x0100000040a}, // Undo - {0x0000ff66, 0x01000000409}, // Redo - {0x0000ff67, 0x01000000505}, // Menu - {0x0000ff68, 0x01000000507}, // Find - {0x0000ff69, 0x01000000504}, // Cancel - {0x0000ff6a, 0x01000000508}, // Help - {0x0000ff7e, 0x0100000070b}, // Mode_switch - {0x0000ff7f, 0x0100000010a}, // Num_Lock - {0x0000ff80, 0x00000000020}, // KP_Space - {0x0000ff89, 0x01000000009}, // KP_Tab - {0x0000ff8d, 0x5000000000d}, // KP_Enter - {0x0000ff91, 0x01000000801}, // KP_F1 - {0x0000ff92, 0x01000000802}, // KP_F2 - {0x0000ff93, 0x01000000803}, // KP_F3 - {0x0000ff94, 0x01000000804}, // KP_F4 - {0x0000ff95, 0x50000000037}, // KP_Home - {0x0000ff96, 0x50000000034}, // KP_Left - {0x0000ff97, 0x50000000038}, // KP_Up - {0x0000ff98, 0x50000000036}, // KP_Right - {0x0000ff99, 0x50000000032}, // KP_Down - {0x0000ff9a, 0x50000000039}, // KP_Page_Up - {0x0000ff9b, 0x50000000033}, // KP_Page_Down - {0x0000ff9c, 0x50000000031}, // KP_End - {0x0000ff9e, 0x50000000030}, // KP_Insert - {0x0000ff9f, 0x5000000002e}, // KP_Delete - {0x0000ffaa, 0x5000000002a}, // KP_Multiply - {0x0000ffab, 0x5000000002b}, // KP_Add - {0x0000ffad, 0x5000000002d}, // KP_Subtract - {0x0000ffae, 0x0000000002e}, // KP_Decimal - {0x0000ffaf, 0x5000000002f}, // KP_Divide - {0x0000ffb0, 0x50000000030}, // KP_0 - {0x0000ffb1, 0x50000000031}, // KP_1 - {0x0000ffb2, 0x50000000032}, // KP_2 - {0x0000ffb3, 0x50000000033}, // KP_3 - {0x0000ffb4, 0x50000000034}, // KP_4 - {0x0000ffb5, 0x50000000035}, // KP_5 - {0x0000ffb6, 0x50000000036}, // KP_6 - {0x0000ffb7, 0x50000000037}, // KP_7 - {0x0000ffb8, 0x50000000038}, // KP_8 - {0x0000ffb9, 0x50000000039}, // KP_9 - {0x0000ffbd, 0x5000000003d}, // KP_Equal - {0x0000ffbe, 0x01000000801}, // F1 - {0x0000ffbf, 0x01000000802}, // F2 - {0x0000ffc0, 0x01000000803}, // F3 - {0x0000ffc1, 0x01000000804}, // F4 - {0x0000ffc2, 0x01000000805}, // F5 - {0x0000ffc3, 0x01000000806}, // F6 - {0x0000ffc4, 0x01000000807}, // F7 - {0x0000ffc5, 0x01000000808}, // F8 - {0x0000ffc6, 0x01000000809}, // F9 - {0x0000ffc7, 0x0100000080a}, // F10 - {0x0000ffc8, 0x0100000080b}, // F11 - {0x0000ffc9, 0x0100000080c}, // F12 - {0x0000ffca, 0x0100000080d}, // F13 - {0x0000ffcb, 0x0100000080e}, // F14 - {0x0000ffcc, 0x0100000080f}, // F15 - {0x0000ffcd, 0x01000000810}, // F16 - {0x0000ffce, 0x01000000811}, // F17 - {0x0000ffcf, 0x01000000812}, // F18 - {0x0000ffd0, 0x01000000813}, // F19 - {0x0000ffd1, 0x01000000814}, // F20 - {0x0000ffd2, 0x01000000815}, // F21 - {0x0000ffd3, 0x01000000816}, // F22 - {0x0000ffd4, 0x01000000817}, // F23 - {0x0000ffd5, 0x01000000818}, // F24 - {0x0000ffe1, 0x3000000010d}, // Shift_L - {0x0000ffe2, 0x4000000010d}, // Shift_R - {0x0000ffe3, 0x30000000105}, // Control_L - {0x0000ffe4, 0x40000000105}, // Control_R - {0x0000ffe5, 0x01000000104}, // Caps_Lock - {0x0000ffe7, 0x30000000109}, // Meta_L - {0x0000ffe8, 0x40000000109}, // Meta_R - {0x0000ffe9, 0x30000000102}, // Alt_L - {0x0000ffea, 0x40000000102}, // Alt_R - {0x0000ffeb, 0x0100000010e}, // Super_L - {0x0000ffec, 0x0100000010e}, // Super_R - {0x0000ffed, 0x01000000108}, // Hyper_L - {0x0000ffee, 0x01000000108}, // Hyper_R - {0x0000ffff, 0x0100000007f}, // Delete - {0x1008ff02, 0x01000000602}, // MonBrightnessUp - {0x1008ff03, 0x01000000601}, // MonBrightnessDown - {0x1008ff10, 0x0100000060a}, // Standby - {0x1008ff11, 0x01000000a0f}, // AudioLowerVolume - {0x1008ff12, 0x01000000a11}, // AudioMute - {0x1008ff13, 0x01000000a10}, // AudioRaiseVolume - {0x1008ff14, 0x01000000d2f}, // AudioPlay - {0x1008ff15, 0x01000000a07}, // AudioStop - {0x1008ff16, 0x01000000a09}, // AudioPrev - {0x1008ff17, 0x01000000a08}, // AudioNext - {0x1008ff18, 0x01000000c04}, // HomePage - {0x1008ff19, 0x01000000b03}, // Mail - {0x1008ff1b, 0x01000000c06}, // Search - {0x1008ff1c, 0x01000000d30}, // AudioRecord - {0x1008ff20, 0x01000000b02}, // Calendar - {0x1008ff26, 0x01000000c01}, // Back - {0x1008ff27, 0x01000000c03}, // Forward - {0x1008ff28, 0x01000000c07}, // Stop - {0x1008ff29, 0x01000000c05}, // Refresh - {0x1008ff2a, 0x01000000607}, // PowerOff - {0x1008ff2b, 0x0100000060b}, // WakeUp - {0x1008ff2c, 0x01000000604}, // Eject - {0x1008ff2d, 0x01000000b07}, // ScreenSaver - {0x1008ff2f, 0x01100010082}, // Sleep - {0x1008ff30, 0x01000000c02}, // Favorites - {0x1008ff31, 0x01000000d2e}, // AudioPause - {0x1008ff3e, 0x01000000d31}, // AudioRewind - {0x1008ff56, 0x01000000a01}, // Close - {0x1008ff57, 0x01000000402}, // Copy - {0x1008ff58, 0x01000000404}, // Cut - {0x1008ff61, 0x01000000605}, // LogOff - {0x1008ff68, 0x01000000a0a}, // New - {0x1008ff6b, 0x01000000a0b}, // Open - {0x1008ff6d, 0x01000000408}, // Paste - {0x1008ff6e, 0x01000000b0d}, // Phone - {0x1008ff72, 0x01000000a03}, // Reply - {0x1008ff77, 0x01000000a0d}, // Save - {0x1008ff7b, 0x01000000a04}, // Send - {0x1008ff7c, 0x01000000a0e}, // Spell - {0x1008ff8b, 0x0100000050d}, // ZoomIn - {0x1008ff8c, 0x0100000050e}, // ZoomOut - {0x1008ff90, 0x01000000a02}, // MailForward - {0x1008ff97, 0x01000000d2c}, // AudioForward - {0x1008ffa7, 0x01100000014}, // Suspend -} +std::map gtk_keyval_to_logical_key_map = { + {0x000000a5, 0x01100070089}, // yen + {0x0000fd06, 0x01000000405}, // 3270_EraseEOF + {0x0000fd0e, 0x01000000503}, // 3270_Attn + {0x0000fd15, 0x01000000402}, // 3270_Copy + {0x0000fd16, 0x01000000d2f}, // 3270_Play + {0x0000fd1b, 0x01000000406}, // 3270_ExSelect + {0x0000fd1d, 0x01000000608}, // 3270_PrintScreen + {0x0000fd1e, 0x0100000000d}, // 3270_Enter + {0x0000fe03, 0x40000000102}, // ISO_Level3_Shift + {0x0000fe08, 0x01000000709}, // ISO_Next_Group + {0x0000fe0a, 0x0100000070a}, // ISO_Prev_Group + {0x0000fe0c, 0x01000000707}, // ISO_First_Group + {0x0000fe0e, 0x01000000708}, // ISO_Last_Group + {0x0000fe20, 0x01000000009}, // ISO_Left_Tab + {0x0000fe34, 0x0100000000d}, // ISO_Enter + {0x0000ff08, 0x01000000008}, // BackSpace + {0x0000ff09, 0x01000000009}, // Tab + {0x0000ff0b, 0x01000000401}, // Clear + {0x0000ff0d, 0x0100000000d}, // Return + {0x0000ff13, 0x01000000509}, // Pause + {0x0000ff14, 0x0100000010c}, // Scroll_Lock + {0x0000ff1b, 0x0100000001b}, // Escape + {0x0000ff21, 0x01000000719}, // Kanji + {0x0000ff24, 0x0100000071b}, // Romaji + {0x0000ff25, 0x01000000716}, // Hiragana + {0x0000ff26, 0x0100000071a}, // Katakana + {0x0000ff27, 0x01000000717}, // Hiragana_Katakana + {0x0000ff28, 0x0100000071c}, // Zenkaku + {0x0000ff29, 0x01000000715}, // Hankaku + {0x0000ff2a, 0x0100000071d}, // Zenkaku_Hankaku + {0x0000ff2f, 0x01000000714}, // Eisu_Shift + {0x0000ff31, 0x01000000711}, // Hangul + {0x0000ff34, 0x01000000712}, // Hangul_Hanja + {0x0000ff37, 0x01000000703}, // Codeinput + {0x0000ff3c, 0x01000000710}, // SingleCandidate + {0x0000ff3e, 0x0100000070e}, // PreviousCandidate + {0x0000ff50, 0x01000000306}, // Home + {0x0000ff51, 0x01000000302}, // Left + {0x0000ff52, 0x01000000304}, // Up + {0x0000ff53, 0x01000000303}, // Right + {0x0000ff54, 0x01000000301}, // Down + {0x0000ff55, 0x01000000308}, // Page_Up + {0x0000ff56, 0x01000000307}, // Page_Down + {0x0000ff57, 0x01000000305}, // End + {0x0000ff60, 0x0100000050c}, // Select + {0x0000ff61, 0x01000000a0c}, // Print + {0x0000ff62, 0x01000000506}, // Execute + {0x0000ff63, 0x01000000407}, // Insert + {0x0000ff65, 0x0100000040a}, // Undo + {0x0000ff66, 0x01000000409}, // Redo + {0x0000ff67, 0x01000000505}, // Menu + {0x0000ff68, 0x01000000507}, // Find + {0x0000ff69, 0x01000000504}, // Cancel + {0x0000ff6a, 0x01000000508}, // Help + {0x0000ff7e, 0x0100000070b}, // Mode_switch + {0x0000ff7f, 0x0100000010a}, // Num_Lock + {0x0000ff80, 0x00000000020}, // KP_Space + {0x0000ff89, 0x01000000009}, // KP_Tab + {0x0000ff8d, 0x5000000000d}, // KP_Enter + {0x0000ff91, 0x01000000801}, // KP_F1 + {0x0000ff92, 0x01000000802}, // KP_F2 + {0x0000ff93, 0x01000000803}, // KP_F3 + {0x0000ff94, 0x01000000804}, // KP_F4 + {0x0000ff95, 0x50000000037}, // KP_Home + {0x0000ff96, 0x50000000034}, // KP_Left + {0x0000ff97, 0x50000000038}, // KP_Up + {0x0000ff98, 0x50000000036}, // KP_Right + {0x0000ff99, 0x50000000032}, // KP_Down + {0x0000ff9a, 0x50000000039}, // KP_Page_Up + {0x0000ff9b, 0x50000000033}, // KP_Page_Down + {0x0000ff9c, 0x50000000031}, // KP_End + {0x0000ff9e, 0x50000000030}, // KP_Insert + {0x0000ff9f, 0x5000000002e}, // KP_Delete + {0x0000ffaa, 0x5000000002a}, // KP_Multiply + {0x0000ffab, 0x5000000002b}, // KP_Add + {0x0000ffad, 0x5000000002d}, // KP_Subtract + {0x0000ffae, 0x0000000002e}, // KP_Decimal + {0x0000ffaf, 0x5000000002f}, // KP_Divide + {0x0000ffb0, 0x50000000030}, // KP_0 + {0x0000ffb1, 0x50000000031}, // KP_1 + {0x0000ffb2, 0x50000000032}, // KP_2 + {0x0000ffb3, 0x50000000033}, // KP_3 + {0x0000ffb4, 0x50000000034}, // KP_4 + {0x0000ffb5, 0x50000000035}, // KP_5 + {0x0000ffb6, 0x50000000036}, // KP_6 + {0x0000ffb7, 0x50000000037}, // KP_7 + {0x0000ffb8, 0x50000000038}, // KP_8 + {0x0000ffb9, 0x50000000039}, // KP_9 + {0x0000ffbd, 0x5000000003d}, // KP_Equal + {0x0000ffbe, 0x01000000801}, // F1 + {0x0000ffbf, 0x01000000802}, // F2 + {0x0000ffc0, 0x01000000803}, // F3 + {0x0000ffc1, 0x01000000804}, // F4 + {0x0000ffc2, 0x01000000805}, // F5 + {0x0000ffc3, 0x01000000806}, // F6 + {0x0000ffc4, 0x01000000807}, // F7 + {0x0000ffc5, 0x01000000808}, // F8 + {0x0000ffc6, 0x01000000809}, // F9 + {0x0000ffc7, 0x0100000080a}, // F10 + {0x0000ffc8, 0x0100000080b}, // F11 + {0x0000ffc9, 0x0100000080c}, // F12 + {0x0000ffca, 0x0100000080d}, // F13 + {0x0000ffcb, 0x0100000080e}, // F14 + {0x0000ffcc, 0x0100000080f}, // F15 + {0x0000ffcd, 0x01000000810}, // F16 + {0x0000ffce, 0x01000000811}, // F17 + {0x0000ffcf, 0x01000000812}, // F18 + {0x0000ffd0, 0x01000000813}, // F19 + {0x0000ffd1, 0x01000000814}, // F20 + {0x0000ffd2, 0x01000000815}, // F21 + {0x0000ffd3, 0x01000000816}, // F22 + {0x0000ffd4, 0x01000000817}, // F23 + {0x0000ffd5, 0x01000000818}, // F24 + {0x0000ffe1, 0x3000000010d}, // Shift_L + {0x0000ffe2, 0x4000000010d}, // Shift_R + {0x0000ffe3, 0x30000000105}, // Control_L + {0x0000ffe4, 0x40000000105}, // Control_R + {0x0000ffe5, 0x01000000104}, // Caps_Lock + {0x0000ffe7, 0x30000000109}, // Meta_L + {0x0000ffe8, 0x40000000109}, // Meta_R + {0x0000ffe9, 0x30000000102}, // Alt_L + {0x0000ffea, 0x40000000102}, // Alt_R + {0x0000ffeb, 0x0100000010e}, // Super_L + {0x0000ffec, 0x0100000010e}, // Super_R + {0x0000ffed, 0x01000000108}, // Hyper_L + {0x0000ffee, 0x01000000108}, // Hyper_R + {0x0000ffff, 0x0100000007f}, // Delete + {0x1008ff02, 0x01000000602}, // MonBrightnessUp + {0x1008ff03, 0x01000000601}, // MonBrightnessDown + {0x1008ff10, 0x0100000060a}, // Standby + {0x1008ff11, 0x01000000a0f}, // AudioLowerVolume + {0x1008ff12, 0x01000000a11}, // AudioMute + {0x1008ff13, 0x01000000a10}, // AudioRaiseVolume + {0x1008ff14, 0x01000000d2f}, // AudioPlay + {0x1008ff15, 0x01000000a07}, // AudioStop + {0x1008ff16, 0x01000000a09}, // AudioPrev + {0x1008ff17, 0x01000000a08}, // AudioNext + {0x1008ff18, 0x01000000c04}, // HomePage + {0x1008ff19, 0x01000000b03}, // Mail + {0x1008ff1b, 0x01000000c06}, // Search + {0x1008ff1c, 0x01000000d30}, // AudioRecord + {0x1008ff20, 0x01000000b02}, // Calendar + {0x1008ff26, 0x01000000c01}, // Back + {0x1008ff27, 0x01000000c03}, // Forward + {0x1008ff28, 0x01000000c07}, // Stop + {0x1008ff29, 0x01000000c05}, // Refresh + {0x1008ff2a, 0x01000000607}, // PowerOff + {0x1008ff2b, 0x0100000060b}, // WakeUp + {0x1008ff2c, 0x01000000604}, // Eject + {0x1008ff2d, 0x01000000b07}, // ScreenSaver + {0x1008ff2f, 0x01100010082}, // Sleep + {0x1008ff30, 0x01000000c02}, // Favorites + {0x1008ff31, 0x01000000d2e}, // AudioPause + {0x1008ff3e, 0x01000000d31}, // AudioRewind + {0x1008ff56, 0x01000000a01}, // Close + {0x1008ff57, 0x01000000402}, // Copy + {0x1008ff58, 0x01000000404}, // Cut + {0x1008ff61, 0x01000000605}, // LogOff + {0x1008ff68, 0x01000000a0a}, // New + {0x1008ff6b, 0x01000000a0b}, // Open + {0x1008ff6d, 0x01000000408}, // Paste + {0x1008ff6e, 0x01000000b0d}, // Phone + {0x1008ff72, 0x01000000a03}, // Reply + {0x1008ff77, 0x01000000a0d}, // Save + {0x1008ff7b, 0x01000000a04}, // Send + {0x1008ff7c, 0x01000000a0e}, // Spell + {0x1008ff8b, 0x0100000050d}, // ZoomIn + {0x1008ff8c, 0x0100000050e}, // ZoomOut + {0x1008ff90, 0x01000000a02}, // MailForward + {0x1008ff97, 0x01000000d2c}, // AudioForward + {0x1008ffa7, 0x01100000014}, // Suspend +}; void initialize_modifier_bit_to_checked_keys(GHashTable* table) { FlKeyEmbedderCheckedKey* data; @@ -598,30 +416,30 @@ void initialize_modifier_bit_to_checked_keys(GHashTable* table) { data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_SHIFT_MASK), data); data->is_caps_lock = false; - data->primary_logical_key = 0x3000000010d; // shiftLeft - data->primary_physical_key = 0x0000700e1; // shiftLeft - data->secondary_physical_key = 0x0000700e5; // shiftRight + data->primary_physical_key = 0x0000700e1; // shiftLeft + data->primary_logical_key = 0x3000000010d; // shiftLeft + data->secondary_logical_key = 0x4000000010d; // shiftRight data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_CONTROL_MASK), data); data->is_caps_lock = false; - data->primary_logical_key = 0x30000000105; // controlLeft - data->primary_physical_key = 0x0000700e0; // controlLeft - data->secondary_physical_key = 0x0000700e4; // controlRight + data->primary_physical_key = 0x0000700e0; // controlLeft + data->primary_logical_key = 0x30000000105; // controlLeft + data->secondary_logical_key = 0x40000000105; // controlRight data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_MOD1_MASK), data); data->is_caps_lock = false; - data->primary_logical_key = 0x30000000102; // altLeft - data->primary_physical_key = 0x0000700e2; // altLeft - data->secondary_physical_key = 0x0000700e6; // altRight + data->primary_physical_key = 0x0000700e2; // altLeft + data->primary_logical_key = 0x30000000102; // altLeft + data->secondary_logical_key = 0x40000000102; // altRight data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_META_MASK), data); data->is_caps_lock = false; - data->primary_logical_key = 0x30000000109; // metaLeft - data->primary_physical_key = 0x0000700e3; // metaLeft - data->secondary_physical_key = 0x0000700e7; // metaRight + data->primary_physical_key = 0x0000700e3; // metaLeft + data->primary_logical_key = 0x30000000109; // metaLeft + data->secondary_logical_key = 0x40000000109; // metaRight } void initialize_lock_bit_to_checked_keys(GHashTable* table) { @@ -630,12 +448,12 @@ void initialize_lock_bit_to_checked_keys(GHashTable* table) { data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_LOCK_MASK), data); data->is_caps_lock = true; - data->primary_logical_key = 0x01000000104; // capsLock data->primary_physical_key = 0x000070039; // capsLock + data->primary_logical_key = 0x01000000104; // capsLock data = g_new(FlKeyEmbedderCheckedKey, 1); g_hash_table_insert(table, GUINT_TO_POINTER(GDK_MOD2_MASK), data); data->is_caps_lock = false; - data->primary_logical_key = 0x0100000010a; // numLock data->primary_physical_key = 0x000070053; // numLock + data->primary_logical_key = 0x0100000010a; // numLock } From 45eb2372d8d2340194a5becd5037436865f52dd9 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 17 May 2021 01:10:29 -0700 Subject: [PATCH 087/126] Fix event --- .../linux/fl_key_channel_responder_test.cc | 38 +++++--------- .../linux/fl_key_embedder_responder_test.cc | 50 ++++++++----------- shell/platform/linux/fl_key_event.cc | 25 +++++++++- shell/platform/linux/fl_key_event.h | 20 ++++---- .../linux/fl_keyboard_manager_test.cc | 12 ++--- 5 files changed, 70 insertions(+), 75 deletions(-) diff --git a/shell/platform/linux/fl_key_channel_responder_test.cc b/shell/platform/linux/fl_key_channel_responder_test.cc index 0150fa43ab771..177f5f8f4aff2 100644 --- a/shell/platform/linux/fl_key_channel_responder_test.cc +++ b/shell/platform/linux/fl_key_channel_responder_test.cc @@ -29,31 +29,21 @@ static void responder_callback(bool handled, gpointer user_data) { g_main_loop_quit(static_cast(user_data)); } -namespace { -// A dummy object, whose pointer will be used as _g_key_event->origin. -static int _origin_event; -// A global variable to store new event. It is a global variable so that it can -// be returned by key_event_new for easy use. -static FlKeyEvent _g_key_event; -} // namespace - // Clone string onto the heap. // // If #string is nullptr, returns nullptr. Otherwise, the returned pointer must -// be freed with g_free. The #out_length must not be nullptr, and is used to -// store the length of the string. -static char* clone_string(const char* string, size_t* out_length) { +// be freed with g_free. +static char* clone_string(const char* string) { if (string == nullptr) { - *out_length = 0; return nullptr; } size_t len = strlen(string); char* result = g_new(char, len + 1); strcpy(result, string); - *out_length = len; return result; } +// Create a new #FlKeyEvent with the given information. static FlKeyEvent* fl_key_event_new_by_mock(guint32 time_in_milliseconds, bool is_press, guint keyval, @@ -61,18 +51,16 @@ static FlKeyEvent* fl_key_event_new_by_mock(guint32 time_in_milliseconds, int state, const char* string, gboolean is_modifier) { - if (_g_key_event.string != nullptr) { - g_free(const_cast(_g_key_event.string)); - } - _g_key_event.is_press = is_press; - _g_key_event.time = time_in_milliseconds; - _g_key_event.state = state; - _g_key_event.keyval = keyval; - _g_key_event.string = clone_string(string, &_g_key_event.length); - _g_key_event.keycode = keycode; - _g_key_event.origin = &_origin_event; - _g_key_event.dispose = nullptr; - return &_g_key_event; + FlKeyEvent* event = g_new(FlKeyEvent, 1); + event->is_press = is_press; + event->time = time_in_milliseconds; + event->state = state; + event->keyval = keyval; + event->string = clone_string(string); + event->keycode = keycode; + event->origin = nullptr; + event->dispose_origin = nullptr; + return event; } // Test sending a letter "A"; diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index 6e514535a4973..06e6269f81614 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -72,8 +72,7 @@ static void fl_key_embedder_call_record_dispose(GObject* object) { FlKeyEmbedderCallRecord* self = FL_KEY_EMBEDDER_CALL_RECORD(object); if (self->event != nullptr) { - g_free(const_cast(self->event->character)); - g_free(self->event); + fl_key_event_dispose(self->event); } G_OBJECT_CLASS(fl_key_embedder_call_record_parent_class)->dispose(object); } @@ -93,45 +92,30 @@ static FlKeyEmbedderCallRecord* fl_key_embedder_call_record_new( FlKeyEmbedderCallRecord* self = FL_KEY_EMBEDDER_CALL_RECORD( g_object_new(fl_key_embedder_call_record_get_type(), nullptr)); - FlutterKeyEvent* clone_event = g_new(FlutterKeyEvent, 1); - *clone_event = *event; - if (event->character != nullptr) { - size_t character_length = strlen(event->character); - char* clone_character = g_new(char, character_length + 1); - strcpy(clone_character, event->character); - clone_event->character = clone_character; - } - self->event = clone_event; + self->event = fl_key_event_clone(event); self->callback = callback; self->user_data = user_data; return self; } -namespace { -// A dummy object, whose pointer will be used as _g_key_event->origin. -static int _origin_event; -// A global variable to store new event. It is a global variable so that it can -// be returned by key_event_new for easy use. -FlKeyEvent _g_key_event; -} // namespace - +// Create a new #FlKeyEvent with the given information. static FlKeyEvent* fl_key_event_new_by_mock(guint32 time_in_milliseconds, bool is_press, guint keyval, guint16 keycode, int state, gboolean is_modifier) { - _g_key_event.is_press = is_press; - _g_key_event.time = time_in_milliseconds; - _g_key_event.state = state; - _g_key_event.keyval = keyval; - _g_key_event.length = 0; - _g_key_event.string = nullptr; - _g_key_event.keycode = keycode; - _g_key_event.origin = &_origin_event; - _g_key_event.dispose = nullptr; - return &_g_key_event; + FlKeyEvent* event = g_new(FlKeyEvent, 1); + event->is_press = is_press; + event->time = time_in_milliseconds; + event->state = state; + event->keyval = keyval; + event->string = nullptr; + event->keycode = keycode; + event->origin = nullptr; + event->dispose_origin = nullptr; + return event; } static gboolean g_expected_handled; @@ -154,6 +138,12 @@ namespace { GPtrArray* g_call_records; } +static FlKeyEvent* fl_key_event_clone(FlKeyEvent* event) { + FlKeyEvent* new_event = g_new(FlKeyEvent, 1); + *new_event = *event; + return new_event; +} + static FlEngine* make_mock_engine_with_records() { FlEngine* engine = make_mock_engine(); FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); @@ -161,7 +151,7 @@ static FlEngine* make_mock_engine_with_records() { FlutterKeyEventCallback callback, void* user_data) { g_ptr_array_add(g_call_records, fl_key_embedder_call_record_new( - event, callback, user_data)); + fl_key_event_clone(event), callback, user_data)); return kSuccess; }; diff --git a/shell/platform/linux/fl_key_event.cc b/shell/platform/linux/fl_key_event.cc index e9a4723effc6b..83c1f5e279580 100644 --- a/shell/platform/linux/fl_key_event.cc +++ b/shell/platform/linux/fl_key_event.cc @@ -8,6 +8,16 @@ static void dispose_from_gdk_event(FlKeyEvent* event) { gdk_event_free(reinterpret_cast(event->origin)); } +static const char* clone_string(char* source) { + if (source == nullptr) { + return nullptr; + } + size_t character_length = strlen(event->character); + char* clone_character = g_new(char, character_length + 1); + strcpy(clone_character, event->character); + return clone_character; +} + FlKeyEvent* fl_key_event_new_from_gdk_event(GdkEvent* raw_event) { g_return_val_if_fail(raw_event != nullptr, nullptr); GdkEventKey* event = reinterpret_cast(raw_event); @@ -21,6 +31,7 @@ FlKeyEvent* fl_key_event_new_from_gdk_event(GdkEvent* raw_event) { result->keycode = event->hardware_keycode; result->keyval = event->keyval; result->state = event->state; + result->string = clone_string(event->string); result->origin = event; result->dispose = dispose_from_gdk_event; @@ -28,8 +39,18 @@ FlKeyEvent* fl_key_event_new_from_gdk_event(GdkEvent* raw_event) { } void fl_key_event_dispose(FlKeyEvent* event) { - if (event->dispose != nullptr) { - event->dispose(event); + if (event->string != nullptr) { + g_free(const_cast(event->string)); + } + if (event->dispose_origin != nullptr) { + event->dispose_origin(event->origin); } g_free(event); } + +FlKeyEvent* fl_key_event_clone(const FlKeyEvent* event) { + FlKeyEvent* new_event = g_new(FlKeyEvent, 1); + *new_event = *event; + new_event->string = clone_string(event->string); + return new_event; +} diff --git a/shell/platform/linux/fl_key_event.h b/shell/platform/linux/fl_key_event.h index 6f54be24ba174..38b0d0a99ac3c 100644 --- a/shell/platform/linux/fl_key_event.h +++ b/shell/platform/linux/fl_key_event.h @@ -7,16 +7,14 @@ #include -typedef struct _FlKeyEvent FlKeyEvent; - /** * FlKeyEventDispose: - * @self: the self pointer to dispose. + * @origin: the #FlKeyEvent::origin to dispose. * - * The signature for a callback with which a #FlKeyEvent performs - * before being freed. + * The signature for #FlKeyEvent::dispose_origin, which + * frees #FlKeyEvent::origin. **/ -typedef void (*FlKeyEventDispose)(FlKeyEvent* self); +typedef void (*FlKeyEventDisposeOrigin)(gpointer origin); /** * FlKeyEvent: @@ -40,17 +38,15 @@ typedef struct _FlKeyEvent { // // Can be nullptr. const char* string; - // Length of #string (without the terminating \0). - size_t length; // An opaque pointer to the original event. // // This is used when dispatching. For native events, this is #GdkEvent // pointer. For unit tests, this is a dummy pointer. gpointer origin; - // Extra steps before freeing this #FlKeyEvent. + // A callback to free #origin, called in #fl_key_event_dispose. // - // Usually a function that frees origin. Can be nullptr. - FlKeyEventDispose dispose; + // Can be nullptr. + FlKeyEventDisposeOrigin dispose_origin; } FlKeyEvent; /** @@ -72,4 +68,6 @@ FlKeyEvent* fl_key_event_new_from_gdk_event(GdkEvent* event); */ void fl_key_event_dispose(FlKeyEvent* event); +FlKeyEvent* fl_key_event_clone(const FlKeyEvent* source); + #endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_KEY_EVENT_H_ diff --git a/shell/platform/linux/fl_keyboard_manager_test.cc b/shell/platform/linux/fl_keyboard_manager_test.cc index 010f025870110..7894a5e48e16f 100644 --- a/shell/platform/linux/fl_keyboard_manager_test.cc +++ b/shell/platform/linux/fl_keyboard_manager_test.cc @@ -132,10 +132,9 @@ static void fl_key_mock_responder_iface_init(FlKeyResponderInterface* iface) { // Return a newly allocated #FlKeyEvent that is a clone to the given #event // but with #origin and #dispose set to 0. static FlKeyEvent* fl_key_event_clone_information_only(FlKeyEvent* event) { - FlKeyEvent* new_event = g_new(FlKeyEvent, 1); - *new_event = *event; + FlKeyEvent* new_event = fl_key_event_clone(event); new_event->origin = nullptr; - new_event->dispose = nullptr; + new_event->dispose_origin = nullptr; return new_event; } static void fl_key_mock_responder_handle_event( @@ -175,8 +174,8 @@ static gpointer g_ptr_array_last(GPtrArray* array) { return g_ptr_array_index(array, array->len - 1); } -static void fl_key_event_free_by_mock(FlKeyEvent* event) { - g_free(event->origin); +static void fl_key_event_free_origin_by_mock(gpointer origin) { + g_free(origin); } // Create a new #FlKeyEvent with the given information. // @@ -192,12 +191,11 @@ static FlKeyEvent* fl_key_event_new_by_mock(bool is_press, event->time = 0; event->state = state; event->keyval = keyval; - event->length = 0; event->string = nullptr; event->keycode = keycode; FlKeyEvent* origin_event = fl_key_event_clone_information_only(event); event->origin = origin_event; - event->dispose = fl_key_event_free_by_mock; + event->dispose_origin = fl_key_event_free_origin_by_mock; return event; } From 631a9793e7ebe83971a797801de444d726e103c8 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 17 May 2021 01:23:42 -0700 Subject: [PATCH 088/126] ATP --- .../linux/fl_key_embedder_responder_test.cc | 22 ++++++++++--------- shell/platform/linux/fl_key_event.cc | 17 +++++++------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index 06e6269f81614..2c4a9d6a17b8e 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -72,7 +72,8 @@ static void fl_key_embedder_call_record_dispose(GObject* object) { FlKeyEmbedderCallRecord* self = FL_KEY_EMBEDDER_CALL_RECORD(object); if (self->event != nullptr) { - fl_key_event_dispose(self->event); + g_free(const_cast(self->event->character)); + g_free(self->event); } G_OBJECT_CLASS(fl_key_embedder_call_record_parent_class)->dispose(object); } @@ -92,7 +93,15 @@ static FlKeyEmbedderCallRecord* fl_key_embedder_call_record_new( FlKeyEmbedderCallRecord* self = FL_KEY_EMBEDDER_CALL_RECORD( g_object_new(fl_key_embedder_call_record_get_type(), nullptr)); - self->event = fl_key_event_clone(event); + FlutterKeyEvent* clone_event = g_new(FlutterKeyEvent, 1); + *clone_event = *event; + if (event->character != nullptr) { + size_t character_length = strlen(event->character); + char* clone_character = g_new(char, character_length + 1); + strcpy(clone_character, event->character); + clone_event->character = clone_character; + } + self->event = clone_event; self->callback = callback; self->user_data = user_data; @@ -138,20 +147,13 @@ namespace { GPtrArray* g_call_records; } -static FlKeyEvent* fl_key_event_clone(FlKeyEvent* event) { - FlKeyEvent* new_event = g_new(FlKeyEvent, 1); - *new_event = *event; - return new_event; -} - static FlEngine* make_mock_engine_with_records() { FlEngine* engine = make_mock_engine(); FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); embedder_api->SendKeyEvent = [](auto engine, const FlutterKeyEvent* event, FlutterKeyEventCallback callback, void* user_data) { - g_ptr_array_add(g_call_records, fl_key_embedder_call_record_new( - fl_key_event_clone(event), callback, user_data)); + g_ptr_array_add(g_call_records, fl_key_embedder_call_record_new(event, callback, user_data)); return kSuccess; }; diff --git a/shell/platform/linux/fl_key_event.cc b/shell/platform/linux/fl_key_event.cc index 83c1f5e279580..b823a3377ae16 100644 --- a/shell/platform/linux/fl_key_event.cc +++ b/shell/platform/linux/fl_key_event.cc @@ -4,18 +4,19 @@ #include "flutter/shell/platform/linux/fl_key_event.h" -static void dispose_from_gdk_event(FlKeyEvent* event) { - gdk_event_free(reinterpret_cast(event->origin)); +static void dispose_origin_from_gdk_event(gpointer origin) { + g_return_if_fail(origin != nullptr); + gdk_event_free(reinterpret_cast(origin)); } -static const char* clone_string(char* source) { +static char* clone_string(const char* source) { if (source == nullptr) { return nullptr; } - size_t character_length = strlen(event->character); - char* clone_character = g_new(char, character_length + 1); - strcpy(clone_character, event->character); - return clone_character; + size_t length = strlen(source); + char* result = g_new(char, length + 1); + strcpy(result, source); + return result; } FlKeyEvent* fl_key_event_new_from_gdk_event(GdkEvent* raw_event) { @@ -33,7 +34,7 @@ FlKeyEvent* fl_key_event_new_from_gdk_event(GdkEvent* raw_event) { result->state = event->state; result->string = clone_string(event->string); result->origin = event; - result->dispose = dispose_from_gdk_event; + result->dispose_origin = dispose_origin_from_gdk_event; return result; } From 7da46cd023fc103373ae393d84c2b73a76aaa3f6 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 17 May 2021 01:26:23 -0700 Subject: [PATCH 089/126] Format --- shell/platform/linux/fl_key_embedder_responder_test.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index 2c4a9d6a17b8e..5386076783b07 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -153,7 +153,8 @@ static FlEngine* make_mock_engine_with_records() { embedder_api->SendKeyEvent = [](auto engine, const FlutterKeyEvent* event, FlutterKeyEventCallback callback, void* user_data) { - g_ptr_array_add(g_call_records, fl_key_embedder_call_record_new(event, callback, user_data)); + g_ptr_array_add(g_call_records, fl_key_embedder_call_record_new( + event, callback, user_data)); return kSuccess; }; From 9ffccfdbe60292db23c6de7725f4450be0027c96 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 17 May 2021 02:44:08 -0700 Subject: [PATCH 090/126] Dont release textinput --- shell/platform/linux/fl_keyboard_manager.cc | 14 ++++--------- shell/platform/linux/fl_keyboard_manager.h | 3 ++- .../linux/fl_keyboard_manager_test.cc | 20 +++++++++++-------- 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/shell/platform/linux/fl_keyboard_manager.cc b/shell/platform/linux/fl_keyboard_manager.cc index 4c25f1cf90ae1..ad3dc7f6d102c 100644 --- a/shell/platform/linux/fl_keyboard_manager.cc +++ b/shell/platform/linux/fl_keyboard_manager.cc @@ -314,16 +314,10 @@ static void responder_handle_event_callback(bool handled, gpointer removed = g_ptr_array_remove_index_fast(self->pending_responds, result_index); g_return_if_fail(removed == pending); - bool should_redispatch = false; - if (!pending->any_handled) { - // If no responders have handled, send it to text plugin. - if (self->text_input_plugin == nullptr || - !fl_text_input_plugin_filter_keypress(self->text_input_plugin, - pending->event)) { - // If text plugin doesn't handle either, redispatch. - should_redispatch = true; - } - } + bool should_redispatch = + !pending->any_handled && (self->text_input_plugin == nullptr || + !fl_text_input_plugin_filter_keypress( + self->text_input_plugin, pending->event)); if (should_redispatch) { g_ptr_array_add(self->pending_redispatches, pending); self->redispatch_callback(pending->event->origin); diff --git a/shell/platform/linux/fl_keyboard_manager.h b/shell/platform/linux/fl_keyboard_manager.h index 6325942355623..23eef64b5eeca 100644 --- a/shell/platform/linux/fl_keyboard_manager.h +++ b/shell/platform/linux/fl_keyboard_manager.h @@ -58,7 +58,8 @@ G_DECLARE_FINAL_TYPE(FlKeyboardManager, /** * fl_keyboard_manager_new: * @text_input_plugin: the #FlTextInputPlugin to send key events to if the - * framework doesn't handle them. + * framework doesn't handle them. This object will be managed and freed by + * #FlKeyboardManager. * @redispatch_callback: how the events should be sent if no processing * objects handle the event. Typically a function that calls #gdk_event_put * on #FlKeyEvent::origin. diff --git a/shell/platform/linux/fl_keyboard_manager_test.cc b/shell/platform/linux/fl_keyboard_manager_test.cc index 7894a5e48e16f..b822f30e52d04 100644 --- a/shell/platform/linux/fl_keyboard_manager_test.cc +++ b/shell/platform/linux/fl_keyboard_manager_test.cc @@ -180,7 +180,7 @@ static void fl_key_event_free_origin_by_mock(gpointer origin) { // Create a new #FlKeyEvent with the given information. // // The #origin will be another #FlKeyEvent with the exact information, -// so that it can be used to redispatch, and is freed by #dispose. +// so that it can be used to redispatch, and is freed upon disposal. static FlKeyEvent* fl_key_event_new_by_mock(bool is_press, guint keyval, guint16 keycode, @@ -312,6 +312,8 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) { record->callback(true, record->user_data); g_ptr_array_clear(redispatched_events()); + EXPECT_TRUE(fl_keyboard_manager_is_state_clear(manager)); + g_ptr_array_clear(call_records); } TEST(FlKeyboardManagerTest, SingleDelegateWithSyncResponds) { @@ -367,6 +369,7 @@ TEST(FlKeyboardManagerTest, SingleDelegateWithSyncResponds) { EXPECT_TRUE(fl_keyboard_manager_is_state_clear(manager)); g_ptr_array_clear(redispatched_events()); + g_ptr_array_clear(call_records); } TEST(FlKeyboardManagerTest, WithTwoAsyncDelegates) { @@ -441,10 +444,10 @@ TEST(FlKeyboardManagerTest, TextInputPluginReturnsFalse) { gboolean manager_handled = false; // The text input plugin doesn't handle events. - g_autoptr(FlMockTextInputPlugin) text_input_plugin = - fl_mock_text_input_plugin_new(filter_keypress_returns_false); g_autoptr(FlKeyboardManager) manager = fl_keyboard_manager_new( - FL_TEXT_INPUT_PLUGIN(text_input_plugin), store_redispatched_event); + FL_TEXT_INPUT_PLUGIN( + fl_mock_text_input_plugin_new(filter_keypress_returns_false)), + store_redispatched_event); // The responder never handles events. FlKeyMockResponder* responder = fl_key_mock_responder_new(call_records, 1); @@ -466,17 +469,17 @@ TEST(FlKeyboardManagerTest, TextInputPluginReturnsFalse) { g_ptr_array_clear(redispatched_events()); EXPECT_TRUE(fl_keyboard_manager_is_state_clear(manager)); + g_ptr_array_clear(call_records); } TEST(FlKeyboardManagerTest, TextInputPluginReturnsTrue) { GPtrArray* call_records = g_ptr_array_new_with_free_func(g_object_unref); gboolean manager_handled = false; - // The text input plugin handles events. - g_autoptr(FlMockTextInputPlugin) text_input_plugin = - fl_mock_text_input_plugin_new(filter_keypress_returns_true); g_autoptr(FlKeyboardManager) manager = fl_keyboard_manager_new( - FL_TEXT_INPUT_PLUGIN(text_input_plugin), store_redispatched_event); + FL_TEXT_INPUT_PLUGIN( + fl_mock_text_input_plugin_new(filter_keypress_returns_true)), + store_redispatched_event); // The responder never handles events. FlKeyMockResponder* responder = fl_key_mock_responder_new(call_records, 1); @@ -492,6 +495,7 @@ TEST(FlKeyboardManagerTest, TextInputPluginReturnsTrue) { EXPECT_EQ(redispatched_events()->len, 0u); EXPECT_TRUE(fl_keyboard_manager_is_state_clear(manager)); + g_ptr_array_clear(call_records); } } // namespace From 34de759f54952906968406703f9feda63e4ac9f6 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 17 May 2021 04:00:34 -0700 Subject: [PATCH 091/126] Remove duplicate clone --- shell/platform/linux/fl_key_embedder_responder_test.cc | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index 06e6269f81614..cfd665846a3c1 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -138,20 +138,13 @@ namespace { GPtrArray* g_call_records; } -static FlKeyEvent* fl_key_event_clone(FlKeyEvent* event) { - FlKeyEvent* new_event = g_new(FlKeyEvent, 1); - *new_event = *event; - return new_event; -} - static FlEngine* make_mock_engine_with_records() { FlEngine* engine = make_mock_engine(); FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); embedder_api->SendKeyEvent = [](auto engine, const FlutterKeyEvent* event, FlutterKeyEventCallback callback, void* user_data) { - g_ptr_array_add(g_call_records, fl_key_embedder_call_record_new( - fl_key_event_clone(event), callback, user_data)); + g_ptr_array_add(g_call_records, fl_key_embedder_call_record_new(event, callback, user_data)); return kSuccess; }; From af817fbd46f32e148891997d587f1cc43e92e177 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 17 May 2021 04:07:36 -0700 Subject: [PATCH 092/126] Clear more pointers --- shell/platform/linux/fl_key_embedder_responder.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index 3bafe66b980e2..8987d3d8aee5e 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -221,8 +221,10 @@ static void fl_key_embedder_responder_dispose(GObject* object) { FlKeyEmbedderResponder* self = FL_KEY_EMBEDDER_RESPONDER(object); g_clear_pointer(&self->pressing_records, g_hash_table_unref); + g_clear_pointer(&self->mapping_records, g_hash_table_unref); g_clear_pointer(&self->modifier_bit_to_checked_keys, g_hash_table_unref); g_clear_pointer(&self->lock_bit_to_checked_keys, g_hash_table_unref); + g_clear_pointer(&self->logical_key_to_lock_bit, g_hash_table_unref); G_OBJECT_CLASS(fl_key_embedder_responder_parent_class)->dispose(object); } From ea885384850f4fee7114cc179160aa66392736a3 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 17 May 2021 05:01:28 -0700 Subject: [PATCH 093/126] Stricter check --- shell/platform/linux/fl_key_embedder_responder.cc | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index 8987d3d8aee5e..12fdd0707dd43 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -326,16 +326,13 @@ static char* event_to_character(const FlKeyEvent* event) { static void handle_response(bool handled, gpointer user_data) { g_autoptr(FlKeyEmbedderUserData) data = FL_KEY_EMBEDDER_USER_DATA(user_data); + g_return_if_fail(data->callback != nullptr); + // Return if the weak pointer has been destroyed. if (data->responder == nullptr) { return; } - // Return if callback is not requested (happens for synthesized events). - if (data->callback == nullptr) { - return; - } - data->callback(handled, data->user_data); } From c08326bd1a5759a7be369f3fafc020726e88e2d3 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 17 May 2021 05:26:31 -0700 Subject: [PATCH 094/126] Revert to global event --- .../linux/fl_key_channel_responder_test.cc | 33 +++++++++++++------ .../linux/fl_key_embedder_responder_test.cc | 30 +++++++++++------ shell/platform/linux/fl_key_event.h | 9 +++-- 3 files changed, 50 insertions(+), 22 deletions(-) diff --git a/shell/platform/linux/fl_key_channel_responder_test.cc b/shell/platform/linux/fl_key_channel_responder_test.cc index 177f5f8f4aff2..cd6812494b8e6 100644 --- a/shell/platform/linux/fl_key_channel_responder_test.cc +++ b/shell/platform/linux/fl_key_channel_responder_test.cc @@ -43,7 +43,18 @@ static char* clone_string(const char* string) { return result; } +namespace { +// A global variable to store new event. It is a global variable so that it can +// be returned by #fl_key_event_new_by_mock for easy use. +FlKeyEvent _g_key_event; +} // namespace + // Create a new #FlKeyEvent with the given information. +// +// This event is passed to #fl_key_responder_handle_event, +// which assumes that the event is managed by callee. +// Therefore #fl_key_event_new_by_mock doesn't need to +// dynamically allocate, but reuses the same global object. static FlKeyEvent* fl_key_event_new_by_mock(guint32 time_in_milliseconds, bool is_press, guint keyval, @@ -51,16 +62,18 @@ static FlKeyEvent* fl_key_event_new_by_mock(guint32 time_in_milliseconds, int state, const char* string, gboolean is_modifier) { - FlKeyEvent* event = g_new(FlKeyEvent, 1); - event->is_press = is_press; - event->time = time_in_milliseconds; - event->state = state; - event->keyval = keyval; - event->string = clone_string(string); - event->keycode = keycode; - event->origin = nullptr; - event->dispose_origin = nullptr; - return event; + if (_g_key_event->string != nullptr) { + g_free(_g_key_event->string); + } + _g_key_event->is_press = is_press; + _g_key_event->time = time_in_milliseconds; + _g_key_event->state = state; + _g_key_event->keyval = keyval; + _g_key_event->string = clone_string(string); + _g_key_event->keycode = keycode; + _g_key_event->origin = nullptr; + _g_key_event->dispose_origin = nullptr; + return &_g_key_event; } // Test sending a letter "A"; diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index 5386076783b07..fa69237a07b77 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -108,23 +108,33 @@ static FlKeyEmbedderCallRecord* fl_key_embedder_call_record_new( return self; } +namespace { +// A global variable to store new event. It is a global variable so that it can +// be returned by #fl_key_event_new_by_mock for easy use. +FlKeyEvent _g_key_event; +} // namespace + // Create a new #FlKeyEvent with the given information. +// +// This event is passed to #fl_key_responder_handle_event, +// which assumes that the event is managed by callee. +// Therefore #fl_key_event_new_by_mock doesn't need to +// dynamically allocate, but reuses the same global object. static FlKeyEvent* fl_key_event_new_by_mock(guint32 time_in_milliseconds, bool is_press, guint keyval, guint16 keycode, int state, gboolean is_modifier) { - FlKeyEvent* event = g_new(FlKeyEvent, 1); - event->is_press = is_press; - event->time = time_in_milliseconds; - event->state = state; - event->keyval = keyval; - event->string = nullptr; - event->keycode = keycode; - event->origin = nullptr; - event->dispose_origin = nullptr; - return event; + _g_key_event.is_press = is_press; + _g_key_event.time = time_in_milliseconds; + _g_key_event.state = state; + _g_key_event.keyval = keyval; + _g_key_event.string = nullptr; + _g_key_event.keycode = keycode; + _g_key_event.origin = nullptr; + _g_key_event.dispose_origin = nullptr; + return &_g_key_event; } static gboolean g_expected_handled; diff --git a/shell/platform/linux/fl_key_event.h b/shell/platform/linux/fl_key_event.h index 38b0d0a99ac3c..2fd6240b240f0 100644 --- a/shell/platform/linux/fl_key_event.h +++ b/shell/platform/linux/fl_key_event.h @@ -20,8 +20,13 @@ typedef void (*FlKeyEventDisposeOrigin)(gpointer origin); * FlKeyEvent: * A struct that stores information from GdkEvent. * - * GDK will stop supporting creating GdkEvent since 4.0. This struct - * is used so that Flutter can create an event object in unittests. + * This is a class only used within the GTK embedding, created by + * FlView and consumed by FlKeyboardManager. It is not sent to + * the embedder. + * + * This object contains information from GdkEvent as well as an origin event + * object, so that Flutter can create an event object in unit tests even after + * migrating to GDK 4.0 which stops supporting creating GdkEvent. */ typedef struct _FlKeyEvent { // Time in milliseconds. From 363aa63f33b2ea45d6de480d8b0b125709a44b0c Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 17 May 2021 05:28:43 -0700 Subject: [PATCH 095/126] Fix tests --- .../linux/fl_key_channel_responder_test.cc | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/shell/platform/linux/fl_key_channel_responder_test.cc b/shell/platform/linux/fl_key_channel_responder_test.cc index cd6812494b8e6..c0fefe5effae0 100644 --- a/shell/platform/linux/fl_key_channel_responder_test.cc +++ b/shell/platform/linux/fl_key_channel_responder_test.cc @@ -62,17 +62,17 @@ static FlKeyEvent* fl_key_event_new_by_mock(guint32 time_in_milliseconds, int state, const char* string, gboolean is_modifier) { - if (_g_key_event->string != nullptr) { - g_free(_g_key_event->string); + if (_g_key_event.string != nullptr) { + g_free(const_cast(_g_key_event.string)); } - _g_key_event->is_press = is_press; - _g_key_event->time = time_in_milliseconds; - _g_key_event->state = state; - _g_key_event->keyval = keyval; - _g_key_event->string = clone_string(string); - _g_key_event->keycode = keycode; - _g_key_event->origin = nullptr; - _g_key_event->dispose_origin = nullptr; + _g_key_event.is_press = is_press; + _g_key_event.time = time_in_milliseconds; + _g_key_event.state = state; + _g_key_event.keyval = keyval; + _g_key_event.string = clone_string(string); + _g_key_event.keycode = keycode; + _g_key_event.origin = nullptr; + _g_key_event.dispose_origin = nullptr; return &_g_key_event; } From ad4bd9f1039fd0a77d5ca1de777bcc4bab8d64b9 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 17 May 2021 16:45:43 -0700 Subject: [PATCH 096/126] Trace everywhere --- .../linux/fl_key_embedder_responder.cc | 23 +++++++ .../linux/fl_key_embedder_responder_test.cc | 68 ++++++++++++++++--- shell/platform/linux/fl_key_event.cc | 13 ++++ 3 files changed, 96 insertions(+), 8 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index 12fdd0707dd43..cfcb1c0f7deb6 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -12,6 +12,15 @@ #include "flutter/shell/platform/linux/fl_key_embedder_responder_private.h" #include "flutter/shell/platform/linux/key_mapping.h" +#define TRACE(x) \ + printf("before "#x"\n");fflush(stdout); \ + x \ + printf("after "#x"\n");fflush(stdout); +#define TRACEI(x, i) \ + printf("before "#x" "#i"\n");fflush(stdout); \ + x \ + printf("after "#x" "#i"\n");fflush(stdout); + // The code prefix for unrecognized keys that are unique to Gtk, generated from // platform-specific codes. constexpr uint64_t kGtkKeyIdPlane = 0x00600000000; @@ -88,9 +97,11 @@ static void fl_key_embedder_user_data_dispose(GObject* object) { g_return_if_fail(FL_IS_KEY_EMBEDDER_USER_DATA(object)); FlKeyEmbedderUserData* self = FL_KEY_EMBEDDER_USER_DATA(object); if (self->responder != nullptr) { + TRACE( g_object_remove_weak_pointer( G_OBJECT(self->responder), reinterpret_cast(&(self->responder))); + ); self->responder = nullptr; } } @@ -220,13 +231,25 @@ static void fl_key_embedder_responder_init(FlKeyEmbedderResponder* self) {} static void fl_key_embedder_responder_dispose(GObject* object) { FlKeyEmbedderResponder* self = FL_KEY_EMBEDDER_RESPONDER(object); + TRACE( g_clear_pointer(&self->pressing_records, g_hash_table_unref); + ); + TRACE( g_clear_pointer(&self->mapping_records, g_hash_table_unref); + ); + TRACE( g_clear_pointer(&self->modifier_bit_to_checked_keys, g_hash_table_unref); + ); + TRACE( g_clear_pointer(&self->lock_bit_to_checked_keys, g_hash_table_unref); + ); + TRACE( g_clear_pointer(&self->logical_key_to_lock_bit, g_hash_table_unref); + ); + TRACE( G_OBJECT_CLASS(fl_key_embedder_responder_parent_class)->dispose(object); + ); } // Fill in #logical_key_to_lock_bit by associating a logical key with diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index fa69237a07b77..59cddebaa3e14 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -11,6 +11,15 @@ #include "flutter/shell/platform/linux/fl_engine_private.h" #include "flutter/shell/platform/linux/testing/fl_test.h" +#define TRACE(x) \ + printf("before "#x"\n");fflush(stdout); \ + x \ + printf("after "#x"\n");fflush(stdout); +#define TRACEI(x, i) \ + printf("before "#x" "#i"\n");fflush(stdout); \ + x \ + printf("after "#x" "#i"\n");fflush(stdout); + namespace { constexpr gboolean kRelease = FALSE; constexpr gboolean kPress = TRUE; @@ -43,7 +52,9 @@ constexpr uint64_t kLogicalCapsLock = 0x1000000104; } // namespace static void g_ptr_array_clear(GPtrArray* array) { + TRACE( g_ptr_array_remove_range(array, 0, array->len); + ); } G_DECLARE_FINAL_TYPE(FlKeyEmbedderCallRecord, @@ -72,8 +83,12 @@ static void fl_key_embedder_call_record_dispose(GObject* object) { FlKeyEmbedderCallRecord* self = FL_KEY_EMBEDDER_CALL_RECORD(object); if (self->event != nullptr) { + TRACE( g_free(const_cast(self->event->character)); + ); + TRACE( g_free(self->event); + ); } G_OBJECT_CLASS(fl_key_embedder_call_record_parent_class)->dispose(object); } @@ -173,7 +188,9 @@ static FlEngine* make_mock_engine_with_records() { } static void clear_g_call_records() { + TRACE( g_ptr_array_free(g_call_records, TRUE); + ); g_call_records = nullptr; } @@ -694,8 +711,8 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); - g_autoptr(FlEngine) engine = make_mock_engine_with_records(); - g_autoptr(FlKeyResponder) responder = + FlEngine* engine = make_mock_engine_with_records(); + FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); int user_data = 123; // Arbitrary user data @@ -717,7 +734,9 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); + TRACEI( g_ptr_array_clear(g_call_records); + ,1); // Press CapsLock (stage 0 -> 1) fl_key_responder_handle_event( @@ -735,7 +754,9 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); + TRACEI( g_ptr_array_clear(g_call_records); + ,2); // Release CapsLock (stage 1 -> 2) fl_key_responder_handle_event( @@ -753,7 +774,9 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); + TRACEI( g_ptr_array_clear(g_call_records); + ,3); // Release key A (stage 2) fl_key_responder_handle_event( @@ -771,7 +794,9 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); + TRACEI( g_ptr_array_clear(g_call_records); + ,4); // Press key A (stage 2) fl_key_responder_handle_event( @@ -789,7 +814,9 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); + TRACEI( g_ptr_array_clear(g_call_records); + ,5); // Press CapsLock (stage 2 -> 3) fl_key_responder_handle_event( @@ -807,7 +834,9 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); + TRACEI( g_ptr_array_clear(g_call_records); + ,6); // Release CapsLock (stage 3 -> 0) fl_key_responder_handle_event( @@ -825,7 +854,9 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); + TRACEI( g_ptr_array_clear(g_call_records); + ,7); // Release key A (stage 0) fl_key_responder_handle_event( @@ -843,9 +874,13 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); + TRACEI( g_ptr_array_clear(g_call_records); + ,8); clear_g_call_records(); + TRACE(g_object_unref(engine);); + TRACE(g_object_unref(responder);); } TEST(FlKeyEmbedderResponderTest, IgnoreDuplicateDownEvent) { @@ -900,8 +935,8 @@ TEST(FlKeyEmbedderResponderTest, IgnoreDuplicateDownEvent) { TEST(FlKeyEmbedderResponderTest, IgnoreAbruptUpEvent) { EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); - g_autoptr(FlEngine) engine = make_mock_engine_with_records(); - g_autoptr(FlKeyResponder) responder = + FlEngine* engine = make_mock_engine_with_records(); + FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); int user_data = 123; // Arbitrary user data @@ -916,6 +951,9 @@ TEST(FlKeyEmbedderResponderTest, IgnoreAbruptUpEvent) { EXPECT_EQ(g_call_records->len, 0u); clear_g_call_records(); + + TRACE(g_object_unref(engine);); + TRACE(g_object_unref(responder);); } // Test if missed modifier keys can be detected and synthesized with state @@ -1253,8 +1291,8 @@ TEST(FlKeyEmbedderResponderTest, TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); - g_autoptr(FlEngine) engine = make_mock_engine_with_records(); - g_autoptr(FlKeyResponder) responder = + FlEngine* engine = make_mock_engine_with_records(); + FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); int user_data = 123; // Arbitrary user data @@ -1288,7 +1326,9 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); + TRACEI( g_ptr_array_clear(g_call_records); + ,1); // The NumLock is desynchronized by being disabled. state = 0; @@ -1334,7 +1374,9 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); + TRACEI( g_ptr_array_clear(g_call_records); + ,2); // Release NumLock. Since the previous event should have synthesized NumLock // to be released, this should result in no events. @@ -1348,6 +1390,9 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { EXPECT_EQ(g_call_records->len, 0u); clear_g_call_records(); + + TRACE(g_object_unref(engine);); + TRACE(g_object_unref(responder);); } // Test if missed lock keys can be detected and synthesized with state @@ -1355,8 +1400,8 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) { EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); - g_autoptr(FlEngine) engine = make_mock_engine_with_records(); - g_autoptr(FlKeyResponder) responder = + FlEngine* engine = make_mock_engine_with_records(); + FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); int user_data = 123; // Arbitrary user data @@ -1398,7 +1443,9 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); + TRACEI( g_ptr_array_clear(g_call_records); + ,1); // The NumLock is desynchronized by being enabled in a press event. state = GDK_MOD2_MASK; @@ -1444,9 +1491,14 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); + TRACEI( g_ptr_array_clear(g_call_records); + ,2); clear_g_call_records(); + + TRACE(g_object_unref(engine);); + TRACE(g_object_unref(responder);); } // Ensures that even if the primary event is ignored (due to duplicate diff --git a/shell/platform/linux/fl_key_event.cc b/shell/platform/linux/fl_key_event.cc index b823a3377ae16..dba910ef52c10 100644 --- a/shell/platform/linux/fl_key_event.cc +++ b/shell/platform/linux/fl_key_event.cc @@ -4,9 +4,16 @@ #include "flutter/shell/platform/linux/fl_key_event.h" +#define TRACE(x) \ + printf("before "#x"\n");fflush(stdout); \ + x \ + printf("after "#x"\n");fflush(stdout); + static void dispose_origin_from_gdk_event(gpointer origin) { g_return_if_fail(origin != nullptr); + TRACE( gdk_event_free(reinterpret_cast(origin)); + ); } static char* clone_string(const char* source) { @@ -41,12 +48,18 @@ FlKeyEvent* fl_key_event_new_from_gdk_event(GdkEvent* raw_event) { void fl_key_event_dispose(FlKeyEvent* event) { if (event->string != nullptr) { + TRACE( g_free(const_cast(event->string)); + ); } if (event->dispose_origin != nullptr) { + TRACE( event->dispose_origin(event->origin); + ); } + TRACE( g_free(event); + ); } FlKeyEvent* fl_key_event_clone(const FlKeyEvent* event) { From c18185e37dcc42e621a2b17005911e025597f5db Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 17 May 2021 19:10:38 -0700 Subject: [PATCH 097/126] Check engine nullptr --- .../linux/fl_key_embedder_responder.cc | 24 ++++++++++++++----- .../linux/fl_key_embedder_responder_test.cc | 7 ++++++ shell/platform/linux/fl_key_event.cc | 5 ++++ 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index cfcb1c0f7deb6..540c6457cc6c4 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -12,6 +12,7 @@ #include "flutter/shell/platform/linux/fl_key_embedder_responder_private.h" #include "flutter/shell/platform/linux/key_mapping.h" +#if 0 #define TRACE(x) \ printf("before "#x"\n");fflush(stdout); \ x \ @@ -20,6 +21,12 @@ printf("before "#x" "#i"\n");fflush(stdout); \ x \ printf("after "#x" "#i"\n");fflush(stdout); +#else +#define TRACE(x) \ + x +#define TRACEI(x, i) \ + x +#endif // The code prefix for unrecognized keys that are unique to Gtk, generated from // platform-specific codes. @@ -373,7 +380,9 @@ static void synthesize_simple_event(FlKeyEmbedderResponder* self, out_event.logical = logical; out_event.character = nullptr; out_event.synthesized = true; - fl_engine_send_key_event(self->engine, &out_event, nullptr, nullptr); + if (self->engine != nullptr) { + fl_engine_send_key_event(self->engine, &out_event, nullptr, nullptr); + } } namespace { @@ -775,9 +784,12 @@ static void fl_key_embedder_responder_handle_event( if (is_down_event) { update_mapping_record(self, physical_key, logical_key); } - FlKeyEmbedderUserData* response_data = - fl_key_embedder_user_data_new(self, callback, user_data); - - fl_engine_send_key_event(self->engine, &out_event, handle_response, - response_data); + if (self->engine != nullptr) { + FlKeyEmbedderUserData* response_data = + fl_key_embedder_user_data_new(self, callback, user_data); + fl_engine_send_key_event(self->engine, &out_event, handle_response, + response_data); + } else { + callback(true, user_data); + } } diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index 59cddebaa3e14..f7ec8958c7530 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -11,6 +11,7 @@ #include "flutter/shell/platform/linux/fl_engine_private.h" #include "flutter/shell/platform/linux/testing/fl_test.h" +#if 0 #define TRACE(x) \ printf("before "#x"\n");fflush(stdout); \ x \ @@ -19,6 +20,12 @@ printf("before "#x" "#i"\n");fflush(stdout); \ x \ printf("after "#x" "#i"\n");fflush(stdout); +#else +#define TRACE(x) \ + x +#define TRACEI(x, i) \ + x +#endif namespace { constexpr gboolean kRelease = FALSE; diff --git a/shell/platform/linux/fl_key_event.cc b/shell/platform/linux/fl_key_event.cc index dba910ef52c10..5c5c1e3ca7ebe 100644 --- a/shell/platform/linux/fl_key_event.cc +++ b/shell/platform/linux/fl_key_event.cc @@ -4,10 +4,15 @@ #include "flutter/shell/platform/linux/fl_key_event.h" +#if 0 #define TRACE(x) \ printf("before "#x"\n");fflush(stdout); \ x \ printf("after "#x"\n");fflush(stdout); +#else +#define TRACE(x) \ + x +#endif static void dispose_origin_from_gdk_event(gpointer origin) { g_return_if_fail(origin != nullptr); From 6b64fd2ade5497e6b102374e60c5a69da76b2972 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 17 May 2021 20:27:05 -0700 Subject: [PATCH 098/126] Remove tracing --- .../linux/fl_key_embedder_responder.cc | 30 -------- .../linux/fl_key_embedder_responder_test.cc | 75 ++----------------- shell/platform/linux/fl_key_event.cc | 18 ----- 3 files changed, 8 insertions(+), 115 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index 540c6457cc6c4..322346d1523f2 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -12,22 +12,6 @@ #include "flutter/shell/platform/linux/fl_key_embedder_responder_private.h" #include "flutter/shell/platform/linux/key_mapping.h" -#if 0 -#define TRACE(x) \ - printf("before "#x"\n");fflush(stdout); \ - x \ - printf("after "#x"\n");fflush(stdout); -#define TRACEI(x, i) \ - printf("before "#x" "#i"\n");fflush(stdout); \ - x \ - printf("after "#x" "#i"\n");fflush(stdout); -#else -#define TRACE(x) \ - x -#define TRACEI(x, i) \ - x -#endif - // The code prefix for unrecognized keys that are unique to Gtk, generated from // platform-specific codes. constexpr uint64_t kGtkKeyIdPlane = 0x00600000000; @@ -104,11 +88,9 @@ static void fl_key_embedder_user_data_dispose(GObject* object) { g_return_if_fail(FL_IS_KEY_EMBEDDER_USER_DATA(object)); FlKeyEmbedderUserData* self = FL_KEY_EMBEDDER_USER_DATA(object); if (self->responder != nullptr) { - TRACE( g_object_remove_weak_pointer( G_OBJECT(self->responder), reinterpret_cast(&(self->responder))); - ); self->responder = nullptr; } } @@ -238,25 +220,13 @@ static void fl_key_embedder_responder_init(FlKeyEmbedderResponder* self) {} static void fl_key_embedder_responder_dispose(GObject* object) { FlKeyEmbedderResponder* self = FL_KEY_EMBEDDER_RESPONDER(object); - TRACE( g_clear_pointer(&self->pressing_records, g_hash_table_unref); - ); - TRACE( g_clear_pointer(&self->mapping_records, g_hash_table_unref); - ); - TRACE( g_clear_pointer(&self->modifier_bit_to_checked_keys, g_hash_table_unref); - ); - TRACE( g_clear_pointer(&self->lock_bit_to_checked_keys, g_hash_table_unref); - ); - TRACE( g_clear_pointer(&self->logical_key_to_lock_bit, g_hash_table_unref); - ); - TRACE( G_OBJECT_CLASS(fl_key_embedder_responder_parent_class)->dispose(object); - ); } // Fill in #logical_key_to_lock_bit by associating a logical key with diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index f7ec8958c7530..fa69237a07b77 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -11,22 +11,6 @@ #include "flutter/shell/platform/linux/fl_engine_private.h" #include "flutter/shell/platform/linux/testing/fl_test.h" -#if 0 -#define TRACE(x) \ - printf("before "#x"\n");fflush(stdout); \ - x \ - printf("after "#x"\n");fflush(stdout); -#define TRACEI(x, i) \ - printf("before "#x" "#i"\n");fflush(stdout); \ - x \ - printf("after "#x" "#i"\n");fflush(stdout); -#else -#define TRACE(x) \ - x -#define TRACEI(x, i) \ - x -#endif - namespace { constexpr gboolean kRelease = FALSE; constexpr gboolean kPress = TRUE; @@ -59,9 +43,7 @@ constexpr uint64_t kLogicalCapsLock = 0x1000000104; } // namespace static void g_ptr_array_clear(GPtrArray* array) { - TRACE( g_ptr_array_remove_range(array, 0, array->len); - ); } G_DECLARE_FINAL_TYPE(FlKeyEmbedderCallRecord, @@ -90,12 +72,8 @@ static void fl_key_embedder_call_record_dispose(GObject* object) { FlKeyEmbedderCallRecord* self = FL_KEY_EMBEDDER_CALL_RECORD(object); if (self->event != nullptr) { - TRACE( g_free(const_cast(self->event->character)); - ); - TRACE( g_free(self->event); - ); } G_OBJECT_CLASS(fl_key_embedder_call_record_parent_class)->dispose(object); } @@ -195,9 +173,7 @@ static FlEngine* make_mock_engine_with_records() { } static void clear_g_call_records() { - TRACE( g_ptr_array_free(g_call_records, TRUE); - ); g_call_records = nullptr; } @@ -718,8 +694,8 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); - FlEngine* engine = make_mock_engine_with_records(); - FlKeyResponder* responder = + g_autoptr(FlEngine) engine = make_mock_engine_with_records(); + g_autoptr(FlKeyResponder) responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); int user_data = 123; // Arbitrary user data @@ -741,9 +717,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI( g_ptr_array_clear(g_call_records); - ,1); // Press CapsLock (stage 0 -> 1) fl_key_responder_handle_event( @@ -761,9 +735,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI( g_ptr_array_clear(g_call_records); - ,2); // Release CapsLock (stage 1 -> 2) fl_key_responder_handle_event( @@ -781,9 +753,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI( g_ptr_array_clear(g_call_records); - ,3); // Release key A (stage 2) fl_key_responder_handle_event( @@ -801,9 +771,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI( g_ptr_array_clear(g_call_records); - ,4); // Press key A (stage 2) fl_key_responder_handle_event( @@ -821,9 +789,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI( g_ptr_array_clear(g_call_records); - ,5); // Press CapsLock (stage 2 -> 3) fl_key_responder_handle_event( @@ -841,9 +807,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI( g_ptr_array_clear(g_call_records); - ,6); // Release CapsLock (stage 3 -> 0) fl_key_responder_handle_event( @@ -861,9 +825,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI( g_ptr_array_clear(g_call_records); - ,7); // Release key A (stage 0) fl_key_responder_handle_event( @@ -881,13 +843,9 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI( g_ptr_array_clear(g_call_records); - ,8); clear_g_call_records(); - TRACE(g_object_unref(engine);); - TRACE(g_object_unref(responder);); } TEST(FlKeyEmbedderResponderTest, IgnoreDuplicateDownEvent) { @@ -942,8 +900,8 @@ TEST(FlKeyEmbedderResponderTest, IgnoreDuplicateDownEvent) { TEST(FlKeyEmbedderResponderTest, IgnoreAbruptUpEvent) { EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); - FlEngine* engine = make_mock_engine_with_records(); - FlKeyResponder* responder = + g_autoptr(FlEngine) engine = make_mock_engine_with_records(); + g_autoptr(FlKeyResponder) responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); int user_data = 123; // Arbitrary user data @@ -958,9 +916,6 @@ TEST(FlKeyEmbedderResponderTest, IgnoreAbruptUpEvent) { EXPECT_EQ(g_call_records->len, 0u); clear_g_call_records(); - - TRACE(g_object_unref(engine);); - TRACE(g_object_unref(responder);); } // Test if missed modifier keys can be detected and synthesized with state @@ -1298,8 +1253,8 @@ TEST(FlKeyEmbedderResponderTest, TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); - FlEngine* engine = make_mock_engine_with_records(); - FlKeyResponder* responder = + g_autoptr(FlEngine) engine = make_mock_engine_with_records(); + g_autoptr(FlKeyResponder) responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); int user_data = 123; // Arbitrary user data @@ -1333,9 +1288,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI( g_ptr_array_clear(g_call_records); - ,1); // The NumLock is desynchronized by being disabled. state = 0; @@ -1381,9 +1334,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI( g_ptr_array_clear(g_call_records); - ,2); // Release NumLock. Since the previous event should have synthesized NumLock // to be released, this should result in no events. @@ -1397,9 +1348,6 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { EXPECT_EQ(g_call_records->len, 0u); clear_g_call_records(); - - TRACE(g_object_unref(engine);); - TRACE(g_object_unref(responder);); } // Test if missed lock keys can be detected and synthesized with state @@ -1407,8 +1355,8 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) { EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); - FlEngine* engine = make_mock_engine_with_records(); - FlKeyResponder* responder = + g_autoptr(FlEngine) engine = make_mock_engine_with_records(); + g_autoptr(FlKeyResponder) responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); int user_data = 123; // Arbitrary user data @@ -1450,9 +1398,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI( g_ptr_array_clear(g_call_records); - ,1); // The NumLock is desynchronized by being enabled in a press event. state = GDK_MOD2_MASK; @@ -1498,14 +1444,9 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI( g_ptr_array_clear(g_call_records); - ,2); clear_g_call_records(); - - TRACE(g_object_unref(engine);); - TRACE(g_object_unref(responder);); } // Ensures that even if the primary event is ignored (due to duplicate diff --git a/shell/platform/linux/fl_key_event.cc b/shell/platform/linux/fl_key_event.cc index 5c5c1e3ca7ebe..b823a3377ae16 100644 --- a/shell/platform/linux/fl_key_event.cc +++ b/shell/platform/linux/fl_key_event.cc @@ -4,21 +4,9 @@ #include "flutter/shell/platform/linux/fl_key_event.h" -#if 0 -#define TRACE(x) \ - printf("before "#x"\n");fflush(stdout); \ - x \ - printf("after "#x"\n");fflush(stdout); -#else -#define TRACE(x) \ - x -#endif - static void dispose_origin_from_gdk_event(gpointer origin) { g_return_if_fail(origin != nullptr); - TRACE( gdk_event_free(reinterpret_cast(origin)); - ); } static char* clone_string(const char* source) { @@ -53,18 +41,12 @@ FlKeyEvent* fl_key_event_new_from_gdk_event(GdkEvent* raw_event) { void fl_key_event_dispose(FlKeyEvent* event) { if (event->string != nullptr) { - TRACE( g_free(const_cast(event->string)); - ); } if (event->dispose_origin != nullptr) { - TRACE( event->dispose_origin(event->origin); - ); } - TRACE( g_free(event); - ); } FlKeyEvent* fl_key_event_clone(const FlKeyEvent* event) { From e8ac1e558bf0cf5a19ef3b0ad471a6756618727b Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 17 May 2021 20:55:13 -0700 Subject: [PATCH 099/126] Format --- shell/platform/linux/fl_key_embedder_responder.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index 322346d1523f2..d9e9b66239ee1 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -758,7 +758,7 @@ static void fl_key_embedder_responder_handle_event( FlKeyEmbedderUserData* response_data = fl_key_embedder_user_data_new(self, callback, user_data); fl_engine_send_key_event(self->engine, &out_event, handle_response, - response_data); + response_data); } else { callback(true, user_data); } From a2c01a1bbc4748a6c93ffb242396eb8c33956b2e Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 17 May 2021 22:00:04 -0700 Subject: [PATCH 100/126] Format --- .../linux/fl_key_embedder_responder.cc | 58 +++++------- .../linux/fl_key_embedder_responder_test.cc | 88 ++++++------------- shell/platform/linux/fl_key_event.cc | 28 +++--- 3 files changed, 61 insertions(+), 113 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index 540c6457cc6c4..299d7dee78a2e 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -13,19 +13,19 @@ #include "flutter/shell/platform/linux/key_mapping.h" #if 0 -#define TRACE(x) \ - printf("before "#x"\n");fflush(stdout); \ - x \ - printf("after "#x"\n");fflush(stdout); -#define TRACEI(x, i) \ - printf("before "#x" "#i"\n");fflush(stdout); \ - x \ - printf("after "#x" "#i"\n");fflush(stdout); +#define TRACE(x) \ + printf("before " #x "\n"); \ + fflush(stdout); \ + x printf("after " #x "\n"); \ + fflush(stdout); +#define TRACEI(x, i) \ + printf("before " #x " " #i "\n"); \ + fflush(stdout); \ + x printf("after " #x " " #i "\n"); \ + fflush(stdout); #else -#define TRACE(x) \ - x -#define TRACEI(x, i) \ - x +#define TRACE(x) x +#define TRACEI(x, i) x #endif // The code prefix for unrecognized keys that are unique to Gtk, generated from @@ -104,11 +104,9 @@ static void fl_key_embedder_user_data_dispose(GObject* object) { g_return_if_fail(FL_IS_KEY_EMBEDDER_USER_DATA(object)); FlKeyEmbedderUserData* self = FL_KEY_EMBEDDER_USER_DATA(object); if (self->responder != nullptr) { - TRACE( - g_object_remove_weak_pointer( - G_OBJECT(self->responder), - reinterpret_cast(&(self->responder))); - ); + TRACE(g_object_remove_weak_pointer( + G_OBJECT(self->responder), + reinterpret_cast(&(self->responder)));); self->responder = nullptr; } } @@ -238,25 +236,15 @@ static void fl_key_embedder_responder_init(FlKeyEmbedderResponder* self) {} static void fl_key_embedder_responder_dispose(GObject* object) { FlKeyEmbedderResponder* self = FL_KEY_EMBEDDER_RESPONDER(object); - TRACE( - g_clear_pointer(&self->pressing_records, g_hash_table_unref); - ); - TRACE( - g_clear_pointer(&self->mapping_records, g_hash_table_unref); - ); - TRACE( - g_clear_pointer(&self->modifier_bit_to_checked_keys, g_hash_table_unref); - ); - TRACE( - g_clear_pointer(&self->lock_bit_to_checked_keys, g_hash_table_unref); - ); - TRACE( - g_clear_pointer(&self->logical_key_to_lock_bit, g_hash_table_unref); - ); + TRACE(g_clear_pointer(&self->pressing_records, g_hash_table_unref);); + TRACE(g_clear_pointer(&self->mapping_records, g_hash_table_unref);); + TRACE(g_clear_pointer(&self->modifier_bit_to_checked_keys, + g_hash_table_unref);); + TRACE(g_clear_pointer(&self->lock_bit_to_checked_keys, g_hash_table_unref);); + TRACE(g_clear_pointer(&self->logical_key_to_lock_bit, g_hash_table_unref);); TRACE( - G_OBJECT_CLASS(fl_key_embedder_responder_parent_class)->dispose(object); - ); + G_OBJECT_CLASS(fl_key_embedder_responder_parent_class)->dispose(object);); } // Fill in #logical_key_to_lock_bit by associating a logical key with @@ -788,7 +776,7 @@ static void fl_key_embedder_responder_handle_event( FlKeyEmbedderUserData* response_data = fl_key_embedder_user_data_new(self, callback, user_data); fl_engine_send_key_event(self->engine, &out_event, handle_response, - response_data); + response_data); } else { callback(true, user_data); } diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index f7ec8958c7530..d48e93b9b7707 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -12,19 +12,19 @@ #include "flutter/shell/platform/linux/testing/fl_test.h" #if 0 -#define TRACE(x) \ - printf("before "#x"\n");fflush(stdout); \ - x \ - printf("after "#x"\n");fflush(stdout); -#define TRACEI(x, i) \ - printf("before "#x" "#i"\n");fflush(stdout); \ - x \ - printf("after "#x" "#i"\n");fflush(stdout); +#define TRACE(x) \ + printf("before " #x "\n"); \ + fflush(stdout); \ + x printf("after " #x "\n"); \ + fflush(stdout); +#define TRACEI(x, i) \ + printf("before " #x " " #i "\n"); \ + fflush(stdout); \ + x printf("after " #x " " #i "\n"); \ + fflush(stdout); #else -#define TRACE(x) \ - x -#define TRACEI(x, i) \ - x +#define TRACE(x) x +#define TRACEI(x, i) x #endif namespace { @@ -59,9 +59,7 @@ constexpr uint64_t kLogicalCapsLock = 0x1000000104; } // namespace static void g_ptr_array_clear(GPtrArray* array) { - TRACE( - g_ptr_array_remove_range(array, 0, array->len); - ); + TRACE(g_ptr_array_remove_range(array, 0, array->len);); } G_DECLARE_FINAL_TYPE(FlKeyEmbedderCallRecord, @@ -90,12 +88,8 @@ static void fl_key_embedder_call_record_dispose(GObject* object) { FlKeyEmbedderCallRecord* self = FL_KEY_EMBEDDER_CALL_RECORD(object); if (self->event != nullptr) { - TRACE( - g_free(const_cast(self->event->character)); - ); - TRACE( - g_free(self->event); - ); + TRACE(g_free(const_cast(self->event->character));); + TRACE(g_free(self->event);); } G_OBJECT_CLASS(fl_key_embedder_call_record_parent_class)->dispose(object); } @@ -195,9 +189,7 @@ static FlEngine* make_mock_engine_with_records() { } static void clear_g_call_records() { - TRACE( - g_ptr_array_free(g_call_records, TRUE); - ); + TRACE(g_ptr_array_free(g_call_records, TRUE);); g_call_records = nullptr; } @@ -741,9 +733,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI( - g_ptr_array_clear(g_call_records); - ,1); + TRACEI(g_ptr_array_clear(g_call_records);, 1); // Press CapsLock (stage 0 -> 1) fl_key_responder_handle_event( @@ -761,9 +751,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI( - g_ptr_array_clear(g_call_records); - ,2); + TRACEI(g_ptr_array_clear(g_call_records);, 2); // Release CapsLock (stage 1 -> 2) fl_key_responder_handle_event( @@ -781,9 +769,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI( - g_ptr_array_clear(g_call_records); - ,3); + TRACEI(g_ptr_array_clear(g_call_records);, 3); // Release key A (stage 2) fl_key_responder_handle_event( @@ -801,9 +787,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI( - g_ptr_array_clear(g_call_records); - ,4); + TRACEI(g_ptr_array_clear(g_call_records);, 4); // Press key A (stage 2) fl_key_responder_handle_event( @@ -821,9 +805,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI( - g_ptr_array_clear(g_call_records); - ,5); + TRACEI(g_ptr_array_clear(g_call_records);, 5); // Press CapsLock (stage 2 -> 3) fl_key_responder_handle_event( @@ -841,9 +823,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI( - g_ptr_array_clear(g_call_records); - ,6); + TRACEI(g_ptr_array_clear(g_call_records);, 6); // Release CapsLock (stage 3 -> 0) fl_key_responder_handle_event( @@ -861,9 +841,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI( - g_ptr_array_clear(g_call_records); - ,7); + TRACEI(g_ptr_array_clear(g_call_records);, 7); // Release key A (stage 0) fl_key_responder_handle_event( @@ -881,9 +859,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI( - g_ptr_array_clear(g_call_records); - ,8); + TRACEI(g_ptr_array_clear(g_call_records);, 8); clear_g_call_records(); TRACE(g_object_unref(engine);); @@ -1333,9 +1309,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI( - g_ptr_array_clear(g_call_records); - ,1); + TRACEI(g_ptr_array_clear(g_call_records);, 1); // The NumLock is desynchronized by being disabled. state = 0; @@ -1381,9 +1355,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI( - g_ptr_array_clear(g_call_records); - ,2); + TRACEI(g_ptr_array_clear(g_call_records);, 2); // Release NumLock. Since the previous event should have synthesized NumLock // to be released, this should result in no events. @@ -1450,9 +1422,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI( - g_ptr_array_clear(g_call_records); - ,1); + TRACEI(g_ptr_array_clear(g_call_records);, 1); // The NumLock is desynchronized by being enabled in a press event. state = GDK_MOD2_MASK; @@ -1498,9 +1468,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI( - g_ptr_array_clear(g_call_records); - ,2); + TRACEI(g_ptr_array_clear(g_call_records);, 2); clear_g_call_records(); diff --git a/shell/platform/linux/fl_key_event.cc b/shell/platform/linux/fl_key_event.cc index 5c5c1e3ca7ebe..46e4157f8a101 100644 --- a/shell/platform/linux/fl_key_event.cc +++ b/shell/platform/linux/fl_key_event.cc @@ -5,20 +5,18 @@ #include "flutter/shell/platform/linux/fl_key_event.h" #if 0 -#define TRACE(x) \ - printf("before "#x"\n");fflush(stdout); \ - x \ - printf("after "#x"\n");fflush(stdout); +#define TRACE(x) \ + printf("before " #x "\n"); \ + fflush(stdout); \ + x printf("after " #x "\n"); \ + fflush(stdout); #else -#define TRACE(x) \ - x +#define TRACE(x) x #endif static void dispose_origin_from_gdk_event(gpointer origin) { g_return_if_fail(origin != nullptr); - TRACE( - gdk_event_free(reinterpret_cast(origin)); - ); + TRACE(gdk_event_free(reinterpret_cast(origin));); } static char* clone_string(const char* source) { @@ -53,18 +51,12 @@ FlKeyEvent* fl_key_event_new_from_gdk_event(GdkEvent* raw_event) { void fl_key_event_dispose(FlKeyEvent* event) { if (event->string != nullptr) { - TRACE( - g_free(const_cast(event->string)); - ); + TRACE(g_free(const_cast(event->string));); } if (event->dispose_origin != nullptr) { - TRACE( - event->dispose_origin(event->origin); - ); + TRACE(event->dispose_origin(event->origin);); } - TRACE( - g_free(event); - ); + TRACE(g_free(event);); } FlKeyEvent* fl_key_event_clone(const FlKeyEvent* event) { From e7c1d4bfe082f9a6e03032513d051eabf17ea593 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Mon, 17 May 2021 22:02:51 -0700 Subject: [PATCH 101/126] Turn on tests --- shell/platform/linux/fl_key_embedder_responder.cc | 2 +- shell/platform/linux/fl_key_embedder_responder_test.cc | 2 +- shell/platform/linux/fl_key_event.cc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index 299d7dee78a2e..bca9299f8ab2a 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -12,7 +12,7 @@ #include "flutter/shell/platform/linux/fl_key_embedder_responder_private.h" #include "flutter/shell/platform/linux/key_mapping.h" -#if 0 +#if 1 #define TRACE(x) \ printf("before " #x "\n"); \ fflush(stdout); \ diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index 956ffeecaba05..41cfb5e000fa0 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -11,7 +11,7 @@ #include "flutter/shell/platform/linux/fl_engine_private.h" #include "flutter/shell/platform/linux/testing/fl_test.h" -#if 0 +#if 1 #define TRACE(x) \ printf("before " #x "\n"); \ fflush(stdout); \ diff --git a/shell/platform/linux/fl_key_event.cc b/shell/platform/linux/fl_key_event.cc index 46e4157f8a101..1142329498096 100644 --- a/shell/platform/linux/fl_key_event.cc +++ b/shell/platform/linux/fl_key_event.cc @@ -4,7 +4,7 @@ #include "flutter/shell/platform/linux/fl_key_event.h" -#if 0 +#if 1 #define TRACE(x) \ printf("before " #x "\n"); \ fflush(stdout); \ From 9a0c84d9454fd7c512469c65e0cfcc0fb3e5a86c Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 18 May 2021 01:16:35 -0700 Subject: [PATCH 102/126] Complete test --- .../linux/fl_key_embedder_responder_test.cc | 158 ++++++++++-------- 1 file changed, 92 insertions(+), 66 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index 41cfb5e000fa0..fb0a16e337bef 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -18,9 +18,9 @@ x printf("after " #x "\n"); \ fflush(stdout); #define TRACEI(x, i) \ - printf("before " #x " " #i "\n"); \ + printf("before " #x " " __LINE__ "\n"); \ fflush(stdout); \ - x printf("after " #x " " #i "\n"); \ + x printf("after " #x " " __LINE__ "\n"); \ fflush(stdout); #else #define TRACE(x) x @@ -197,8 +197,8 @@ static void clear_g_call_records() { TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); - g_autoptr(FlEngine) engine = make_mock_engine_with_records(); - g_autoptr(FlKeyResponder) responder = + FlEngine* engine = make_mock_engine_with_records(); + FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); int user_data = 123; // Arbitrary user data @@ -223,7 +223,7 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - g_ptr_array_clear(g_call_records); + TRACEI(g_ptr_array_clear(g_call_records);, 1); // Skip testing key repeats, which is not present on GDK. @@ -245,7 +245,7 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, FALSE, &user_data); - g_ptr_array_clear(g_call_records); + TRACEI(g_ptr_array_clear(g_call_records);, 2); // On an AZERTY keyboard, press key Q (physically key A), and release. // Key down @@ -266,7 +266,7 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - g_ptr_array_clear(g_call_records); + TRACEI(g_ptr_array_clear(g_call_records);, 3); // Key up fl_key_responder_handle_event( @@ -286,17 +286,19 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, FALSE, &user_data); - g_ptr_array_clear(g_call_records); + TRACEI(g_ptr_array_clear(g_call_records);, 4); clear_g_call_records(); + TRACE(g_object_unref(engine)); + TRACE(g_object_unref(responder)); } // Press Shift, key A, then release Shift, key A. TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); - g_autoptr(FlEngine) engine = make_mock_engine_with_records(); - g_autoptr(FlKeyResponder) responder = + FlEngine* engine = make_mock_engine_with_records(); + FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); int user_data = 123; // Arbitrary user data @@ -318,7 +320,7 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - g_ptr_array_clear(g_call_records); + TRACEI(g_ptr_array_clear(g_call_records);, 1); // Press key A fl_key_responder_handle_event( @@ -336,7 +338,7 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - g_ptr_array_clear(g_call_records); + TRACEI(g_ptr_array_clear(g_call_records);, 1); // Release shift right fl_key_responder_handle_event( @@ -354,7 +356,7 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - g_ptr_array_clear(g_call_records); + TRACEI(g_ptr_array_clear(g_call_records);, 1); // Release key A fl_key_responder_handle_event( @@ -372,9 +374,11 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - g_ptr_array_clear(g_call_records); + TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); + TRACE(g_object_unref(engine)); + TRACE(g_object_unref(responder)); } // Press or release Numpad 1 between presses/releases of NumLock. @@ -388,8 +392,8 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); - g_autoptr(FlEngine) engine = make_mock_engine_with_records(); - g_autoptr(FlKeyResponder) responder = + FlEngine* engine = make_mock_engine_with_records(); + FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); int user_data = 123; // Arbitrary user data @@ -411,7 +415,7 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - g_ptr_array_clear(g_call_records); + TRACEI(g_ptr_array_clear(g_call_records);, 1); // Press NumLock (stage 0 -> 1) fl_key_responder_handle_event( @@ -429,7 +433,7 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - g_ptr_array_clear(g_call_records); + TRACEI(g_ptr_array_clear(g_call_records);, 1); // Release numpad 1 (stage 1) fl_key_responder_handle_event( @@ -447,7 +451,7 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - g_ptr_array_clear(g_call_records); + TRACEI(g_ptr_array_clear(g_call_records);, 1); // Release NumLock (stage 1 -> 2) fl_key_responder_handle_event( @@ -465,7 +469,7 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - g_ptr_array_clear(g_call_records); + TRACEI(g_ptr_array_clear(g_call_records);, 1); // Press Numpad 1 (stage 2) fl_key_responder_handle_event( @@ -483,7 +487,7 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - g_ptr_array_clear(g_call_records); + TRACEI(g_ptr_array_clear(g_call_records);, 1); // Press NumLock (stage 2 -> 3) fl_key_responder_handle_event( @@ -501,7 +505,7 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - g_ptr_array_clear(g_call_records); + TRACEI(g_ptr_array_clear(g_call_records);, 1); // Release numpad 1 (stage 3) fl_key_responder_handle_event( @@ -519,7 +523,7 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - g_ptr_array_clear(g_call_records); + TRACEI(g_ptr_array_clear(g_call_records);, 1); // Release NumLock (stage 3 -> 0) fl_key_responder_handle_event( @@ -537,9 +541,11 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - g_ptr_array_clear(g_call_records); + TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); + TRACE(g_object_unref(engine)); + TRACE(g_object_unref(responder)); } // Press or release letter key between presses/releases of CapsLock. @@ -549,8 +555,8 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); - g_autoptr(FlEngine) engine = make_mock_engine_with_records(); - g_autoptr(FlKeyResponder) responder = + FlEngine* engine = make_mock_engine_with_records(); + FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); int user_data = 123; // Arbitrary user data @@ -572,7 +578,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - g_ptr_array_clear(g_call_records); + TRACEI(g_ptr_array_clear(g_call_records);, 1); // Press key A (stage 1) fl_key_responder_handle_event( @@ -590,7 +596,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - g_ptr_array_clear(g_call_records); + TRACEI(g_ptr_array_clear(g_call_records);, 1); // Release CapsLock (stage 1 -> 2) fl_key_responder_handle_event( @@ -608,7 +614,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - g_ptr_array_clear(g_call_records); + TRACEI(g_ptr_array_clear(g_call_records);, 1); // Release key A (stage 2) fl_key_responder_handle_event( @@ -626,7 +632,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - g_ptr_array_clear(g_call_records); + TRACEI(g_ptr_array_clear(g_call_records);, 1); // Press CapsLock (stage 2 -> 3) fl_key_responder_handle_event( @@ -644,7 +650,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - g_ptr_array_clear(g_call_records); + TRACEI(g_ptr_array_clear(g_call_records);, 1); // Press key A (stage 3) fl_key_responder_handle_event( @@ -662,7 +668,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - g_ptr_array_clear(g_call_records); + TRACEI(g_ptr_array_clear(g_call_records);, 1); // Release CapsLock (stage 3 -> 0) fl_key_responder_handle_event( @@ -680,7 +686,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - g_ptr_array_clear(g_call_records); + TRACEI(g_ptr_array_clear(g_call_records);, 1); // Release key A (stage 0) fl_key_responder_handle_event( @@ -698,9 +704,11 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - g_ptr_array_clear(g_call_records); + TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); + TRACE(g_object_unref(engine)); + TRACE(g_object_unref(responder)); } // Press or release letter key between presses/releases of CapsLock, on @@ -710,8 +718,8 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); - g_autoptr(FlEngine) engine = make_mock_engine_with_records(); - g_autoptr(FlKeyResponder) responder = + FlEngine* engine = make_mock_engine_with_records(); + FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); int user_data = 123; // Arbitrary user data @@ -862,13 +870,15 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { TRACEI(g_ptr_array_clear(g_call_records);, 8); clear_g_call_records(); + TRACE(g_object_unref(engine)); + TRACE(g_object_unref(responder)); } TEST(FlKeyEmbedderResponderTest, IgnoreDuplicateDownEvent) { EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); - g_autoptr(FlEngine) engine = make_mock_engine_with_records(); - g_autoptr(FlKeyResponder) responder = + FlEngine* engine = make_mock_engine_with_records(); + FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); int user_data = 123; // Arbitrary user data @@ -885,7 +895,7 @@ TEST(FlKeyEmbedderResponderTest, IgnoreDuplicateDownEvent) { record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); invoke_record_callback_and_verify(record, TRUE, &user_data); - g_ptr_array_clear(g_call_records); + TRACEI(g_ptr_array_clear(g_call_records);, 1); // Press KeyA again (with different logical key, which is not necessari but // for coverage). @@ -908,16 +918,18 @@ TEST(FlKeyEmbedderResponderTest, IgnoreDuplicateDownEvent) { EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); invoke_record_callback_and_verify(record, TRUE, &user_data); - g_ptr_array_clear(g_call_records); + TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); + TRACE(g_object_unref(engine)); + TRACE(g_object_unref(responder)); } TEST(FlKeyEmbedderResponderTest, IgnoreAbruptUpEvent) { EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); - g_autoptr(FlEngine) engine = make_mock_engine_with_records(); - g_autoptr(FlKeyResponder) responder = + FlEngine* engine = make_mock_engine_with_records(); + FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); int user_data = 123; // Arbitrary user data @@ -932,6 +944,8 @@ TEST(FlKeyEmbedderResponderTest, IgnoreAbruptUpEvent) { EXPECT_EQ(g_call_records->len, 0u); clear_g_call_records(); + TRACE(g_object_unref(engine)); + TRACE(g_object_unref(responder)); } // Test if missed modifier keys can be detected and synthesized with state @@ -939,8 +953,8 @@ TEST(FlKeyEmbedderResponderTest, IgnoreAbruptUpEvent) { TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) { EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); - g_autoptr(FlEngine) engine = make_mock_engine_with_records(); - g_autoptr(FlKeyResponder) responder = + FlEngine* engine = make_mock_engine_with_records(); + FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); int user_data = 123; // Arbitrary user data @@ -976,7 +990,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - g_ptr_array_clear(g_call_records); + TRACEI(g_ptr_array_clear(g_call_records);, 1); // Test 2: synthesize key up. @@ -990,7 +1004,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) { EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); invoke_record_callback_and_verify(record, TRUE, &user_data); - g_ptr_array_clear(g_call_records); + TRACEI(g_ptr_array_clear(g_call_records);, 1); // A key up of control left is missed. state = 0; @@ -1020,7 +1034,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - g_ptr_array_clear(g_call_records); + TRACEI(g_ptr_array_clear(g_call_records);, 1); // Send a ControlLeft up to clear up state. state = GDK_CONTROL_MASK; @@ -1032,7 +1046,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) { EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); invoke_record_callback_and_verify(record, TRUE, &user_data); - g_ptr_array_clear(g_call_records); + TRACEI(g_ptr_array_clear(g_call_records);, 1); // Test 3: synthesize by right modifier. @@ -1059,9 +1073,11 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) { EXPECT_STREQ(record->event->character, nullptr); EXPECT_EQ(record->event->synthesized, true); - g_ptr_array_clear(g_call_records); + TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); + TRACE(g_object_unref(engine)); + TRACE(g_object_unref(responder)); } // Test if missed modifier keys can be detected and synthesized with state @@ -1070,8 +1086,8 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnNonSelfEvents) { EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); - g_autoptr(FlEngine) engine = make_mock_engine_with_records(); - g_autoptr(FlKeyResponder) responder = + FlEngine* engine = make_mock_engine_with_records(); + FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); int user_data = 123; // Arbitrary user data @@ -1105,7 +1121,7 @@ TEST(FlKeyEmbedderResponderTest, EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - g_ptr_array_clear(g_call_records); + TRACEI(g_ptr_array_clear(g_call_records);, 1); // A key up of control left is missed. state = 0; @@ -1135,7 +1151,7 @@ TEST(FlKeyEmbedderResponderTest, EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - g_ptr_array_clear(g_call_records); + TRACEI(g_ptr_array_clear(g_call_records);, 1); // Test non-default key mapping. @@ -1158,7 +1174,7 @@ TEST(FlKeyEmbedderResponderTest, EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - g_ptr_array_clear(g_call_records); + TRACEI(g_ptr_array_clear(g_call_records);, 1); // The key up of the control left press is missed. state = 0; @@ -1190,9 +1206,11 @@ TEST(FlKeyEmbedderResponderTest, EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - g_ptr_array_clear(g_call_records); + TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); + TRACE(g_object_unref(engine)); + TRACE(g_object_unref(responder)); } // Test if missed modifier keys can be detected and synthesized with state @@ -1201,8 +1219,8 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnRemappedEvents) { EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); - g_autoptr(FlEngine) engine = make_mock_engine_with_records(); - g_autoptr(FlKeyResponder) responder = + FlEngine* engine = make_mock_engine_with_records(); + FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); int user_data = 123; // Arbitrary user data @@ -1227,7 +1245,7 @@ TEST(FlKeyEmbedderResponderTest, EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - g_ptr_array_clear(g_call_records); + TRACEI(g_ptr_array_clear(g_call_records);, 1); // The key up of the control left press is missed. state = 0; @@ -1259,9 +1277,11 @@ TEST(FlKeyEmbedderResponderTest, EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - g_ptr_array_clear(g_call_records); + TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); + TRACE(g_object_unref(engine)); + TRACE(g_object_unref(responder)); } // Test if missed lock keys can be detected and synthesized with state @@ -1269,8 +1289,8 @@ TEST(FlKeyEmbedderResponderTest, TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); - g_autoptr(FlEngine) engine = make_mock_engine_with_records(); - g_autoptr(FlKeyResponder) responder = + FlEngine* engine = make_mock_engine_with_records(); + FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); int user_data = 123; // Arbitrary user data @@ -1364,6 +1384,8 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { EXPECT_EQ(g_call_records->len, 0u); clear_g_call_records(); + TRACE(g_object_unref(engine)); + TRACE(g_object_unref(responder)); } // Test if missed lock keys can be detected and synthesized with state @@ -1371,8 +1393,8 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) { EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); - g_autoptr(FlEngine) engine = make_mock_engine_with_records(); - g_autoptr(FlKeyResponder) responder = + FlEngine* engine = make_mock_engine_with_records(); + FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); int user_data = 123; // Arbitrary user data @@ -1463,6 +1485,8 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) { TRACEI(g_ptr_array_clear(g_call_records);, 2); clear_g_call_records(); + TRACE(g_object_unref(engine)); + TRACE(g_object_unref(responder)); } // Ensures that even if the primary event is ignored (due to duplicate @@ -1470,8 +1494,8 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) { TEST(FlKeyEmbedderResponderTest, SynthesizationOccursOnIgnoredEvents) { EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); - g_autoptr(FlEngine) engine = make_mock_engine_with_records(); - g_autoptr(FlKeyResponder) responder = + FlEngine* engine = make_mock_engine_with_records(); + FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); int user_data = 123; // Arbitrary user data @@ -1505,7 +1529,9 @@ TEST(FlKeyEmbedderResponderTest, SynthesizationOccursOnIgnoredEvents) { EXPECT_STREQ(record->event->character, nullptr); EXPECT_EQ(record->event->synthesized, true); - g_ptr_array_clear(g_call_records); + TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); + TRACE(g_object_unref(engine)); + TRACE(g_object_unref(responder)); } From ba1b6642e31a536c44b435b53c025ab4bcebfeb6 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 18 May 2021 01:20:19 -0700 Subject: [PATCH 103/126] Correct line --- shell/platform/linux/fl_key_embedder_responder_test.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index fb0a16e337bef..95aab16450620 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -18,9 +18,9 @@ x printf("after " #x "\n"); \ fflush(stdout); #define TRACEI(x, i) \ - printf("before " #x " " __LINE__ "\n"); \ + printf("before " #x " %d\n", __LINE__); \ fflush(stdout); \ - x printf("after " #x " " __LINE__ "\n"); \ + x printf("after " #x " %d\n", __LINE__); \ fflush(stdout); #else #define TRACE(x) x From b4cdcc3c3578973464707757ecd008fdba3c5af9 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 18 May 2021 01:22:57 -0700 Subject: [PATCH 104/126] Fix build --- .../linux/fl_key_embedder_responder_test.cc | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index 95aab16450620..90aeb6b5a86bd 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -17,9 +17,9 @@ fflush(stdout); \ x printf("after " #x "\n"); \ fflush(stdout); -#define TRACEI(x, i) \ +#define TRACEI(x, i) \ printf("before " #x " %d\n", __LINE__); \ - fflush(stdout); \ + fflush(stdout); \ x printf("after " #x " %d\n", __LINE__); \ fflush(stdout); #else @@ -289,8 +289,8 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { TRACEI(g_ptr_array_clear(g_call_records);, 4); clear_g_call_records(); - TRACE(g_object_unref(engine)); - TRACE(g_object_unref(responder)); + TRACE(g_object_unref(engine);); + TRACE(g_object_unref(responder);); } // Press Shift, key A, then release Shift, key A. @@ -377,8 +377,8 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); - TRACE(g_object_unref(engine)); - TRACE(g_object_unref(responder)); + TRACE(g_object_unref(engine);); + TRACE(g_object_unref(responder);); } // Press or release Numpad 1 between presses/releases of NumLock. @@ -544,8 +544,8 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); - TRACE(g_object_unref(engine)); - TRACE(g_object_unref(responder)); + TRACE(g_object_unref(engine);); + TRACE(g_object_unref(responder);); } // Press or release letter key between presses/releases of CapsLock. @@ -707,8 +707,8 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); - TRACE(g_object_unref(engine)); - TRACE(g_object_unref(responder)); + TRACE(g_object_unref(engine);); + TRACE(g_object_unref(responder);); } // Press or release letter key between presses/releases of CapsLock, on @@ -870,8 +870,8 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { TRACEI(g_ptr_array_clear(g_call_records);, 8); clear_g_call_records(); - TRACE(g_object_unref(engine)); - TRACE(g_object_unref(responder)); + TRACE(g_object_unref(engine);); + TRACE(g_object_unref(responder);); } TEST(FlKeyEmbedderResponderTest, IgnoreDuplicateDownEvent) { @@ -921,8 +921,8 @@ TEST(FlKeyEmbedderResponderTest, IgnoreDuplicateDownEvent) { TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); - TRACE(g_object_unref(engine)); - TRACE(g_object_unref(responder)); + TRACE(g_object_unref(engine);); + TRACE(g_object_unref(responder);); } TEST(FlKeyEmbedderResponderTest, IgnoreAbruptUpEvent) { @@ -944,8 +944,8 @@ TEST(FlKeyEmbedderResponderTest, IgnoreAbruptUpEvent) { EXPECT_EQ(g_call_records->len, 0u); clear_g_call_records(); - TRACE(g_object_unref(engine)); - TRACE(g_object_unref(responder)); + TRACE(g_object_unref(engine);); + TRACE(g_object_unref(responder);); } // Test if missed modifier keys can be detected and synthesized with state @@ -1076,8 +1076,8 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) { TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); - TRACE(g_object_unref(engine)); - TRACE(g_object_unref(responder)); + TRACE(g_object_unref(engine);); + TRACE(g_object_unref(responder);); } // Test if missed modifier keys can be detected and synthesized with state @@ -1209,8 +1209,8 @@ TEST(FlKeyEmbedderResponderTest, TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); - TRACE(g_object_unref(engine)); - TRACE(g_object_unref(responder)); + TRACE(g_object_unref(engine);); + TRACE(g_object_unref(responder);); } // Test if missed modifier keys can be detected and synthesized with state @@ -1280,8 +1280,8 @@ TEST(FlKeyEmbedderResponderTest, TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); - TRACE(g_object_unref(engine)); - TRACE(g_object_unref(responder)); + TRACE(g_object_unref(engine);); + TRACE(g_object_unref(responder);); } // Test if missed lock keys can be detected and synthesized with state @@ -1384,8 +1384,8 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { EXPECT_EQ(g_call_records->len, 0u); clear_g_call_records(); - TRACE(g_object_unref(engine)); - TRACE(g_object_unref(responder)); + TRACE(g_object_unref(engine);); + TRACE(g_object_unref(responder);); } // Test if missed lock keys can be detected and synthesized with state @@ -1485,8 +1485,8 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) { TRACEI(g_ptr_array_clear(g_call_records);, 2); clear_g_call_records(); - TRACE(g_object_unref(engine)); - TRACE(g_object_unref(responder)); + TRACE(g_object_unref(engine);); + TRACE(g_object_unref(responder);); } // Ensures that even if the primary event is ignored (due to duplicate @@ -1532,6 +1532,6 @@ TEST(FlKeyEmbedderResponderTest, SynthesizationOccursOnIgnoredEvents) { TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); - TRACE(g_object_unref(engine)); - TRACE(g_object_unref(responder)); + TRACE(g_object_unref(engine);); + TRACE(g_object_unref(responder);); } From bcc11b62b6dfb28689e399df5102f497a509334c Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 18 May 2021 03:54:16 -0700 Subject: [PATCH 105/126] Turn off 2 files --- shell/platform/linux/fl_key_embedder_responder.cc | 2 +- shell/platform/linux/fl_key_event.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index bca9299f8ab2a..299d7dee78a2e 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -12,7 +12,7 @@ #include "flutter/shell/platform/linux/fl_key_embedder_responder_private.h" #include "flutter/shell/platform/linux/key_mapping.h" -#if 1 +#if 0 #define TRACE(x) \ printf("before " #x "\n"); \ fflush(stdout); \ diff --git a/shell/platform/linux/fl_key_event.cc b/shell/platform/linux/fl_key_event.cc index 1142329498096..46e4157f8a101 100644 --- a/shell/platform/linux/fl_key_event.cc +++ b/shell/platform/linux/fl_key_event.cc @@ -4,7 +4,7 @@ #include "flutter/shell/platform/linux/fl_key_event.h" -#if 1 +#if 0 #define TRACE(x) \ printf("before " #x "\n"); \ fflush(stdout); \ From 385c435b60fcb81f8ebad42922e935bd543ac51e Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 18 May 2021 11:30:42 -0700 Subject: [PATCH 106/126] Turn off another file --- shell/platform/linux/fl_key_embedder_responder_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index 90aeb6b5a86bd..3bef97a5c0ce4 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -11,7 +11,7 @@ #include "flutter/shell/platform/linux/fl_engine_private.h" #include "flutter/shell/platform/linux/testing/fl_test.h" -#if 1 +#if 0 #define TRACE(x) \ printf("before " #x "\n"); \ fflush(stdout); \ From 0f9a4cf15c093b91e639d510b0843f421661f46d Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 18 May 2021 12:55:44 -0700 Subject: [PATCH 107/126] Change order --- .../linux/fl_key_embedder_responder_test.cc | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index 3bef97a5c0ce4..ec3bb2ee55138 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -289,8 +289,8 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { TRACEI(g_ptr_array_clear(g_call_records);, 4); clear_g_call_records(); - TRACE(g_object_unref(engine);); TRACE(g_object_unref(responder);); + TRACE(g_object_unref(engine);); } // Press Shift, key A, then release Shift, key A. @@ -377,8 +377,8 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); - TRACE(g_object_unref(engine);); TRACE(g_object_unref(responder);); + TRACE(g_object_unref(engine);); } // Press or release Numpad 1 between presses/releases of NumLock. @@ -544,8 +544,8 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); - TRACE(g_object_unref(engine);); TRACE(g_object_unref(responder);); + TRACE(g_object_unref(engine);); } // Press or release letter key between presses/releases of CapsLock. @@ -707,8 +707,8 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); - TRACE(g_object_unref(engine);); TRACE(g_object_unref(responder);); + TRACE(g_object_unref(engine);); } // Press or release letter key between presses/releases of CapsLock, on @@ -870,8 +870,8 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { TRACEI(g_ptr_array_clear(g_call_records);, 8); clear_g_call_records(); - TRACE(g_object_unref(engine);); TRACE(g_object_unref(responder);); + TRACE(g_object_unref(engine);); } TEST(FlKeyEmbedderResponderTest, IgnoreDuplicateDownEvent) { @@ -921,8 +921,8 @@ TEST(FlKeyEmbedderResponderTest, IgnoreDuplicateDownEvent) { TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); - TRACE(g_object_unref(engine);); TRACE(g_object_unref(responder);); + TRACE(g_object_unref(engine);); } TEST(FlKeyEmbedderResponderTest, IgnoreAbruptUpEvent) { @@ -944,8 +944,8 @@ TEST(FlKeyEmbedderResponderTest, IgnoreAbruptUpEvent) { EXPECT_EQ(g_call_records->len, 0u); clear_g_call_records(); - TRACE(g_object_unref(engine);); TRACE(g_object_unref(responder);); + TRACE(g_object_unref(engine);); } // Test if missed modifier keys can be detected and synthesized with state @@ -1076,8 +1076,8 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) { TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); - TRACE(g_object_unref(engine);); TRACE(g_object_unref(responder);); + TRACE(g_object_unref(engine);); } // Test if missed modifier keys can be detected and synthesized with state @@ -1209,8 +1209,8 @@ TEST(FlKeyEmbedderResponderTest, TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); - TRACE(g_object_unref(engine);); TRACE(g_object_unref(responder);); + TRACE(g_object_unref(engine);); } // Test if missed modifier keys can be detected and synthesized with state @@ -1280,8 +1280,8 @@ TEST(FlKeyEmbedderResponderTest, TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); - TRACE(g_object_unref(engine);); TRACE(g_object_unref(responder);); + TRACE(g_object_unref(engine);); } // Test if missed lock keys can be detected and synthesized with state @@ -1384,8 +1384,8 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { EXPECT_EQ(g_call_records->len, 0u); clear_g_call_records(); - TRACE(g_object_unref(engine);); TRACE(g_object_unref(responder);); + TRACE(g_object_unref(engine);); } // Test if missed lock keys can be detected and synthesized with state @@ -1485,8 +1485,8 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) { TRACEI(g_ptr_array_clear(g_call_records);, 2); clear_g_call_records(); - TRACE(g_object_unref(engine);); TRACE(g_object_unref(responder);); + TRACE(g_object_unref(engine);); } // Ensures that even if the primary event is ignored (due to duplicate @@ -1532,6 +1532,6 @@ TEST(FlKeyEmbedderResponderTest, SynthesizationOccursOnIgnoredEvents) { TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); - TRACE(g_object_unref(engine);); TRACE(g_object_unref(responder);); + TRACE(g_object_unref(engine);); } From 60a75258738a628b697530dc4bf6cb6792a460d5 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 18 May 2021 13:27:47 -0700 Subject: [PATCH 108/126] Turn on embedder responder test --- shell/platform/linux/fl_key_embedder_responder_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index ec3bb2ee55138..c8ac2fe6f66e9 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -11,7 +11,7 @@ #include "flutter/shell/platform/linux/fl_engine_private.h" #include "flutter/shell/platform/linux/testing/fl_test.h" -#if 0 +#if 1 #define TRACE(x) \ printf("before " #x "\n"); \ fflush(stdout); \ From fafc671b5575ffbf8257ec0ff6aa699c82fa895b Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 18 May 2021 14:46:46 -0700 Subject: [PATCH 109/126] Check call records --- shell/platform/linux/fl_key_embedder_responder_test.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index ec3bb2ee55138..0d0965192388c 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -179,9 +179,10 @@ static FlEngine* make_mock_engine_with_records() { embedder_api->SendKeyEvent = [](auto engine, const FlutterKeyEvent* event, FlutterKeyEventCallback callback, void* user_data) { - g_ptr_array_add(g_call_records, fl_key_embedder_call_record_new( - event, callback, user_data)); - + if (g_call_records != nullptr) { + g_ptr_array_add(g_call_records, fl_key_embedder_call_record_new( + event, callback, user_data)); + } return kSuccess; }; From 6f4bee569e1a888a67c3121e1e7a91cd1ba72d9c Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 18 May 2021 15:47:24 -0700 Subject: [PATCH 110/126] Trace events sending --- .../linux/fl_key_embedder_responder.cc | 45 ++++++++----------- .../linux/fl_key_embedder_responder_test.cc | 4 ++ 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index 299d7dee78a2e..4394d4ed158a6 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -12,20 +12,15 @@ #include "flutter/shell/platform/linux/fl_key_embedder_responder_private.h" #include "flutter/shell/platform/linux/key_mapping.h" -#if 0 -#define TRACE(x) \ - printf("before " #x "\n"); \ - fflush(stdout); \ - x printf("after " #x "\n"); \ - fflush(stdout); -#define TRACEI(x, i) \ - printf("before " #x " " #i "\n"); \ - fflush(stdout); \ - x printf("after " #x " " #i "\n"); \ +#if 1 +#define TRACE(x) \ + printf("before " #x "\n"); \ + fflush(stdout); \ + x; \ + printf("after " #x "\n"); \ fflush(stdout); #else #define TRACE(x) x -#define TRACEI(x, i) x #endif // The code prefix for unrecognized keys that are unique to Gtk, generated from @@ -104,9 +99,9 @@ static void fl_key_embedder_user_data_dispose(GObject* object) { g_return_if_fail(FL_IS_KEY_EMBEDDER_USER_DATA(object)); FlKeyEmbedderUserData* self = FL_KEY_EMBEDDER_USER_DATA(object); if (self->responder != nullptr) { - TRACE(g_object_remove_weak_pointer( - G_OBJECT(self->responder), - reinterpret_cast(&(self->responder)));); + g_object_remove_weak_pointer( + G_OBJECT(self->responder), + reinterpret_cast(&(self->responder))); self->responder = nullptr; } } @@ -236,15 +231,13 @@ static void fl_key_embedder_responder_init(FlKeyEmbedderResponder* self) {} static void fl_key_embedder_responder_dispose(GObject* object) { FlKeyEmbedderResponder* self = FL_KEY_EMBEDDER_RESPONDER(object); - TRACE(g_clear_pointer(&self->pressing_records, g_hash_table_unref);); - TRACE(g_clear_pointer(&self->mapping_records, g_hash_table_unref);); - TRACE(g_clear_pointer(&self->modifier_bit_to_checked_keys, - g_hash_table_unref);); - TRACE(g_clear_pointer(&self->lock_bit_to_checked_keys, g_hash_table_unref);); - TRACE(g_clear_pointer(&self->logical_key_to_lock_bit, g_hash_table_unref);); + g_clear_pointer(&self->pressing_records, g_hash_table_unref); + g_clear_pointer(&self->mapping_records, g_hash_table_unref); + g_clear_pointer(&self->modifier_bit_to_checked_keys, g_hash_table_unref); + g_clear_pointer(&self->lock_bit_to_checked_keys, g_hash_table_unref); + g_clear_pointer(&self->logical_key_to_lock_bit, g_hash_table_unref); - TRACE( - G_OBJECT_CLASS(fl_key_embedder_responder_parent_class)->dispose(object);); + G_OBJECT_CLASS(fl_key_embedder_responder_parent_class)->dispose(object); } // Fill in #logical_key_to_lock_bit by associating a logical key with @@ -369,7 +362,7 @@ static void synthesize_simple_event(FlKeyEmbedderResponder* self, out_event.character = nullptr; out_event.synthesized = true; if (self->engine != nullptr) { - fl_engine_send_key_event(self->engine, &out_event, nullptr, nullptr); + TRACE(fl_engine_send_key_event(self->engine, &out_event, nullptr, nullptr)); } } @@ -775,9 +768,9 @@ static void fl_key_embedder_responder_handle_event( if (self->engine != nullptr) { FlKeyEmbedderUserData* response_data = fl_key_embedder_user_data_new(self, callback, user_data); - fl_engine_send_key_event(self->engine, &out_event, handle_response, - response_data); + TRACE(fl_engine_send_key_event(self->engine, &out_event, handle_response, + response_data)); } else { - callback(true, user_data); + TRACE(callback(true, user_data)); } } diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index 1ab71733454fd..94ad596f4c523 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -179,10 +179,14 @@ static FlEngine* make_mock_engine_with_records() { embedder_api->SendKeyEvent = [](auto engine, const FlutterKeyEvent* event, FlutterKeyEventCallback callback, void* user_data) { + printf("Before adding records\n"); + fflush(stdout); if (g_call_records != nullptr) { g_ptr_array_add(g_call_records, fl_key_embedder_call_record_new( event, callback, user_data)); } + printf("After adding records\n"); + fflush(stdout); return kSuccess; }; From 12427c76250b418e39e065bca61642f222fa5436 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 18 May 2021 16:19:12 -0700 Subject: [PATCH 111/126] Remove FlKeyEmbedderUserData::responder --- .../linux/fl_key_embedder_responder.cc | 23 +++---------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index 4394d4ed158a6..ff71117f8a8ac 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -79,7 +79,6 @@ G_DECLARE_FINAL_TYPE(FlKeyEmbedderUserData, struct _FlKeyEmbedderUserData { GObject parent_instance; - FlKeyEmbedderResponder* responder; FlKeyResponderAsyncCallback callback; gpointer user_data; }; @@ -96,31 +95,20 @@ static void fl_key_embedder_user_data_class_init( static void fl_key_embedder_user_data_init(FlKeyEmbedderUserData* self) {} static void fl_key_embedder_user_data_dispose(GObject* object) { + // The following line suppresses a warning for unused function + // FL_IS_KEY_EMBEDDER_USER_DATA. g_return_if_fail(FL_IS_KEY_EMBEDDER_USER_DATA(object)); - FlKeyEmbedderUserData* self = FL_KEY_EMBEDDER_USER_DATA(object); - if (self->responder != nullptr) { - g_object_remove_weak_pointer( - G_OBJECT(self->responder), - reinterpret_cast(&(self->responder))); - self->responder = nullptr; - } } // Creates a new FlKeyChannelUserData private class with all information. // // The callback and the user_data might be nullptr. static FlKeyEmbedderUserData* fl_key_embedder_user_data_new( - FlKeyEmbedderResponder* responder, FlKeyResponderAsyncCallback callback, gpointer user_data) { FlKeyEmbedderUserData* self = FL_KEY_EMBEDDER_USER_DATA( g_object_new(FL_TYPE_EMBEDDER_USER_DATA, nullptr)); - self->responder = responder; - // Add a weak pointer so we can know if the key event responder disappeared - // while the framework was responding. - g_object_add_weak_pointer(G_OBJECT(responder), - reinterpret_cast(&(self->responder))); self->callback = callback; self->user_data = user_data; return self; @@ -339,11 +327,6 @@ static void handle_response(bool handled, gpointer user_data) { g_return_if_fail(data->callback != nullptr); - // Return if the weak pointer has been destroyed. - if (data->responder == nullptr) { - return; - } - data->callback(handled, data->user_data); } @@ -767,7 +750,7 @@ static void fl_key_embedder_responder_handle_event( } if (self->engine != nullptr) { FlKeyEmbedderUserData* response_data = - fl_key_embedder_user_data_new(self, callback, user_data); + fl_key_embedder_user_data_new(callback, user_data); TRACE(fl_engine_send_key_event(self->engine, &out_event, handle_response, response_data)); } else { From 5616eb3e44a17628e3ff7d06281beb4dd8ccd017 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 18 May 2021 16:47:12 -0700 Subject: [PATCH 112/126] New test --- .../linux/fl_key_embedder_responder_test.cc | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index 94ad596f4c523..418827b4681c2 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -200,6 +200,8 @@ static void clear_g_call_records() { // Basic key presses TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { + printf("New test\n"); + fflush(stdout); EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); FlEngine* engine = make_mock_engine_with_records(); @@ -300,6 +302,8 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { // Press Shift, key A, then release Shift, key A. TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { + printf("New test\n"); + fflush(stdout); EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); FlEngine* engine = make_mock_engine_with_records(); @@ -395,6 +399,8 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { // test-worthy because the keyval for the numpad key will change before and // after the NumLock tap, which should not alter the resulting logical key. TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { + printf("New test\n"); + fflush(stdout); EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); FlEngine* engine = make_mock_engine_with_records(); @@ -558,6 +564,8 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { // This tests interaction between lock keys and non-lock keys in cases that do // not have events missed. TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { + printf("New test\n"); + fflush(stdout); EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); FlEngine* engine = make_mock_engine_with_records(); @@ -721,6 +729,8 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { // // This happens when using a Chrome remote desktop on MacOS. TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { + printf("New test\n"); + fflush(stdout); EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); FlEngine* engine = make_mock_engine_with_records(); @@ -880,6 +890,8 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { } TEST(FlKeyEmbedderResponderTest, IgnoreDuplicateDownEvent) { + printf("New test\n"); + fflush(stdout); EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); FlEngine* engine = make_mock_engine_with_records(); @@ -931,6 +943,8 @@ TEST(FlKeyEmbedderResponderTest, IgnoreDuplicateDownEvent) { } TEST(FlKeyEmbedderResponderTest, IgnoreAbruptUpEvent) { + printf("New test\n"); + fflush(stdout); EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); FlEngine* engine = make_mock_engine_with_records(); @@ -956,6 +970,8 @@ TEST(FlKeyEmbedderResponderTest, IgnoreAbruptUpEvent) { // Test if missed modifier keys can be detected and synthesized with state // information upon events that are for this modifier key. TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) { + printf("New test\n"); + fflush(stdout); EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); FlEngine* engine = make_mock_engine_with_records(); @@ -1089,6 +1105,8 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) { // information upon events that are not for this modifier key. TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnNonSelfEvents) { + printf("New test\n"); + fflush(stdout); EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); FlEngine* engine = make_mock_engine_with_records(); @@ -1222,6 +1240,8 @@ TEST(FlKeyEmbedderResponderTest, // information upon events that do not have the standard key mapping. TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnRemappedEvents) { + printf("New test\n"); + fflush(stdout); EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); FlEngine* engine = make_mock_engine_with_records(); @@ -1292,6 +1312,8 @@ TEST(FlKeyEmbedderResponderTest, // Test if missed lock keys can be detected and synthesized with state // information upon events that are not for this modifier key. TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { + printf("New test\n"); + fflush(stdout); EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); FlEngine* engine = make_mock_engine_with_records(); @@ -1396,6 +1418,8 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { // Test if missed lock keys can be detected and synthesized with state // information upon events that are for this modifier key. TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) { + printf("New test\n"); + fflush(stdout); EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); FlEngine* engine = make_mock_engine_with_records(); @@ -1497,6 +1521,8 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) { // Ensures that even if the primary event is ignored (due to duplicate // key up or down events), key synthesization is still performed. TEST(FlKeyEmbedderResponderTest, SynthesizationOccursOnIgnoredEvents) { + printf("New test\n"); + fflush(stdout); EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); FlEngine* engine = make_mock_engine_with_records(); From a1978b56105ba4681815cc45cea0e88a17e478e4 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 18 May 2021 16:49:38 -0700 Subject: [PATCH 113/126] printf("After create responder\n"); --- .../linux/fl_key_embedder_responder_test.cc | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index 418827b4681c2..a5d58e1fcd18b 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -175,7 +175,9 @@ GPtrArray* g_call_records; static FlEngine* make_mock_engine_with_records() { FlEngine* engine = make_mock_engine(); + printf("After mock engine\n"); FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); + printf("After get API\n"); embedder_api->SendKeyEvent = [](auto engine, const FlutterKeyEvent* event, FlutterKeyEventCallback callback, void* user_data) { @@ -207,6 +209,7 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { FlEngine* engine = make_mock_engine_with_records(); FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); + printf("After create responder\n"); int user_data = 123; // Arbitrary user data FlKeyEmbedderCallRecord* record; @@ -309,6 +312,7 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { FlEngine* engine = make_mock_engine_with_records(); FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); + printf("After create responder\n"); int user_data = 123; // Arbitrary user data FlKeyEmbedderCallRecord* record; @@ -406,6 +410,7 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { FlEngine* engine = make_mock_engine_with_records(); FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); + printf("After create responder\n"); int user_data = 123; // Arbitrary user data FlKeyEmbedderCallRecord* record; @@ -571,6 +576,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { FlEngine* engine = make_mock_engine_with_records(); FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); + printf("After create responder\n"); int user_data = 123; // Arbitrary user data FlKeyEmbedderCallRecord* record; @@ -736,6 +742,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { FlEngine* engine = make_mock_engine_with_records(); FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); + printf("After create responder\n"); int user_data = 123; // Arbitrary user data FlKeyEmbedderCallRecord* record; @@ -897,6 +904,7 @@ TEST(FlKeyEmbedderResponderTest, IgnoreDuplicateDownEvent) { FlEngine* engine = make_mock_engine_with_records(); FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); + printf("After create responder\n"); int user_data = 123; // Arbitrary user data FlKeyEmbedderCallRecord* record; @@ -950,6 +958,7 @@ TEST(FlKeyEmbedderResponderTest, IgnoreAbruptUpEvent) { FlEngine* engine = make_mock_engine_with_records(); FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); + printf("After create responder\n"); int user_data = 123; // Arbitrary user data // Release KeyA before it was even pressed. @@ -977,6 +986,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) { FlEngine* engine = make_mock_engine_with_records(); FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); + printf("After create responder\n"); int user_data = 123; // Arbitrary user data FlKeyEmbedderCallRecord* record; @@ -1112,6 +1122,7 @@ TEST(FlKeyEmbedderResponderTest, FlEngine* engine = make_mock_engine_with_records(); FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); + printf("After create responder\n"); int user_data = 123; // Arbitrary user data FlKeyEmbedderCallRecord* record; @@ -1247,6 +1258,7 @@ TEST(FlKeyEmbedderResponderTest, FlEngine* engine = make_mock_engine_with_records(); FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); + printf("After create responder\n"); int user_data = 123; // Arbitrary user data FlKeyEmbedderCallRecord* record; @@ -1319,6 +1331,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { FlEngine* engine = make_mock_engine_with_records(); FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); + printf("After create responder\n"); int user_data = 123; // Arbitrary user data FlKeyEmbedderCallRecord* record; @@ -1425,6 +1438,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) { FlEngine* engine = make_mock_engine_with_records(); FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); + printf("After create responder\n"); int user_data = 123; // Arbitrary user data FlKeyEmbedderCallRecord* record; @@ -1528,6 +1542,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizationOccursOnIgnoredEvents) { FlEngine* engine = make_mock_engine_with_records(); FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); + printf("After create responder\n"); int user_data = 123; // Arbitrary user data FlKeyEmbedderCallRecord* record; From 628144089f4eb615e9e74e840bc05fd413c4b51c Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 18 May 2021 17:26:13 -0700 Subject: [PATCH 114/126] Trace mock engine --- shell/platform/linux/testing/fl_test.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/shell/platform/linux/testing/fl_test.cc b/shell/platform/linux/testing/fl_test.cc index 15de90e557ac4..b528efedbdc88 100644 --- a/shell/platform/linux/testing/fl_test.cc +++ b/shell/platform/linux/testing/fl_test.cc @@ -49,8 +49,14 @@ gchar* bytes_to_hex_string(GBytes* bytes) { } FlEngine* make_mock_engine() { + printf("mock engine: before project\n"); + fflush(stdout); g_autoptr(FlDartProject) project = fl_dart_project_new(); + printf("mock engine: before renderer\n"); + fflush(stdout); g_autoptr(FlMockRenderer) renderer = fl_mock_renderer_new(); + printf("mock engine: before engine\n"); + fflush(stdout); g_autoptr(FlEngine) engine = fl_engine_new(project, FL_RENDERER(renderer)); g_autoptr(GError) engine_error = nullptr; EXPECT_TRUE(fl_engine_start(engine, &engine_error)); From c98da47e2ee5cda5c2c6ef08107bbcf3dd4c2992 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Wed, 19 May 2021 01:15:10 -0700 Subject: [PATCH 115/126] More engine testing --- shell/platform/linux/fl_engine.cc | 24 ++++++++++++++++++++++++ shell/platform/linux/testing/fl_test.cc | 6 ++++++ 2 files changed, 30 insertions(+) diff --git a/shell/platform/linux/fl_engine.cc b/shell/platform/linux/fl_engine.cc index 116fd3f5c7e18..993627a142477 100644 --- a/shell/platform/linux/fl_engine.cc +++ b/shell/platform/linux/fl_engine.cc @@ -353,6 +353,8 @@ gboolean fl_engine_start(FlEngine* self, GError** error) { self->task_runner = fl_task_runner_new(self); + printf("engine start: before config\n"); + fflush(stdout); FlutterRendererConfig config = {}; config.type = kOpenGL; config.open_gl.struct_size = sizeof(FlutterOpenGLRendererConfig); @@ -363,6 +365,8 @@ gboolean fl_engine_start(FlEngine* self, GError** error) { config.open_gl.present = fl_engine_gl_present; config.open_gl.make_resource_current = fl_engine_gl_make_resource_current; + printf("engine start: platform_task_runner\n"); + fflush(stdout); FlutterTaskRunnerDescription platform_task_runner = {}; platform_task_runner.struct_size = sizeof(FlutterTaskRunnerDescription); platform_task_runner.user_data = self; @@ -371,11 +375,15 @@ gboolean fl_engine_start(FlEngine* self, GError** error) { platform_task_runner.post_task_callback = fl_engine_post_task; platform_task_runner.identifier = kPlatformTaskRunnerIdentifier; + printf("engine start: custom_task_runners\n"); + fflush(stdout); FlutterCustomTaskRunners custom_task_runners = {}; custom_task_runners.struct_size = sizeof(FlutterCustomTaskRunners); custom_task_runners.platform_task_runner = &platform_task_runner; custom_task_runners.render_task_runner = &platform_task_runner; + printf("engine start: command_line_args\n"); + fflush(stdout); g_autoptr(GPtrArray) command_line_args = fl_dart_project_get_switches(self->project); // FlutterProjectArgs expects a full argv, so when processing it for flags @@ -383,6 +391,8 @@ gboolean fl_engine_start(FlEngine* self, GError** error) { // so that all switches are used. g_ptr_array_insert(command_line_args, 0, g_strdup("flutter")); + printf("engine start: dart_entrypoint_args\n"); + fflush(stdout); gchar** dart_entrypoint_args = fl_dart_project_get_dart_entrypoint_arguments(self->project); @@ -402,6 +412,8 @@ gboolean fl_engine_start(FlEngine* self, GError** error) { args.dart_entrypoint_argv = reinterpret_cast(dart_entrypoint_args); + printf("engine start: compositor\n"); + fflush(stdout); FlutterCompositor compositor = {}; compositor.struct_size = sizeof(FlutterCompositor); compositor.user_data = self->renderer; @@ -412,6 +424,8 @@ gboolean fl_engine_start(FlEngine* self, GError** error) { compositor.present_layers_callback = compositor_present_layers_callback; args.compositor = &compositor; + printf("engine start: RunsAOTCompiledDartCode\n"); + fflush(stdout); if (self->embedder_api.RunsAOTCompiledDartCode()) { FlutterEngineAOTDataSource source = {}; source.type = kFlutterEngineAOTDataSourceTypeElfPath; @@ -425,6 +439,8 @@ gboolean fl_engine_start(FlEngine* self, GError** error) { args.aot_data = self->aot_data; } + printf("engine start: Initialize\n"); + fflush(stdout); FlutterEngineResult result = self->embedder_api.Initialize( FLUTTER_ENGINE_VERSION, &config, &args, self, &self->engine); if (result != kSuccess) { @@ -433,6 +449,8 @@ gboolean fl_engine_start(FlEngine* self, GError** error) { return FALSE; } + printf("engine start: RunInitialized\n"); + fflush(stdout); result = self->embedder_api.RunInitialized(self->engine); if (result != kSuccess) { g_set_error(error, fl_engine_error_quark(), FL_ENGINE_ERROR_FAILED, @@ -440,11 +458,17 @@ gboolean fl_engine_start(FlEngine* self, GError** error) { return FALSE; } + printf("engine start: setup_locales\n"); + fflush(stdout); setup_locales(self); + printf("engine start: fl_settings_plugin_new\n"); + fflush(stdout); self->settings_plugin = fl_settings_plugin_new(self->binary_messenger); fl_settings_plugin_start(self->settings_plugin); + printf("engine start: UpdateSemanticsEnabled\n"); + fflush(stdout); result = self->embedder_api.UpdateSemanticsEnabled(self->engine, TRUE); if (result != kSuccess) g_warning("Failed to enable accessibility features on Flutter engine"); diff --git a/shell/platform/linux/testing/fl_test.cc b/shell/platform/linux/testing/fl_test.cc index b528efedbdc88..0fe7d33c3236f 100644 --- a/shell/platform/linux/testing/fl_test.cc +++ b/shell/platform/linux/testing/fl_test.cc @@ -59,8 +59,14 @@ FlEngine* make_mock_engine() { fflush(stdout); g_autoptr(FlEngine) engine = fl_engine_new(project, FL_RENDERER(renderer)); g_autoptr(GError) engine_error = nullptr; + printf("mock engine: before engine start\n"); + fflush(stdout); EXPECT_TRUE(fl_engine_start(engine, &engine_error)); + printf("mock engine: after engine start\n"); + fflush(stdout); EXPECT_EQ(engine_error, nullptr); + printf("mock engine: before return\n"); + fflush(stdout); return static_cast(g_object_ref(engine)); } From c1a043388884aaa47de7837405028db263e2051b Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Wed, 19 May 2021 04:40:45 -0700 Subject: [PATCH 116/126] Add signal disconnection --- shell/platform/linux/fl_settings_plugin.cc | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/shell/platform/linux/fl_settings_plugin.cc b/shell/platform/linux/fl_settings_plugin.cc index db1896108aad1..86568fad4eddd 100644 --- a/shell/platform/linux/fl_settings_plugin.cc +++ b/shell/platform/linux/fl_settings_plugin.cc @@ -31,6 +31,8 @@ struct _FlSettingsPlugin { FlBasicMessageChannel* channel; GSettings* interface_settings; + + GArray* connections; }; G_DEFINE_TYPE(FlSettingsPlugin, fl_settings_plugin, G_TYPE_OBJECT) @@ -112,6 +114,10 @@ static void update_settings(FlSettingsPlugin* self) { static void fl_settings_plugin_dispose(GObject* object) { FlSettingsPlugin* self = FL_SETTINGS_PLUGIN(object); + for (guint i = 0; i < self->connections->len; i += 1) { + g_signal_handler_disconnect(self->interface_settings, self->connections[i]); + } + g_array_unref(self->connections); g_clear_object(&self->channel); g_clear_object(&self->interface_settings); @@ -133,6 +139,7 @@ FlSettingsPlugin* fl_settings_plugin_new(FlBinaryMessenger* messenger) { g_autoptr(FlJsonMessageCodec) codec = fl_json_message_codec_new(); self->channel = fl_basic_message_channel_new(messenger, kChannelName, FL_MESSAGE_CODEC(codec)); + self->connections = g_array_new(FALSE, FALSE, sizeof(gulong)); return self; } @@ -147,15 +154,18 @@ void fl_settings_plugin_start(FlSettingsPlugin* self) { g_settings_schema_source_lookup(source, kDesktopInterfaceSchema, FALSE); if (schema != nullptr) { self->interface_settings = g_settings_new_full(schema, nullptr, nullptr); - g_signal_connect_object( + g_array_append_val(connections, + g_signal_connect_object( self->interface_settings, "changed::text-scaling-factor", - G_CALLBACK(update_settings), self, G_CONNECT_SWAPPED); - g_signal_connect_object(self->interface_settings, "changed::clock-format", + G_CALLBACK(update_settings), self, G_CONNECT_SWAPPED)); + g_array_append_val(connections, + g_signal_connect_object(self->interface_settings, "changed::clock-format", G_CALLBACK(update_settings), self, - G_CONNECT_SWAPPED); - g_signal_connect_object(self->interface_settings, "changed::gtk-theme", + G_CONNECT_SWAPPED)); + g_array_append_val(connections, + g_signal_connect_object(self->interface_settings, "changed::gtk-theme", G_CALLBACK(update_settings), self, - G_CONNECT_SWAPPED); + G_CONNECT_SWAPPED)); } } From e3a4fe6032f0b98a126600fd5b1e2c562b1db9e3 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Wed, 19 May 2021 04:52:56 -0700 Subject: [PATCH 117/126] Format --- shell/platform/linux/fl_settings_plugin.cc | 28 ++++++++++++---------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/shell/platform/linux/fl_settings_plugin.cc b/shell/platform/linux/fl_settings_plugin.cc index 86568fad4eddd..c7b31a466bd2d 100644 --- a/shell/platform/linux/fl_settings_plugin.cc +++ b/shell/platform/linux/fl_settings_plugin.cc @@ -115,7 +115,8 @@ static void fl_settings_plugin_dispose(GObject* object) { FlSettingsPlugin* self = FL_SETTINGS_PLUGIN(object); for (guint i = 0; i < self->connections->len; i += 1) { - g_signal_handler_disconnect(self->interface_settings, self->connections[i]); + g_signal_handler_disconnect(self->interface_settings, + g_array_index(self->connections, gulong, i)); } g_array_unref(self->connections); g_clear_object(&self->channel); @@ -154,18 +155,19 @@ void fl_settings_plugin_start(FlSettingsPlugin* self) { g_settings_schema_source_lookup(source, kDesktopInterfaceSchema, FALSE); if (schema != nullptr) { self->interface_settings = g_settings_new_full(schema, nullptr, nullptr); - g_array_append_val(connections, - g_signal_connect_object( - self->interface_settings, "changed::text-scaling-factor", - G_CALLBACK(update_settings), self, G_CONNECT_SWAPPED)); - g_array_append_val(connections, - g_signal_connect_object(self->interface_settings, "changed::clock-format", - G_CALLBACK(update_settings), self, - G_CONNECT_SWAPPED)); - g_array_append_val(connections, - g_signal_connect_object(self->interface_settings, "changed::gtk-theme", - G_CALLBACK(update_settings), self, - G_CONNECT_SWAPPED)); + gulong new_connections[] = { + g_signal_connect_object( + self->interface_settings, "changed::text-scaling-factor", + G_CALLBACK(update_settings), self, G_CONNECT_SWAPPED), + g_signal_connect_object( + self->interface_settings, "changed::clock-format", + G_CALLBACK(update_settings), self, G_CONNECT_SWAPPED), + g_signal_connect_object( + self->interface_settings, "changed::gtk-theme", + G_CALLBACK(update_settings), self, G_CONNECT_SWAPPED), + }; + g_array_append_vals(self->connections, new_connections, + sizeof(new_connections) / sizeof(gulong)); } } From b807dbe9abc6a9a7acca79fae581d80ac5f65cf2 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Wed, 19 May 2021 05:16:15 -0700 Subject: [PATCH 118/126] More log --- shell/platform/linux/fl_engine.cc | 2 ++ shell/platform/linux/fl_settings_plugin.cc | 12 ++++++++++++ 2 files changed, 14 insertions(+) diff --git a/shell/platform/linux/fl_engine.cc b/shell/platform/linux/fl_engine.cc index 993627a142477..2dec03944ea95 100644 --- a/shell/platform/linux/fl_engine.cc +++ b/shell/platform/linux/fl_engine.cc @@ -465,6 +465,8 @@ gboolean fl_engine_start(FlEngine* self, GError** error) { printf("engine start: fl_settings_plugin_new\n"); fflush(stdout); self->settings_plugin = fl_settings_plugin_new(self->binary_messenger); + printf("engine start: fl_settings_plugin_start\n"); + fflush(stdout); fl_settings_plugin_start(self->settings_plugin); printf("engine start: UpdateSemanticsEnabled\n"); diff --git a/shell/platform/linux/fl_settings_plugin.cc b/shell/platform/linux/fl_settings_plugin.cc index c7b31a466bd2d..7b4fce0e2611a 100644 --- a/shell/platform/linux/fl_settings_plugin.cc +++ b/shell/platform/linux/fl_settings_plugin.cc @@ -138,8 +138,12 @@ FlSettingsPlugin* fl_settings_plugin_new(FlBinaryMessenger* messenger) { FL_SETTINGS_PLUGIN(g_object_new(fl_settings_plugin_get_type(), nullptr)); g_autoptr(FlJsonMessageCodec) codec = fl_json_message_codec_new(); + printf("plugin init: before channel\n"); + fflush(stdout); self->channel = fl_basic_message_channel_new(messenger, kChannelName, FL_MESSAGE_CODEC(codec)); + printf("plugin init: before connections\n"); + fflush(stdout); self->connections = g_array_new(FALSE, FALSE, sizeof(gulong)); return self; @@ -149,12 +153,18 @@ void fl_settings_plugin_start(FlSettingsPlugin* self) { g_return_if_fail(FL_IS_SETTINGS_PLUGIN(self)); // If we are on GNOME, get settings from GSettings. + printf("plugin start: before source\n"); + fflush(stdout); GSettingsSchemaSource* source = g_settings_schema_source_get_default(); if (source != nullptr) { + printf("plugin start: before schema\n"); + fflush(stdout); g_autoptr(GSettingsSchema) schema = g_settings_schema_source_lookup(source, kDesktopInterfaceSchema, FALSE); if (schema != nullptr) { self->interface_settings = g_settings_new_full(schema, nullptr, nullptr); + printf("plugin start: before new connections\n"); + fflush(stdout); gulong new_connections[] = { g_signal_connect_object( self->interface_settings, "changed::text-scaling-factor", @@ -166,6 +176,8 @@ void fl_settings_plugin_start(FlSettingsPlugin* self) { self->interface_settings, "changed::gtk-theme", G_CALLBACK(update_settings), self, G_CONNECT_SWAPPED), }; + printf("plugin start: after new connections\n"); + fflush(stdout); g_array_append_vals(self->connections, new_connections, sizeof(new_connections) / sizeof(gulong)); } From 62dbc93054268e55c9eb484974b87c67acb14486 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Wed, 19 May 2021 05:30:32 -0700 Subject: [PATCH 119/126] More print --- shell/platform/linux/fl_settings_plugin.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/shell/platform/linux/fl_settings_plugin.cc b/shell/platform/linux/fl_settings_plugin.cc index 7b4fce0e2611a..22777f9604b22 100644 --- a/shell/platform/linux/fl_settings_plugin.cc +++ b/shell/platform/linux/fl_settings_plugin.cc @@ -162,6 +162,8 @@ void fl_settings_plugin_start(FlSettingsPlugin* self) { g_autoptr(GSettingsSchema) schema = g_settings_schema_source_lookup(source, kDesktopInterfaceSchema, FALSE); if (schema != nullptr) { + printf("plugin start: before g_settings_new_full\n"); + fflush(stdout); self->interface_settings = g_settings_new_full(schema, nullptr, nullptr); printf("plugin start: before new connections\n"); fflush(stdout); @@ -183,5 +185,7 @@ void fl_settings_plugin_start(FlSettingsPlugin* self) { } } + printf("plugin start: before update_settings\n"); + fflush(stdout); update_settings(self); } From 9bb9e7bda6aae280c36dedd957591cde7cfc62c0 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Wed, 19 May 2021 05:32:32 -0700 Subject: [PATCH 120/126] Prints update_settings --- shell/platform/linux/fl_settings_plugin.cc | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/shell/platform/linux/fl_settings_plugin.cc b/shell/platform/linux/fl_settings_plugin.cc index 22777f9604b22..4f53d78bce003 100644 --- a/shell/platform/linux/fl_settings_plugin.cc +++ b/shell/platform/linux/fl_settings_plugin.cc @@ -88,18 +88,28 @@ static void update_settings(FlSettingsPlugin* self) { gboolean always_use_24hr = FALSE; const gchar* platform_brightness = kPlatformBrightnessLight; + printf("update_settings: before interface_settings\n"); + fflush(stdout); if (self->interface_settings != nullptr) { + printf("update_settings: before kDesktopTextScalingFactorKey\n"); + fflush(stdout); scaling_factor = g_settings_get_double(self->interface_settings, kDesktopTextScalingFactorKey); + printf("update_settings: before kDesktopClockFormatKey\n"); + fflush(stdout); g_autofree gchar* clock_format = g_settings_get_string(self->interface_settings, kDesktopClockFormatKey); always_use_24hr = g_strcmp0(clock_format, kClockFormat24Hour) == 0; } + printf("update_settings: before is_dark_theme\n"); + fflush(stdout); if (is_dark_theme()) { platform_brightness = kPlatformBrightnessDark; } + printf("update_settings: before setting values\n"); + fflush(stdout); g_autoptr(FlValue) message = fl_value_new_map(); fl_value_set_string_take(message, kTextScaleFactorKey, fl_value_new_float(scaling_factor)); @@ -107,6 +117,8 @@ static void update_settings(FlSettingsPlugin* self) { fl_value_new_bool(always_use_24hr)); fl_value_set_string_take(message, kPlatformBrightnessKey, fl_value_new_string(platform_brightness)); + printf("update_settings: before sending values\n"); + fflush(stdout); fl_basic_message_channel_send(self->channel, message, nullptr, nullptr, nullptr); } From 6bf9fde14bd5a70774bbf7a1aa239bf78e18936c Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Wed, 19 May 2021 06:34:37 -0700 Subject: [PATCH 121/126] Remove logs --- shell/platform/linux/fl_engine.cc | 26 ---- .../linux/fl_key_embedder_responder.cc | 20 +-- .../linux/fl_key_embedder_responder_test.cc | 121 +++++------------- shell/platform/linux/fl_key_event.cc | 18 +-- shell/platform/linux/fl_settings_plugin.cc | 28 ---- shell/platform/linux/testing/fl_test.cc | 12 -- 6 files changed, 38 insertions(+), 187 deletions(-) diff --git a/shell/platform/linux/fl_engine.cc b/shell/platform/linux/fl_engine.cc index 2dec03944ea95..116fd3f5c7e18 100644 --- a/shell/platform/linux/fl_engine.cc +++ b/shell/platform/linux/fl_engine.cc @@ -353,8 +353,6 @@ gboolean fl_engine_start(FlEngine* self, GError** error) { self->task_runner = fl_task_runner_new(self); - printf("engine start: before config\n"); - fflush(stdout); FlutterRendererConfig config = {}; config.type = kOpenGL; config.open_gl.struct_size = sizeof(FlutterOpenGLRendererConfig); @@ -365,8 +363,6 @@ gboolean fl_engine_start(FlEngine* self, GError** error) { config.open_gl.present = fl_engine_gl_present; config.open_gl.make_resource_current = fl_engine_gl_make_resource_current; - printf("engine start: platform_task_runner\n"); - fflush(stdout); FlutterTaskRunnerDescription platform_task_runner = {}; platform_task_runner.struct_size = sizeof(FlutterTaskRunnerDescription); platform_task_runner.user_data = self; @@ -375,15 +371,11 @@ gboolean fl_engine_start(FlEngine* self, GError** error) { platform_task_runner.post_task_callback = fl_engine_post_task; platform_task_runner.identifier = kPlatformTaskRunnerIdentifier; - printf("engine start: custom_task_runners\n"); - fflush(stdout); FlutterCustomTaskRunners custom_task_runners = {}; custom_task_runners.struct_size = sizeof(FlutterCustomTaskRunners); custom_task_runners.platform_task_runner = &platform_task_runner; custom_task_runners.render_task_runner = &platform_task_runner; - printf("engine start: command_line_args\n"); - fflush(stdout); g_autoptr(GPtrArray) command_line_args = fl_dart_project_get_switches(self->project); // FlutterProjectArgs expects a full argv, so when processing it for flags @@ -391,8 +383,6 @@ gboolean fl_engine_start(FlEngine* self, GError** error) { // so that all switches are used. g_ptr_array_insert(command_line_args, 0, g_strdup("flutter")); - printf("engine start: dart_entrypoint_args\n"); - fflush(stdout); gchar** dart_entrypoint_args = fl_dart_project_get_dart_entrypoint_arguments(self->project); @@ -412,8 +402,6 @@ gboolean fl_engine_start(FlEngine* self, GError** error) { args.dart_entrypoint_argv = reinterpret_cast(dart_entrypoint_args); - printf("engine start: compositor\n"); - fflush(stdout); FlutterCompositor compositor = {}; compositor.struct_size = sizeof(FlutterCompositor); compositor.user_data = self->renderer; @@ -424,8 +412,6 @@ gboolean fl_engine_start(FlEngine* self, GError** error) { compositor.present_layers_callback = compositor_present_layers_callback; args.compositor = &compositor; - printf("engine start: RunsAOTCompiledDartCode\n"); - fflush(stdout); if (self->embedder_api.RunsAOTCompiledDartCode()) { FlutterEngineAOTDataSource source = {}; source.type = kFlutterEngineAOTDataSourceTypeElfPath; @@ -439,8 +425,6 @@ gboolean fl_engine_start(FlEngine* self, GError** error) { args.aot_data = self->aot_data; } - printf("engine start: Initialize\n"); - fflush(stdout); FlutterEngineResult result = self->embedder_api.Initialize( FLUTTER_ENGINE_VERSION, &config, &args, self, &self->engine); if (result != kSuccess) { @@ -449,8 +433,6 @@ gboolean fl_engine_start(FlEngine* self, GError** error) { return FALSE; } - printf("engine start: RunInitialized\n"); - fflush(stdout); result = self->embedder_api.RunInitialized(self->engine); if (result != kSuccess) { g_set_error(error, fl_engine_error_quark(), FL_ENGINE_ERROR_FAILED, @@ -458,19 +440,11 @@ gboolean fl_engine_start(FlEngine* self, GError** error) { return FALSE; } - printf("engine start: setup_locales\n"); - fflush(stdout); setup_locales(self); - printf("engine start: fl_settings_plugin_new\n"); - fflush(stdout); self->settings_plugin = fl_settings_plugin_new(self->binary_messenger); - printf("engine start: fl_settings_plugin_start\n"); - fflush(stdout); fl_settings_plugin_start(self->settings_plugin); - printf("engine start: UpdateSemanticsEnabled\n"); - fflush(stdout); result = self->embedder_api.UpdateSemanticsEnabled(self->engine, TRUE); if (result != kSuccess) g_warning("Failed to enable accessibility features on Flutter engine"); diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index ff71117f8a8ac..a8cb78aa0911c 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -12,17 +12,6 @@ #include "flutter/shell/platform/linux/fl_key_embedder_responder_private.h" #include "flutter/shell/platform/linux/key_mapping.h" -#if 1 -#define TRACE(x) \ - printf("before " #x "\n"); \ - fflush(stdout); \ - x; \ - printf("after " #x "\n"); \ - fflush(stdout); -#else -#define TRACE(x) x -#endif - // The code prefix for unrecognized keys that are unique to Gtk, generated from // platform-specific codes. constexpr uint64_t kGtkKeyIdPlane = 0x00600000000; @@ -345,7 +334,7 @@ static void synthesize_simple_event(FlKeyEmbedderResponder* self, out_event.character = nullptr; out_event.synthesized = true; if (self->engine != nullptr) { - TRACE(fl_engine_send_key_event(self->engine, &out_event, nullptr, nullptr)); + fl_engine_send_key_event(self->engine, &out_event, nullptr, nullptr); } } @@ -619,7 +608,6 @@ static void synchronize_lock_states_loop_body(gpointer key, g_return_if_fail(pressed_logical_key == 0 || pressed_logical_key == logical_key); - fflush(stdout); const int stage_by_record = find_stage_by_record( pressed_logical_key != 0, (self->lock_records & modifier_bit) != 0); @@ -751,9 +739,9 @@ static void fl_key_embedder_responder_handle_event( if (self->engine != nullptr) { FlKeyEmbedderUserData* response_data = fl_key_embedder_user_data_new(callback, user_data); - TRACE(fl_engine_send_key_event(self->engine, &out_event, handle_response, - response_data)); + fl_engine_send_key_event(self->engine, &out_event, handle_response, + response_data); } else { - TRACE(callback(true, user_data)); + callback(true, user_data); } } diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index a5d58e1fcd18b..73d9d9fc9b94a 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -11,22 +11,6 @@ #include "flutter/shell/platform/linux/fl_engine_private.h" #include "flutter/shell/platform/linux/testing/fl_test.h" -#if 1 -#define TRACE(x) \ - printf("before " #x "\n"); \ - fflush(stdout); \ - x printf("after " #x "\n"); \ - fflush(stdout); -#define TRACEI(x, i) \ - printf("before " #x " %d\n", __LINE__); \ - fflush(stdout); \ - x printf("after " #x " %d\n", __LINE__); \ - fflush(stdout); -#else -#define TRACE(x) x -#define TRACEI(x, i) x -#endif - namespace { constexpr gboolean kRelease = FALSE; constexpr gboolean kPress = TRUE; @@ -59,7 +43,7 @@ constexpr uint64_t kLogicalCapsLock = 0x1000000104; } // namespace static void g_ptr_array_clear(GPtrArray* array) { - TRACE(g_ptr_array_remove_range(array, 0, array->len);); + g_ptr_array_remove_range(array, 0, array->len); } G_DECLARE_FINAL_TYPE(FlKeyEmbedderCallRecord, @@ -88,8 +72,8 @@ static void fl_key_embedder_call_record_dispose(GObject* object) { FlKeyEmbedderCallRecord* self = FL_KEY_EMBEDDER_CALL_RECORD(object); if (self->event != nullptr) { - TRACE(g_free(const_cast(self->event->character));); - TRACE(g_free(self->event);); + g_free(const_cast(self->event->character)); + g_free(self->event); } G_OBJECT_CLASS(fl_key_embedder_call_record_parent_class)->dispose(object); } @@ -175,20 +159,14 @@ GPtrArray* g_call_records; static FlEngine* make_mock_engine_with_records() { FlEngine* engine = make_mock_engine(); - printf("After mock engine\n"); FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine); - printf("After get API\n"); embedder_api->SendKeyEvent = [](auto engine, const FlutterKeyEvent* event, FlutterKeyEventCallback callback, void* user_data) { - printf("Before adding records\n"); - fflush(stdout); if (g_call_records != nullptr) { g_ptr_array_add(g_call_records, fl_key_embedder_call_record_new( event, callback, user_data)); } - printf("After adding records\n"); - fflush(stdout); return kSuccess; }; @@ -196,20 +174,17 @@ static FlEngine* make_mock_engine_with_records() { } static void clear_g_call_records() { - TRACE(g_ptr_array_free(g_call_records, TRUE);); + g_ptr_array_free(g_call_records, TRUE); g_call_records = nullptr; } // Basic key presses TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { - printf("New test\n"); - fflush(stdout); EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); FlEngine* engine = make_mock_engine_with_records(); FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); - printf("After create responder\n"); int user_data = 123; // Arbitrary user data FlKeyEmbedderCallRecord* record; @@ -299,20 +274,17 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { TRACEI(g_ptr_array_clear(g_call_records);, 4); clear_g_call_records(); - TRACE(g_object_unref(responder);); - TRACE(g_object_unref(engine);); + g_object_unref(responder); + g_object_unref(engine); } // Press Shift, key A, then release Shift, key A. TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { - printf("New test\n"); - fflush(stdout); EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); FlEngine* engine = make_mock_engine_with_records(); FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); - printf("After create responder\n"); int user_data = 123; // Arbitrary user data FlKeyEmbedderCallRecord* record; @@ -390,8 +362,8 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); - TRACE(g_object_unref(responder);); - TRACE(g_object_unref(engine);); + g_object_unref(responder); + g_object_unref(engine); } // Press or release Numpad 1 between presses/releases of NumLock. @@ -403,14 +375,11 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { // test-worthy because the keyval for the numpad key will change before and // after the NumLock tap, which should not alter the resulting logical key. TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { - printf("New test\n"); - fflush(stdout); EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); FlEngine* engine = make_mock_engine_with_records(); FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); - printf("After create responder\n"); int user_data = 123; // Arbitrary user data FlKeyEmbedderCallRecord* record; @@ -560,8 +529,8 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); - TRACE(g_object_unref(responder);); - TRACE(g_object_unref(engine);); + g_object_unref(responder); + g_object_unref(engine); } // Press or release letter key between presses/releases of CapsLock. @@ -569,14 +538,11 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { // This tests interaction between lock keys and non-lock keys in cases that do // not have events missed. TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { - printf("New test\n"); - fflush(stdout); EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); FlEngine* engine = make_mock_engine_with_records(); FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); - printf("After create responder\n"); int user_data = 123; // Arbitrary user data FlKeyEmbedderCallRecord* record; @@ -726,8 +692,8 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); - TRACE(g_object_unref(responder);); - TRACE(g_object_unref(engine);); + g_object_unref(responder); + g_object_unref(engine); } // Press or release letter key between presses/releases of CapsLock, on @@ -735,14 +701,11 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { // // This happens when using a Chrome remote desktop on MacOS. TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { - printf("New test\n"); - fflush(stdout); EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); FlEngine* engine = make_mock_engine_with_records(); FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); - printf("After create responder\n"); int user_data = 123; // Arbitrary user data FlKeyEmbedderCallRecord* record; @@ -892,19 +855,16 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { TRACEI(g_ptr_array_clear(g_call_records);, 8); clear_g_call_records(); - TRACE(g_object_unref(responder);); - TRACE(g_object_unref(engine);); + g_object_unref(responder); + g_object_unref(engine); } TEST(FlKeyEmbedderResponderTest, IgnoreDuplicateDownEvent) { - printf("New test\n"); - fflush(stdout); EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); FlEngine* engine = make_mock_engine_with_records(); FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); - printf("After create responder\n"); int user_data = 123; // Arbitrary user data FlKeyEmbedderCallRecord* record; @@ -946,19 +906,16 @@ TEST(FlKeyEmbedderResponderTest, IgnoreDuplicateDownEvent) { TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); - TRACE(g_object_unref(responder);); - TRACE(g_object_unref(engine);); + g_object_unref(responder); + g_object_unref(engine); } TEST(FlKeyEmbedderResponderTest, IgnoreAbruptUpEvent) { - printf("New test\n"); - fflush(stdout); EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); FlEngine* engine = make_mock_engine_with_records(); FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); - printf("After create responder\n"); int user_data = 123; // Arbitrary user data // Release KeyA before it was even pressed. @@ -972,21 +929,18 @@ TEST(FlKeyEmbedderResponderTest, IgnoreAbruptUpEvent) { EXPECT_EQ(g_call_records->len, 0u); clear_g_call_records(); - TRACE(g_object_unref(responder);); - TRACE(g_object_unref(engine);); + g_object_unref(responder); + g_object_unref(engine); } // Test if missed modifier keys can be detected and synthesized with state // information upon events that are for this modifier key. TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) { - printf("New test\n"); - fflush(stdout); EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); FlEngine* engine = make_mock_engine_with_records(); FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); - printf("After create responder\n"); int user_data = 123; // Arbitrary user data FlKeyEmbedderCallRecord* record; @@ -1107,22 +1061,19 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) { TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); - TRACE(g_object_unref(responder);); - TRACE(g_object_unref(engine);); + g_object_unref(responder); + g_object_unref(engine); } // Test if missed modifier keys can be detected and synthesized with state // information upon events that are not for this modifier key. TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnNonSelfEvents) { - printf("New test\n"); - fflush(stdout); EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); FlEngine* engine = make_mock_engine_with_records(); FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); - printf("After create responder\n"); int user_data = 123; // Arbitrary user data FlKeyEmbedderCallRecord* record; @@ -1243,22 +1194,19 @@ TEST(FlKeyEmbedderResponderTest, TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); - TRACE(g_object_unref(responder);); - TRACE(g_object_unref(engine);); + g_object_unref(responder); + g_object_unref(engine); } // Test if missed modifier keys can be detected and synthesized with state // information upon events that do not have the standard key mapping. TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnRemappedEvents) { - printf("New test\n"); - fflush(stdout); EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); FlEngine* engine = make_mock_engine_with_records(); FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); - printf("After create responder\n"); int user_data = 123; // Arbitrary user data FlKeyEmbedderCallRecord* record; @@ -1317,21 +1265,18 @@ TEST(FlKeyEmbedderResponderTest, TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); - TRACE(g_object_unref(responder);); - TRACE(g_object_unref(engine);); + g_object_unref(responder); + g_object_unref(engine); } // Test if missed lock keys can be detected and synthesized with state // information upon events that are not for this modifier key. TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { - printf("New test\n"); - fflush(stdout); EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); FlEngine* engine = make_mock_engine_with_records(); FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); - printf("After create responder\n"); int user_data = 123; // Arbitrary user data FlKeyEmbedderCallRecord* record; @@ -1424,21 +1369,18 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { EXPECT_EQ(g_call_records->len, 0u); clear_g_call_records(); - TRACE(g_object_unref(responder);); - TRACE(g_object_unref(engine);); + g_object_unref(responder); + g_object_unref(engine); } // Test if missed lock keys can be detected and synthesized with state // information upon events that are for this modifier key. TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) { - printf("New test\n"); - fflush(stdout); EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); FlEngine* engine = make_mock_engine_with_records(); FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); - printf("After create responder\n"); int user_data = 123; // Arbitrary user data FlKeyEmbedderCallRecord* record; @@ -1528,21 +1470,18 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) { TRACEI(g_ptr_array_clear(g_call_records);, 2); clear_g_call_records(); - TRACE(g_object_unref(responder);); - TRACE(g_object_unref(engine);); + g_object_unref(responder); + g_object_unref(engine); } // Ensures that even if the primary event is ignored (due to duplicate // key up or down events), key synthesization is still performed. TEST(FlKeyEmbedderResponderTest, SynthesizationOccursOnIgnoredEvents) { - printf("New test\n"); - fflush(stdout); EXPECT_EQ(g_call_records, nullptr); g_call_records = g_ptr_array_new_with_free_func(g_object_unref); FlEngine* engine = make_mock_engine_with_records(); FlKeyResponder* responder = FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); - printf("After create responder\n"); int user_data = 123; // Arbitrary user data FlKeyEmbedderCallRecord* record; @@ -1578,6 +1517,6 @@ TEST(FlKeyEmbedderResponderTest, SynthesizationOccursOnIgnoredEvents) { TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); - TRACE(g_object_unref(responder);); - TRACE(g_object_unref(engine);); + g_object_unref(responder); + g_object_unref(engine); } diff --git a/shell/platform/linux/fl_key_event.cc b/shell/platform/linux/fl_key_event.cc index 46e4157f8a101..b823a3377ae16 100644 --- a/shell/platform/linux/fl_key_event.cc +++ b/shell/platform/linux/fl_key_event.cc @@ -4,19 +4,9 @@ #include "flutter/shell/platform/linux/fl_key_event.h" -#if 0 -#define TRACE(x) \ - printf("before " #x "\n"); \ - fflush(stdout); \ - x printf("after " #x "\n"); \ - fflush(stdout); -#else -#define TRACE(x) x -#endif - static void dispose_origin_from_gdk_event(gpointer origin) { g_return_if_fail(origin != nullptr); - TRACE(gdk_event_free(reinterpret_cast(origin));); + gdk_event_free(reinterpret_cast(origin)); } static char* clone_string(const char* source) { @@ -51,12 +41,12 @@ FlKeyEvent* fl_key_event_new_from_gdk_event(GdkEvent* raw_event) { void fl_key_event_dispose(FlKeyEvent* event) { if (event->string != nullptr) { - TRACE(g_free(const_cast(event->string));); + g_free(const_cast(event->string)); } if (event->dispose_origin != nullptr) { - TRACE(event->dispose_origin(event->origin);); + event->dispose_origin(event->origin); } - TRACE(g_free(event);); + g_free(event); } FlKeyEvent* fl_key_event_clone(const FlKeyEvent* event) { diff --git a/shell/platform/linux/fl_settings_plugin.cc b/shell/platform/linux/fl_settings_plugin.cc index 4f53d78bce003..c7b31a466bd2d 100644 --- a/shell/platform/linux/fl_settings_plugin.cc +++ b/shell/platform/linux/fl_settings_plugin.cc @@ -88,28 +88,18 @@ static void update_settings(FlSettingsPlugin* self) { gboolean always_use_24hr = FALSE; const gchar* platform_brightness = kPlatformBrightnessLight; - printf("update_settings: before interface_settings\n"); - fflush(stdout); if (self->interface_settings != nullptr) { - printf("update_settings: before kDesktopTextScalingFactorKey\n"); - fflush(stdout); scaling_factor = g_settings_get_double(self->interface_settings, kDesktopTextScalingFactorKey); - printf("update_settings: before kDesktopClockFormatKey\n"); - fflush(stdout); g_autofree gchar* clock_format = g_settings_get_string(self->interface_settings, kDesktopClockFormatKey); always_use_24hr = g_strcmp0(clock_format, kClockFormat24Hour) == 0; } - printf("update_settings: before is_dark_theme\n"); - fflush(stdout); if (is_dark_theme()) { platform_brightness = kPlatformBrightnessDark; } - printf("update_settings: before setting values\n"); - fflush(stdout); g_autoptr(FlValue) message = fl_value_new_map(); fl_value_set_string_take(message, kTextScaleFactorKey, fl_value_new_float(scaling_factor)); @@ -117,8 +107,6 @@ static void update_settings(FlSettingsPlugin* self) { fl_value_new_bool(always_use_24hr)); fl_value_set_string_take(message, kPlatformBrightnessKey, fl_value_new_string(platform_brightness)); - printf("update_settings: before sending values\n"); - fflush(stdout); fl_basic_message_channel_send(self->channel, message, nullptr, nullptr, nullptr); } @@ -150,12 +138,8 @@ FlSettingsPlugin* fl_settings_plugin_new(FlBinaryMessenger* messenger) { FL_SETTINGS_PLUGIN(g_object_new(fl_settings_plugin_get_type(), nullptr)); g_autoptr(FlJsonMessageCodec) codec = fl_json_message_codec_new(); - printf("plugin init: before channel\n"); - fflush(stdout); self->channel = fl_basic_message_channel_new(messenger, kChannelName, FL_MESSAGE_CODEC(codec)); - printf("plugin init: before connections\n"); - fflush(stdout); self->connections = g_array_new(FALSE, FALSE, sizeof(gulong)); return self; @@ -165,20 +149,12 @@ void fl_settings_plugin_start(FlSettingsPlugin* self) { g_return_if_fail(FL_IS_SETTINGS_PLUGIN(self)); // If we are on GNOME, get settings from GSettings. - printf("plugin start: before source\n"); - fflush(stdout); GSettingsSchemaSource* source = g_settings_schema_source_get_default(); if (source != nullptr) { - printf("plugin start: before schema\n"); - fflush(stdout); g_autoptr(GSettingsSchema) schema = g_settings_schema_source_lookup(source, kDesktopInterfaceSchema, FALSE); if (schema != nullptr) { - printf("plugin start: before g_settings_new_full\n"); - fflush(stdout); self->interface_settings = g_settings_new_full(schema, nullptr, nullptr); - printf("plugin start: before new connections\n"); - fflush(stdout); gulong new_connections[] = { g_signal_connect_object( self->interface_settings, "changed::text-scaling-factor", @@ -190,14 +166,10 @@ void fl_settings_plugin_start(FlSettingsPlugin* self) { self->interface_settings, "changed::gtk-theme", G_CALLBACK(update_settings), self, G_CONNECT_SWAPPED), }; - printf("plugin start: after new connections\n"); - fflush(stdout); g_array_append_vals(self->connections, new_connections, sizeof(new_connections) / sizeof(gulong)); } } - printf("plugin start: before update_settings\n"); - fflush(stdout); update_settings(self); } diff --git a/shell/platform/linux/testing/fl_test.cc b/shell/platform/linux/testing/fl_test.cc index 0fe7d33c3236f..15de90e557ac4 100644 --- a/shell/platform/linux/testing/fl_test.cc +++ b/shell/platform/linux/testing/fl_test.cc @@ -49,24 +49,12 @@ gchar* bytes_to_hex_string(GBytes* bytes) { } FlEngine* make_mock_engine() { - printf("mock engine: before project\n"); - fflush(stdout); g_autoptr(FlDartProject) project = fl_dart_project_new(); - printf("mock engine: before renderer\n"); - fflush(stdout); g_autoptr(FlMockRenderer) renderer = fl_mock_renderer_new(); - printf("mock engine: before engine\n"); - fflush(stdout); g_autoptr(FlEngine) engine = fl_engine_new(project, FL_RENDERER(renderer)); g_autoptr(GError) engine_error = nullptr; - printf("mock engine: before engine start\n"); - fflush(stdout); EXPECT_TRUE(fl_engine_start(engine, &engine_error)); - printf("mock engine: after engine start\n"); - fflush(stdout); EXPECT_EQ(engine_error, nullptr); - printf("mock engine: before return\n"); - fflush(stdout); return static_cast(g_object_ref(engine)); } From a8b69d4f8a5316e3cb83ef829e79e0ab8d4ab80c Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Wed, 19 May 2021 06:36:03 -0700 Subject: [PATCH 122/126] Adjust order --- .../linux/fl_key_embedder_responder_test.cc | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index 73d9d9fc9b94a..8a5f4945b0175 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -274,8 +274,8 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { TRACEI(g_ptr_array_clear(g_call_records);, 4); clear_g_call_records(); - g_object_unref(responder); g_object_unref(engine); + g_object_unref(responder); } // Press Shift, key A, then release Shift, key A. @@ -362,8 +362,8 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); - g_object_unref(responder); g_object_unref(engine); + g_object_unref(responder); } // Press or release Numpad 1 between presses/releases of NumLock. @@ -529,8 +529,8 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); - g_object_unref(responder); g_object_unref(engine); + g_object_unref(responder); } // Press or release letter key between presses/releases of CapsLock. @@ -692,8 +692,8 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); - g_object_unref(responder); g_object_unref(engine); + g_object_unref(responder); } // Press or release letter key between presses/releases of CapsLock, on @@ -855,8 +855,8 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { TRACEI(g_ptr_array_clear(g_call_records);, 8); clear_g_call_records(); - g_object_unref(responder); g_object_unref(engine); + g_object_unref(responder); } TEST(FlKeyEmbedderResponderTest, IgnoreDuplicateDownEvent) { @@ -906,8 +906,8 @@ TEST(FlKeyEmbedderResponderTest, IgnoreDuplicateDownEvent) { TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); - g_object_unref(responder); g_object_unref(engine); + g_object_unref(responder); } TEST(FlKeyEmbedderResponderTest, IgnoreAbruptUpEvent) { @@ -929,8 +929,8 @@ TEST(FlKeyEmbedderResponderTest, IgnoreAbruptUpEvent) { EXPECT_EQ(g_call_records->len, 0u); clear_g_call_records(); - g_object_unref(responder); g_object_unref(engine); + g_object_unref(responder); } // Test if missed modifier keys can be detected and synthesized with state @@ -1061,8 +1061,8 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) { TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); - g_object_unref(responder); g_object_unref(engine); + g_object_unref(responder); } // Test if missed modifier keys can be detected and synthesized with state @@ -1194,8 +1194,8 @@ TEST(FlKeyEmbedderResponderTest, TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); - g_object_unref(responder); g_object_unref(engine); + g_object_unref(responder); } // Test if missed modifier keys can be detected and synthesized with state @@ -1265,8 +1265,8 @@ TEST(FlKeyEmbedderResponderTest, TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); - g_object_unref(responder); g_object_unref(engine); + g_object_unref(responder); } // Test if missed lock keys can be detected and synthesized with state @@ -1369,8 +1369,8 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { EXPECT_EQ(g_call_records->len, 0u); clear_g_call_records(); - g_object_unref(responder); g_object_unref(engine); + g_object_unref(responder); } // Test if missed lock keys can be detected and synthesized with state @@ -1470,8 +1470,8 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) { TRACEI(g_ptr_array_clear(g_call_records);, 2); clear_g_call_records(); - g_object_unref(responder); g_object_unref(engine); + g_object_unref(responder); } // Ensures that even if the primary event is ignored (due to duplicate @@ -1517,6 +1517,6 @@ TEST(FlKeyEmbedderResponderTest, SynthesizationOccursOnIgnoredEvents) { TRACEI(g_ptr_array_clear(g_call_records);, 1); clear_g_call_records(); - g_object_unref(responder); g_object_unref(engine); + g_object_unref(responder); } From 89a271eb574669a6598673368eb6860384be22c1 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Wed, 19 May 2021 06:39:05 -0700 Subject: [PATCH 123/126] Format --- .../linux/fl_key_embedder_responder_test.cc | 100 +++++++++--------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index 8a5f4945b0175..c846b19143843 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -208,7 +208,7 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 1); + g_ptr_array_clear(g_call_records); // Skip testing key repeats, which is not present on GDK. @@ -230,7 +230,7 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, FALSE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 2); + g_ptr_array_clear(g_call_records); // On an AZERTY keyboard, press key Q (physically key A), and release. // Key down @@ -251,7 +251,7 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 3); + g_ptr_array_clear(g_call_records); // Key up fl_key_responder_handle_event( @@ -271,7 +271,7 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, FALSE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 4); + g_ptr_array_clear(g_call_records); clear_g_call_records(); g_object_unref(engine); @@ -305,7 +305,7 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 1); + g_ptr_array_clear(g_call_records); // Press key A fl_key_responder_handle_event( @@ -323,7 +323,7 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 1); + g_ptr_array_clear(g_call_records); // Release shift right fl_key_responder_handle_event( @@ -341,7 +341,7 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 1); + g_ptr_array_clear(g_call_records); // Release key A fl_key_responder_handle_event( @@ -359,7 +359,7 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 1); + g_ptr_array_clear(g_call_records); clear_g_call_records(); g_object_unref(engine); @@ -400,7 +400,7 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 1); + g_ptr_array_clear(g_call_records); // Press NumLock (stage 0 -> 1) fl_key_responder_handle_event( @@ -418,7 +418,7 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 1); + g_ptr_array_clear(g_call_records); // Release numpad 1 (stage 1) fl_key_responder_handle_event( @@ -436,7 +436,7 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 1); + g_ptr_array_clear(g_call_records); // Release NumLock (stage 1 -> 2) fl_key_responder_handle_event( @@ -454,7 +454,7 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 1); + g_ptr_array_clear(g_call_records); // Press Numpad 1 (stage 2) fl_key_responder_handle_event( @@ -472,7 +472,7 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 1); + g_ptr_array_clear(g_call_records); // Press NumLock (stage 2 -> 3) fl_key_responder_handle_event( @@ -490,7 +490,7 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 1); + g_ptr_array_clear(g_call_records); // Release numpad 1 (stage 3) fl_key_responder_handle_event( @@ -508,7 +508,7 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 1); + g_ptr_array_clear(g_call_records); // Release NumLock (stage 3 -> 0) fl_key_responder_handle_event( @@ -526,7 +526,7 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 1); + g_ptr_array_clear(g_call_records); clear_g_call_records(); g_object_unref(engine); @@ -563,7 +563,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 1); + g_ptr_array_clear(g_call_records); // Press key A (stage 1) fl_key_responder_handle_event( @@ -581,7 +581,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 1); + g_ptr_array_clear(g_call_records); // Release CapsLock (stage 1 -> 2) fl_key_responder_handle_event( @@ -599,7 +599,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 1); + g_ptr_array_clear(g_call_records); // Release key A (stage 2) fl_key_responder_handle_event( @@ -617,7 +617,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 1); + g_ptr_array_clear(g_call_records); // Press CapsLock (stage 2 -> 3) fl_key_responder_handle_event( @@ -635,7 +635,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 1); + g_ptr_array_clear(g_call_records); // Press key A (stage 3) fl_key_responder_handle_event( @@ -653,7 +653,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 1); + g_ptr_array_clear(g_call_records); // Release CapsLock (stage 3 -> 0) fl_key_responder_handle_event( @@ -671,7 +671,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 1); + g_ptr_array_clear(g_call_records); // Release key A (stage 0) fl_key_responder_handle_event( @@ -689,7 +689,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 1); + g_ptr_array_clear(g_call_records); clear_g_call_records(); g_object_unref(engine); @@ -726,7 +726,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 1); + g_ptr_array_clear(g_call_records); // Press CapsLock (stage 0 -> 1) fl_key_responder_handle_event( @@ -744,7 +744,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 2); + g_ptr_array_clear(g_call_records); // Release CapsLock (stage 1 -> 2) fl_key_responder_handle_event( @@ -762,7 +762,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 3); + g_ptr_array_clear(g_call_records); // Release key A (stage 2) fl_key_responder_handle_event( @@ -780,7 +780,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 4); + g_ptr_array_clear(g_call_records); // Press key A (stage 2) fl_key_responder_handle_event( @@ -798,7 +798,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 5); + g_ptr_array_clear(g_call_records); // Press CapsLock (stage 2 -> 3) fl_key_responder_handle_event( @@ -816,7 +816,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 6); + g_ptr_array_clear(g_call_records); // Release CapsLock (stage 3 -> 0) fl_key_responder_handle_event( @@ -834,7 +834,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 7); + g_ptr_array_clear(g_call_records); // Release key A (stage 0) fl_key_responder_handle_event( @@ -852,7 +852,7 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 8); + g_ptr_array_clear(g_call_records); clear_g_call_records(); g_object_unref(engine); @@ -880,7 +880,7 @@ TEST(FlKeyEmbedderResponderTest, IgnoreDuplicateDownEvent) { record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 1); + g_ptr_array_clear(g_call_records); // Press KeyA again (with different logical key, which is not necessari but // for coverage). @@ -903,7 +903,7 @@ TEST(FlKeyEmbedderResponderTest, IgnoreDuplicateDownEvent) { EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 1); + g_ptr_array_clear(g_call_records); clear_g_call_records(); g_object_unref(engine); @@ -975,7 +975,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 1); + g_ptr_array_clear(g_call_records); // Test 2: synthesize key up. @@ -989,7 +989,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) { EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 1); + g_ptr_array_clear(g_call_records); // A key up of control left is missed. state = 0; @@ -1019,7 +1019,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 1); + g_ptr_array_clear(g_call_records); // Send a ControlLeft up to clear up state. state = GDK_CONTROL_MASK; @@ -1031,7 +1031,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) { EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 1); + g_ptr_array_clear(g_call_records); // Test 3: synthesize by right modifier. @@ -1058,7 +1058,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) { EXPECT_STREQ(record->event->character, nullptr); EXPECT_EQ(record->event->synthesized, true); - TRACEI(g_ptr_array_clear(g_call_records);, 1); + g_ptr_array_clear(g_call_records); clear_g_call_records(); g_object_unref(engine); @@ -1106,7 +1106,7 @@ TEST(FlKeyEmbedderResponderTest, EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 1); + g_ptr_array_clear(g_call_records); // A key up of control left is missed. state = 0; @@ -1136,7 +1136,7 @@ TEST(FlKeyEmbedderResponderTest, EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 1); + g_ptr_array_clear(g_call_records); // Test non-default key mapping. @@ -1159,7 +1159,7 @@ TEST(FlKeyEmbedderResponderTest, EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 1); + g_ptr_array_clear(g_call_records); // The key up of the control left press is missed. state = 0; @@ -1191,7 +1191,7 @@ TEST(FlKeyEmbedderResponderTest, EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 1); + g_ptr_array_clear(g_call_records); clear_g_call_records(); g_object_unref(engine); @@ -1230,7 +1230,7 @@ TEST(FlKeyEmbedderResponderTest, EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 1); + g_ptr_array_clear(g_call_records); // The key up of the control left press is missed. state = 0; @@ -1262,7 +1262,7 @@ TEST(FlKeyEmbedderResponderTest, EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 1); + g_ptr_array_clear(g_call_records); clear_g_call_records(); g_object_unref(engine); @@ -1309,7 +1309,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 1); + g_ptr_array_clear(g_call_records); // The NumLock is desynchronized by being disabled. state = 0; @@ -1355,7 +1355,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 2); + g_ptr_array_clear(g_call_records); // Release NumLock. Since the previous event should have synthesized NumLock // to be released, this should result in no events. @@ -1421,7 +1421,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 1); + g_ptr_array_clear(g_call_records); // The NumLock is desynchronized by being enabled in a press event. state = GDK_MOD2_MASK; @@ -1467,7 +1467,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) { EXPECT_EQ(record->event->synthesized, false); invoke_record_callback_and_verify(record, TRUE, &user_data); - TRACEI(g_ptr_array_clear(g_call_records);, 2); + g_ptr_array_clear(g_call_records); clear_g_call_records(); g_object_unref(engine); @@ -1514,7 +1514,7 @@ TEST(FlKeyEmbedderResponderTest, SynthesizationOccursOnIgnoredEvents) { EXPECT_STREQ(record->event->character, nullptr); EXPECT_EQ(record->event->synthesized, true); - TRACEI(g_ptr_array_clear(g_call_records);, 1); + g_ptr_array_clear(g_call_records); clear_g_call_records(); g_object_unref(engine); From 423fb246f0ecf2a84028cfcf64964ae9bc9308b3 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Wed, 19 May 2021 07:09:42 -0700 Subject: [PATCH 124/126] Add TODO to explain --- shell/platform/linux/fl_key_embedder_responder_test.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index 8a5f4945b0175..394928da0c6c7 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -274,6 +274,11 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { TRACEI(g_ptr_array_clear(g_call_records);, 4); clear_g_call_records(); + // TODO(dkwingsmt): Convert `engine` and `responder` to `g_autofree`. + // The current implementation is because `responder` must be unreferenced + // after `engine`, otherwise crash will *consistantly* occur on CI even if + // everything passes locally. This is a strange bug I've tried to track for + // dozens of hours in vain. g_object_unref(engine); g_object_unref(responder); } From f36473a38a9e3694b62920accb5048e7fe7f65a6 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Wed, 19 May 2021 15:03:57 -0700 Subject: [PATCH 125/126] Better doc --- shell/platform/linux/fl_key_embedder_responder_test.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index f929ff760f3b4..740980d5a63a2 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -278,7 +278,8 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { // The current implementation is because `responder` must be unreferenced // after `engine`, otherwise crash will *consistantly* occur on CI even if // everything passes locally. This is a strange bug I've tried to track for - // dozens of hours in vain. + // dozens of hours in vain. It shouldn't affect real application anyway, + // since it seems to appear only during the "reboot" of the engine. g_object_unref(engine); g_object_unref(responder); } From eb1857614cb56470285bf104114fd851347e11a6 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Tue, 25 May 2021 16:49:26 -0700 Subject: [PATCH 126/126] Update mock_text_input_plugin.cc --- shell/platform/linux/testing/mock_text_input_plugin.cc | 5 ----- 1 file changed, 5 deletions(-) diff --git a/shell/platform/linux/testing/mock_text_input_plugin.cc b/shell/platform/linux/testing/mock_text_input_plugin.cc index 4a0fd0f1930d1..bb6d7f070ae0b 100644 --- a/shell/platform/linux/testing/mock_text_input_plugin.cc +++ b/shell/platform/linux/testing/mock_text_input_plugin.cc @@ -31,11 +31,6 @@ static void fl_mock_text_input_plugin_class_init( static void fl_mock_text_input_plugin_init(FlMockTextInputPlugin* self) {} -// static gboolean text_input_im_filter_by_mock(GtkIMContext* im_context, -// gpointer gdk_event) { -// return true; -// } - // Creates a mock text_input_plugin FlMockTextInputPlugin* fl_mock_text_input_plugin_new( gboolean (*filter_keypress)(FlTextInputPlugin* self, FlKeyEvent* event)) {