diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 90af1ef2d726a..cc23fd9729328 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -44800,6 +44800,8 @@ ORIGIN: ../../../flutter/shell/platform/linux/fl_key_responder.h + ../../../flut ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_handler.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_handler.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_handler_test.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_pending_event.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_pending_event.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_view_delegate.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_keyboard_view_delegate.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/shell/platform/linux/fl_message_codec.cc + ../../../flutter/LICENSE @@ -47697,6 +47699,8 @@ FILE: ../../../flutter/shell/platform/linux/fl_key_responder.h FILE: ../../../flutter/shell/platform/linux/fl_keyboard_handler.cc FILE: ../../../flutter/shell/platform/linux/fl_keyboard_handler.h FILE: ../../../flutter/shell/platform/linux/fl_keyboard_handler_test.cc +FILE: ../../../flutter/shell/platform/linux/fl_keyboard_pending_event.cc +FILE: ../../../flutter/shell/platform/linux/fl_keyboard_pending_event.h FILE: ../../../flutter/shell/platform/linux/fl_keyboard_view_delegate.cc FILE: ../../../flutter/shell/platform/linux/fl_keyboard_view_delegate.h FILE: ../../../flutter/shell/platform/linux/fl_message_codec.cc diff --git a/shell/platform/linux/BUILD.gn b/shell/platform/linux/BUILD.gn index 13511e93e4b32..36045a9fd4708 100644 --- a/shell/platform/linux/BUILD.gn +++ b/shell/platform/linux/BUILD.gn @@ -81,6 +81,7 @@ source_set("flutter_linux_sources") { "fl_dart_project_private.h", "fl_engine_private.h", "fl_keyboard_handler.h", + "fl_keyboard_pending_event.h", "fl_keyboard_view_delegate.h", "fl_key_event.h", "fl_key_responder.h", @@ -116,6 +117,7 @@ source_set("flutter_linux_sources") { "fl_key_event.cc", "fl_key_responder.cc", "fl_keyboard_handler.cc", + "fl_keyboard_pending_event.cc", "fl_keyboard_view_delegate.cc", "fl_message_codec.cc", "fl_method_call.cc", diff --git a/shell/platform/linux/fl_key_channel_responder.cc b/shell/platform/linux/fl_key_channel_responder.cc index c79ac942e78a0..8c6e28b4b4aa2 100644 --- a/shell/platform/linux/fl_key_channel_responder.cc +++ b/shell/platform/linux/fl_key_channel_responder.cc @@ -212,9 +212,11 @@ static void fl_key_channel_responder_handle_event( g_return_if_fail(event != nullptr); g_return_if_fail(callback != nullptr); - 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); + const gchar* type = + fl_key_event_get_is_press(event) ? kTypeValueDown : kTypeValueUp; + int64_t scan_code = fl_key_event_get_keycode(event); + int64_t unicode_scarlar_values = + gdk_keyval_to_unicode(fl_key_event_get_keyval(event)); // For most modifier keys, GTK keeps track of the "pressed" state of the // modifier keys. Flutter uses this information to keep modifier keys from @@ -239,20 +241,21 @@ static void fl_key_channel_responder_handle_event( // interactions (for example, if shift-lock is on, tab traversal is broken). // Remove lock states from state mask. - guint state = event->state & ~(GDK_LOCK_MASK | GDK_MOD2_MASK); + guint state = + fl_key_event_get_state(event) & ~(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) { + switch (fl_key_event_get_keyval(event)) { case GDK_KEY_Num_Lock: - num_lock_pressed = event->is_press; + num_lock_pressed = fl_key_event_get_is_press(event); break; case GDK_KEY_Caps_Lock: - caps_lock_pressed = event->is_press; + caps_lock_pressed = fl_key_event_get_is_press(event); break; case GDK_KEY_Shift_Lock: - shift_lock_pressed = event->is_press; + shift_lock_pressed = fl_key_event_get_is_press(event); break; } @@ -269,7 +272,7 @@ static void fl_key_channel_responder_handle_event( 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_new_int(fl_key_event_get_keyval(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, diff --git a/shell/platform/linux/fl_key_channel_responder_test.cc b/shell/platform/linux/fl_key_channel_responder_test.cc index 4972f59b81fd2..2d38456af29c5 100644 --- a/shell/platform/linux/fl_key_channel_responder_test.cc +++ b/shell/platform/linux/fl_key_channel_responder_test.cc @@ -29,33 +29,6 @@ static void responder_callback(bool handled, gpointer user_data) { g_main_loop_quit(static_cast(user_data)); } -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, - GdkModifierType 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.keycode = keycode; - _g_key_event.origin = nullptr; - return &_g_key_event; -} - // Test sending a letter "A"; TEST(FlKeyChannelResponderTest, SendKeyEvent) { g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0); @@ -69,11 +42,9 @@ 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(12345, true, GDK_KEY_A, 0x04, - static_cast(0), false), - responder_callback, loop); + g_autoptr(FlKeyEvent) event1 = fl_key_event_new( + 12345, TRUE, 0x04, GDK_KEY_A, static_cast(0), 0); + fl_key_responder_handle_event(responder, event1, responder_callback, loop); expected_value = "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, keyCode: 65, " "modifiers: 0, unicodeScalarValues: 65}"; @@ -82,11 +53,9 @@ 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(23456, false, GDK_KEY_A, 0x04, - static_cast(0), false), - responder_callback, loop); + g_autoptr(FlKeyEvent) event2 = fl_key_event_new( + 23456, FALSE, 0x04, GDK_KEY_A, static_cast(0), 0); + fl_key_responder_handle_event(responder, event2, responder_callback, loop); expected_value = "{type: keyup, keymap: linux, scanCode: 4, toolkit: gtk, keyCode: 65, " "modifiers: 0, unicodeScalarValues: 65}"; @@ -110,11 +79,9 @@ 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(12345, true, key_code, 0x04, - static_cast(0), false), - responder_callback, loop); + g_autoptr(FlKeyEvent) event1 = fl_key_event_new( + 12345, TRUE, 0x04, key_code, static_cast(0), 0); + fl_key_responder_handle_event(responder, event1, responder_callback, loop); expected_value = down_expected; expected_handled = FALSE; @@ -123,11 +90,9 @@ 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(12346, false, key_code, 0x04, - static_cast(0), false), - responder_callback, loop); + g_autoptr(FlKeyEvent) event2 = fl_key_event_new( + 12346, FALSE, 0x04, key_code, static_cast(0), 0); + fl_key_responder_handle_event(responder, event2, responder_callback, loop); // Blocks here until echo_response_cb is called. g_main_loop_run(loop); @@ -172,11 +137,9 @@ 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(12345, true, GDK_KEY_A, 0x04, - static_cast(0), false), - responder_callback, loop); + g_autoptr(FlKeyEvent) event = fl_key_event_new( + 12345, TRUE, 0x04, GDK_KEY_A, static_cast(0), 0); + fl_key_responder_handle_event(responder, event, responder_callback, loop); expected_handled = TRUE; expected_value = "{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, " @@ -198,11 +161,10 @@ TEST(FlKeyChannelResponderTest, UseSpecifiedLogicalKey) { 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(12345, true, GDK_KEY_A, 0x04, - static_cast(0), false), - responder_callback, loop, 888); + g_autoptr(FlKeyEvent) event = fl_key_event_new( + 12345, TRUE, 0x04, GDK_KEY_A, static_cast(0), 0); + fl_key_responder_handle_event(responder, event, responder_callback, loop, + 888); 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 100d6189f7b53..922922a956c15 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -297,16 +297,16 @@ static uint64_t apply_id_plane(uint64_t logical_id, uint64_t plane) { return (logical_id & kValueMask) | plane; } -static uint64_t event_to_physical_key(const FlKeyEvent* event) { - auto found = xkb_to_physical_key_map.find(event->keycode); +static uint64_t event_to_physical_key(FlKeyEvent* event) { + auto found = xkb_to_physical_key_map.find(fl_key_event_get_keycode(event)); if (found != xkb_to_physical_key_map.end()) { return found->second; } - return apply_id_plane(event->keycode, kGtkPlane); + return apply_id_plane(fl_key_event_get_keycode(event), kGtkPlane); } -static uint64_t event_to_logical_key(const FlKeyEvent* event) { - guint keyval = event->keyval; +static uint64_t event_to_logical_key(FlKeyEvent* event) { + guint keyval = fl_key_event_get_keyval(event); auto found = gtk_keyval_to_logical_key_map.find(keyval); if (found != gtk_keyval_to_logical_key_map.end()) { return found->second; @@ -319,14 +319,15 @@ static uint64_t event_to_logical_key(const FlKeyEvent* event) { return apply_id_plane(keyval, kGtkPlane); } -static uint64_t event_to_timestamp(const FlKeyEvent* event) { - return kMicrosecondsPerMillisecond * static_cast(event->time); +static uint64_t event_to_timestamp(FlKeyEvent* event) { + return kMicrosecondsPerMillisecond * + static_cast(fl_key_event_get_time(event)); } -// Returns a newly accocated UTF-8 string from event->keyval that must be -// freed later with g_free(). -static char* event_to_character(const FlKeyEvent* event) { - gunichar unicodeChar = gdk_keyval_to_unicode(event->keyval); +// Returns a newly accocated UTF-8 string from fl_key_event_get_keyval(event) +// that must be freed later with g_free(). +static char* event_to_character(FlKeyEvent* event) { + gunichar unicodeChar = gdk_keyval_to_unicode(fl_key_event_get_keyval(event)); glong items_written; gchar* result = g_ucs4_to_utf8(&unicodeChar, 1, NULL, &items_written, NULL); if (items_written == 0) { @@ -790,11 +791,11 @@ static void fl_key_embedder_responder_handle_event_impl( const uint64_t physical_key = corrected_modifier_physical_key( self->modifier_bit_to_checked_keys, physical_key_from_event, logical_key); const double timestamp = event_to_timestamp(event); - const bool is_down_event = event->is_press; + const bool is_down_event = fl_key_event_get_is_press(event); SyncStateLoopContext sync_state_context; sync_state_context.self = self; - sync_state_context.state = event->state; + sync_state_context.state = fl_key_event_get_state(event); sync_state_context.timestamp = timestamp; sync_state_context.is_down = is_down_event; sync_state_context.event_logical_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 aac675ddec5ed..3a1ab31100ca9 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -16,9 +16,6 @@ namespace { constexpr gboolean kRelease = FALSE; constexpr gboolean kPress = TRUE; -constexpr gboolean kIsModifier = TRUE; -constexpr gboolean kIsNotModifier = FALSE; - constexpr guint16 kKeyCodeDigit1 = 0x0au; constexpr guint16 kKeyCodeKeyA = 0x26u; constexpr guint16 kKeyCodeShiftLeft = 0x32u; @@ -100,33 +97,6 @@ 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, - GdkModifierType 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.keycode = keycode; - _g_key_event.origin = nullptr; - return &_g_key_event; -} - static gboolean g_expected_handled; static gpointer g_expected_user_data; @@ -176,11 +146,11 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { // On a QWERTY keyboard, press key Q (physically key A), and release. // Key down - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(12345, kPress, GDK_KEY_a, kKeyCodeKeyA, - static_cast(0), kIsNotModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event1 = + fl_key_event_new(12345, kPress, kKeyCodeKeyA, GDK_KEY_a, + static_cast(0), 0); + fl_key_responder_handle_event(responder, event1, 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)); @@ -196,11 +166,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(12346, kRelease, GDK_KEY_a, kKeyCodeKeyA, - static_cast(0), kIsNotModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event2 = + fl_key_event_new(12346, kRelease, kKeyCodeKeyA, GDK_KEY_a, + static_cast(0), 0); + fl_key_responder_handle_event(responder, event2, 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)); @@ -217,11 +187,11 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) { // On an AZERTY keyboard, press key Q (physically key A), and release. // Key down - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(12347, kPress, GDK_KEY_q, kKeyCodeKeyA, - static_cast(0), kIsNotModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event3 = + fl_key_event_new(12347, kPress, kKeyCodeKeyA, GDK_KEY_q, + static_cast(0), 0); + fl_key_responder_handle_event(responder, event3, 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)); @@ -237,11 +207,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, - static_cast(0), kIsNotModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event4 = + fl_key_event_new(12348, kRelease, kKeyCodeKeyA, GDK_KEY_q, + static_cast(0), 0); + fl_key_responder_handle_event(responder, event4, 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)); @@ -272,11 +242,11 @@ TEST(FlKeyEmbedderResponderTest, UsesSpecifiedLogicalKey) { // On an AZERTY keyboard, press physical key 1, and release. // Key down - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(12345, kPress, GDK_KEY_ampersand, kKeyCodeDigit1, - static_cast(0), kIsNotModifier), - verify_response_handled, &user_data, kLogicalDigit1); + g_autoptr(FlKeyEvent) event = + fl_key_event_new(12345, kPress, kKeyCodeDigit1, GDK_KEY_ampersand, + static_cast(0), 0); + fl_key_responder_handle_event(responder, event, verify_response_handled, + &user_data, kLogicalDigit1); EXPECT_EQ(g_call_records->len, 1u); record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); @@ -306,11 +276,11 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { FlKeyEmbedderCallRecord* record; // Press shift right - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(101, kPress, GDK_KEY_Shift_R, kKeyCodeShiftRight, - static_cast(0), kIsModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event1 = + fl_key_event_new(101, kPress, kKeyCodeShiftRight, GDK_KEY_Shift_R, + static_cast(0), 0); + fl_key_responder_handle_event(responder, event1, 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)); @@ -324,11 +294,10 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { g_ptr_array_clear(g_call_records); // Press key A - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(102, kPress, GDK_KEY_A, kKeyCodeKeyA, - GDK_SHIFT_MASK, kIsNotModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event2 = + fl_key_event_new(102, kPress, kKeyCodeKeyA, GDK_KEY_A, GDK_SHIFT_MASK, 0); + fl_key_responder_handle_event(responder, event2, 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)); @@ -342,11 +311,10 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { g_ptr_array_clear(g_call_records); // Release shift right - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(103, kRelease, GDK_KEY_Shift_R, - kKeyCodeShiftRight, GDK_SHIFT_MASK, kIsModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event3 = fl_key_event_new( + 103, kRelease, kKeyCodeShiftRight, GDK_KEY_Shift_R, GDK_SHIFT_MASK, 0); + fl_key_responder_handle_event(responder, event3, 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)); @@ -360,11 +328,11 @@ TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) { g_ptr_array_clear(g_call_records); // Release key A - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(104, kRelease, GDK_KEY_A, kKeyCodeKeyA, - static_cast(0), kIsNotModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event4 = + fl_key_event_new(104, kRelease, kKeyCodeKeyA, GDK_KEY_A, + static_cast(0), 0); + fl_key_responder_handle_event(responder, event4, 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)); @@ -399,11 +367,11 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { FlKeyEmbedderCallRecord* record; // Press Numpad 1 (stage 0) - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(101, kPress, GDK_KEY_KP_End, kKeyCodeNumpad1, - static_cast(0), kIsNotModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event1 = + fl_key_event_new(101, kPress, kKeyCodeNumpad1, GDK_KEY_KP_End, + static_cast(0), 0); + fl_key_responder_handle_event(responder, event1, 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)); @@ -417,11 +385,11 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { g_ptr_array_clear(g_call_records); // Press NumLock (stage 0 -> 1) - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(102, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock, - static_cast(0), kIsNotModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event2 = + fl_key_event_new(102, kPress, kKeyCodeNumLock, GDK_KEY_Num_Lock, + static_cast(0), 0); + fl_key_responder_handle_event(responder, event2, 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)); @@ -435,11 +403,10 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { g_ptr_array_clear(g_call_records); // Release numpad 1 (stage 1) - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(104, kRelease, GDK_KEY_KP_1, kKeyCodeNumpad1, - GDK_MOD2_MASK, kIsNotModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event3 = fl_key_event_new( + 104, kRelease, kKeyCodeNumpad1, GDK_KEY_KP_1, GDK_MOD2_MASK, 0); + fl_key_responder_handle_event(responder, event3, 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)); @@ -453,11 +420,10 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { g_ptr_array_clear(g_call_records); // Release NumLock (stage 1 -> 2) - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(103, kRelease, GDK_KEY_Num_Lock, kKeyCodeNumLock, - GDK_MOD2_MASK, kIsModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event4 = fl_key_event_new( + 103, kRelease, kKeyCodeNumLock, GDK_KEY_Num_Lock, GDK_MOD2_MASK, 0); + fl_key_responder_handle_event(responder, event4, 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)); @@ -471,11 +437,10 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { g_ptr_array_clear(g_call_records); // Press Numpad 1 (stage 2) - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(101, kPress, GDK_KEY_KP_End, kKeyCodeNumpad1, - GDK_MOD2_MASK, kIsNotModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event5 = fl_key_event_new( + 101, kPress, kKeyCodeNumpad1, GDK_KEY_KP_End, GDK_MOD2_MASK, 0); + fl_key_responder_handle_event(responder, event5, 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)); @@ -489,11 +454,10 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { g_ptr_array_clear(g_call_records); // Press NumLock (stage 2 -> 3) - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(102, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock, - GDK_MOD2_MASK, kIsNotModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event6 = fl_key_event_new( + 102, kPress, kKeyCodeNumLock, GDK_KEY_Num_Lock, GDK_MOD2_MASK, 0); + fl_key_responder_handle_event(responder, event6, 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)); @@ -507,11 +471,10 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { g_ptr_array_clear(g_call_records); // Release numpad 1 (stage 3) - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(104, kRelease, GDK_KEY_KP_1, kKeyCodeNumpad1, - GDK_MOD2_MASK, kIsNotModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event7 = fl_key_event_new( + 104, kRelease, kKeyCodeNumpad1, GDK_KEY_KP_1, GDK_MOD2_MASK, 0); + fl_key_responder_handle_event(responder, event7, 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)); @@ -525,11 +488,10 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { g_ptr_array_clear(g_call_records); // Release NumLock (stage 3 -> 0) - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(103, kRelease, GDK_KEY_Num_Lock, kKeyCodeNumLock, - GDK_MOD2_MASK, kIsModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event8 = fl_key_event_new( + 103, kRelease, kKeyCodeNumLock, GDK_KEY_Num_Lock, GDK_MOD2_MASK, 0); + fl_key_responder_handle_event(responder, event8, 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)); @@ -562,11 +524,10 @@ TEST(FlKeyEmbedderResponderTest, ReleaseShiftKeyBetweenDigitKeyEvents) { GdkModifierType state = static_cast(0); // Press shift left - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(101, kPress, GDK_KEY_Shift_L, kKeyCodeShiftLeft, - state, kIsModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event1 = fl_key_event_new( + 101, kPress, kKeyCodeShiftLeft, GDK_KEY_Shift_L, state, 0); + fl_key_responder_handle_event(responder, event1, 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)); @@ -582,11 +543,10 @@ TEST(FlKeyEmbedderResponderTest, ReleaseShiftKeyBetweenDigitKeyEvents) { state = GDK_SHIFT_MASK; // Press digit 1, which is '!' on a US keyboard - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(102, kPress, GDK_KEY_exclam, kKeyCodeDigit1, - state, kIsNotModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event2 = + fl_key_event_new(102, kPress, kKeyCodeDigit1, GDK_KEY_exclam, state, 0); + fl_key_responder_handle_event(responder, event2, 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)); @@ -600,11 +560,10 @@ TEST(FlKeyEmbedderResponderTest, ReleaseShiftKeyBetweenDigitKeyEvents) { g_ptr_array_clear(g_call_records); // Release shift - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(103, kRelease, GDK_KEY_Shift_L, - kKeyCodeShiftLeft, state, kIsModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event3 = fl_key_event_new( + 103, kRelease, kKeyCodeShiftLeft, GDK_KEY_Shift_L, state, 0); + fl_key_responder_handle_event(responder, event3, 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)); @@ -620,11 +579,10 @@ TEST(FlKeyEmbedderResponderTest, ReleaseShiftKeyBetweenDigitKeyEvents) { state = static_cast(0); // Release digit 1, which is "1" because shift has been released. - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(104, kRelease, GDK_KEY_1, kKeyCodeDigit1, state, - kIsNotModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event4 = + fl_key_event_new(104, kRelease, kKeyCodeDigit1, GDK_KEY_1, state, 0); + fl_key_responder_handle_event(responder, event4, 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)); @@ -655,11 +613,11 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { FlKeyEmbedderCallRecord* record; // Press CapsLock (stage 0 -> 1) - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(101, kPress, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, - static_cast(0), kIsModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event1 = + fl_key_event_new(101, kPress, kKeyCodeCapsLock, GDK_KEY_Caps_Lock, + static_cast(0), 0); + fl_key_responder_handle_event(responder, event1, 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)); @@ -673,11 +631,10 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { g_ptr_array_clear(g_call_records); // Press key A (stage 1) - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(102, kPress, GDK_KEY_A, kKeyCodeKeyA, - GDK_LOCK_MASK, kIsNotModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event2 = + fl_key_event_new(102, kPress, kKeyCodeKeyA, GDK_KEY_A, GDK_LOCK_MASK, 0); + fl_key_responder_handle_event(responder, event2, 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)); @@ -691,11 +648,10 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { g_ptr_array_clear(g_call_records); // Release CapsLock (stage 1 -> 2) - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(103, kRelease, GDK_KEY_Caps_Lock, - kKeyCodeCapsLock, GDK_LOCK_MASK, kIsModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event3 = fl_key_event_new( + 103, kRelease, kKeyCodeCapsLock, GDK_KEY_Caps_Lock, GDK_LOCK_MASK, 0); + fl_key_responder_handle_event(responder, event3, 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)); @@ -709,11 +665,10 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { g_ptr_array_clear(g_call_records); // Release key A (stage 2) - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(104, kRelease, GDK_KEY_A, kKeyCodeKeyA, - GDK_LOCK_MASK, kIsNotModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event4 = fl_key_event_new(104, kRelease, kKeyCodeKeyA, + GDK_KEY_A, GDK_LOCK_MASK, 0); + fl_key_responder_handle_event(responder, event4, 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)); @@ -727,11 +682,10 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { g_ptr_array_clear(g_call_records); // Press CapsLock (stage 2 -> 3) - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(105, kPress, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, - GDK_LOCK_MASK, kIsModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event5 = fl_key_event_new( + 105, kPress, kKeyCodeCapsLock, GDK_KEY_Caps_Lock, GDK_LOCK_MASK, 0); + fl_key_responder_handle_event(responder, event5, 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)); @@ -745,11 +699,10 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { g_ptr_array_clear(g_call_records); // Press key A (stage 3) - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(106, kPress, GDK_KEY_A, kKeyCodeKeyA, - GDK_LOCK_MASK, kIsNotModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event6 = + fl_key_event_new(106, kPress, kKeyCodeKeyA, GDK_KEY_A, GDK_LOCK_MASK, 0); + fl_key_responder_handle_event(responder, event6, 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)); @@ -763,11 +716,10 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { g_ptr_array_clear(g_call_records); // Release CapsLock (stage 3 -> 0) - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(107, kRelease, GDK_KEY_Caps_Lock, - kKeyCodeCapsLock, GDK_LOCK_MASK, kIsModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event7 = fl_key_event_new( + 107, kRelease, kKeyCodeCapsLock, GDK_KEY_Caps_Lock, GDK_LOCK_MASK, 0); + fl_key_responder_handle_event(responder, event7, 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)); @@ -781,11 +733,11 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) { g_ptr_array_clear(g_call_records); // Release key A (stage 0) - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(108, kRelease, GDK_KEY_a, kKeyCodeKeyA, - static_cast(0), kIsNotModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event8 = + fl_key_event_new(108, kRelease, kKeyCodeKeyA, GDK_KEY_a, + static_cast(0), 0); + fl_key_responder_handle_event(responder, event8, 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)); @@ -816,11 +768,10 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { FlKeyEmbedderCallRecord* record; // Press key A (stage 0) - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(101, kPress, GDK_KEY_a, kKeyCodeKeyA, - static_cast(0), kIsNotModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event1 = fl_key_event_new( + 101, kPress, kKeyCodeKeyA, GDK_KEY_a, static_cast(0), 0); + fl_key_responder_handle_event(responder, event1, 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)); @@ -834,11 +785,10 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { g_ptr_array_clear(g_call_records); // Press CapsLock (stage 0 -> 1) - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(102, kPress, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, - GDK_LOCK_MASK, kIsModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event2 = fl_key_event_new( + 102, kPress, kKeyCodeCapsLock, GDK_KEY_Caps_Lock, GDK_LOCK_MASK, 0); + fl_key_responder_handle_event(responder, event2, 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)); @@ -852,11 +802,10 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { g_ptr_array_clear(g_call_records); // Release CapsLock (stage 1 -> 2) - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(103, kRelease, GDK_KEY_Caps_Lock, - kKeyCodeCapsLock, GDK_LOCK_MASK, kIsModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event3 = fl_key_event_new( + 103, kRelease, kKeyCodeCapsLock, GDK_KEY_Caps_Lock, GDK_LOCK_MASK, 0); + fl_key_responder_handle_event(responder, event3, 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)); @@ -870,11 +819,10 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { g_ptr_array_clear(g_call_records); // Release key A (stage 2) - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(104, kRelease, GDK_KEY_A, kKeyCodeKeyA, - GDK_LOCK_MASK, kIsNotModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event4 = fl_key_event_new(104, kRelease, kKeyCodeKeyA, + GDK_KEY_A, GDK_LOCK_MASK, 0); + fl_key_responder_handle_event(responder, event4, 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)); @@ -888,11 +836,10 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { g_ptr_array_clear(g_call_records); // Press key A (stage 2) - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(105, kPress, GDK_KEY_A, kKeyCodeKeyA, - GDK_LOCK_MASK, kIsNotModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event5 = + fl_key_event_new(105, kPress, kKeyCodeKeyA, GDK_KEY_A, GDK_LOCK_MASK, 0); + fl_key_responder_handle_event(responder, event5, 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)); @@ -906,11 +853,11 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { g_ptr_array_clear(g_call_records); // Press CapsLock (stage 2 -> 3) - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(106, kPress, GDK_KEY_Caps_Lock, kKeyCodeCapsLock, - static_cast(0), kIsModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event6 = + fl_key_event_new(106, kPress, kKeyCodeCapsLock, GDK_KEY_Caps_Lock, + static_cast(0), 0); + fl_key_responder_handle_event(responder, event6, 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)); @@ -924,11 +871,10 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { g_ptr_array_clear(g_call_records); // Release CapsLock (stage 3 -> 0) - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(107, kRelease, GDK_KEY_Caps_Lock, - kKeyCodeCapsLock, GDK_LOCK_MASK, kIsModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event7 = fl_key_event_new( + 107, kRelease, kKeyCodeCapsLock, GDK_KEY_Caps_Lock, GDK_LOCK_MASK, 0); + fl_key_responder_handle_event(responder, event7, 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)); @@ -942,11 +888,11 @@ TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) { g_ptr_array_clear(g_call_records); // Release key A (stage 0) - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(108, kRelease, GDK_KEY_a, kKeyCodeKeyA, - static_cast(0), kIsNotModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event8 = + fl_key_event_new(108, kRelease, kKeyCodeKeyA, GDK_KEY_a, + static_cast(0), 0); + fl_key_responder_handle_event(responder, event8, 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)); @@ -973,11 +919,10 @@ TEST(FlKeyEmbedderResponderTest, TurnDuplicateDownEventsToRepeats) { FlKeyEmbedderCallRecord* record; // Press KeyA - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(101, kPress, GDK_KEY_a, kKeyCodeKeyA, - static_cast(0), kIsNotModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event1 = fl_key_event_new( + 101, kPress, kKeyCodeKeyA, GDK_KEY_a, static_cast(0), 0); + fl_key_responder_handle_event(responder, event1, verify_response_handled, + &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -987,11 +932,10 @@ TEST(FlKeyEmbedderResponderTest, TurnDuplicateDownEventsToRepeats) { // Another KeyA down events, which usually means a repeated event. g_expected_handled = false; - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(102, kPress, GDK_KEY_a, kKeyCodeKeyA, - static_cast(0), kIsNotModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event2 = fl_key_event_new( + 102, kPress, kKeyCodeKeyA, GDK_KEY_a, static_cast(0), 0); + fl_key_responder_handle_event(responder, event2, verify_response_handled, + &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -1007,11 +951,11 @@ TEST(FlKeyEmbedderResponderTest, TurnDuplicateDownEventsToRepeats) { g_ptr_array_clear(g_call_records); // Release KeyA - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(103, kRelease, GDK_KEY_q, kKeyCodeKeyA, - static_cast(0), kIsNotModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event3 = + fl_key_event_new(103, kRelease, kKeyCodeKeyA, GDK_KEY_q, + static_cast(0), 0); + fl_key_responder_handle_event(responder, event3, 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)); @@ -1033,11 +977,11 @@ TEST(FlKeyEmbedderResponderTest, IgnoreAbruptUpEvent) { // Release KeyA before it was even pressed. g_expected_handled = true; // The empty event is always handled. - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(103, kRelease, GDK_KEY_q, kKeyCodeKeyA, - static_cast(0), kIsNotModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event = + fl_key_event_new(103, kRelease, kKeyCodeKeyA, GDK_KEY_q, + static_cast(0), 0); + fl_key_responder_handle_event(responder, event, verify_response_handled, + &user_data); EXPECT_EQ(g_call_records->len, 1u); @@ -1069,11 +1013,10 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) { GdkModifierType state = GDK_CONTROL_MASK; // 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), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event1 = fl_key_event_new( + 101, kRelease, kKeyCodeControlLeft, GDK_KEY_Control_L, state, 0); + fl_key_responder_handle_event(responder, event1, 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)); @@ -1099,11 +1042,10 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) { // Send a ControlLeft down. state = static_cast(0); - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(102, kPress, GDK_KEY_Control_L, - kKeyCodeControlLeft, state, kIsModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event2 = fl_key_event_new( + 102, kPress, kKeyCodeControlLeft, GDK_KEY_Control_L, state, 0); + fl_key_responder_handle_event(responder, event2, 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); @@ -1113,11 +1055,10 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) { state = static_cast(0); // 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), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event3 = fl_key_event_new( + 103, kPress, kKeyCodeControlLeft, GDK_KEY_Control_L, state, 0); + fl_key_responder_handle_event(responder, event3, 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)); @@ -1141,11 +1082,10 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) { // Send a ControlLeft up to clear up state. 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), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event4 = fl_key_event_new( + 104, kRelease, kKeyCodeControlLeft, GDK_KEY_Control_L, state, 0); + fl_key_responder_handle_event(responder, event4, 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); @@ -1157,11 +1097,10 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) { state = GDK_CONTROL_MASK; // 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), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event5 = fl_key_event_new( + 105, kRelease, kKeyCodeControlRight, GDK_KEY_Control_R, state, 0); + fl_key_responder_handle_event(responder, event5, verify_response_handled, + &user_data); // A ControlLeft down is synthesized, with an empty event. // Reason: The ControlLeft down is synthesized to synchronize the state @@ -1198,11 +1137,10 @@ TEST(FlKeyEmbedderResponderTest, GdkModifierType state = GDK_CONTROL_MASK; // Send a normal event (KeyA down) - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(101, kPress, GDK_KEY_a, kKeyCodeKeyA, state, - kIsNotModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event1 = + fl_key_event_new(101, kPress, kKeyCodeKeyA, GDK_KEY_a, state, 0); + fl_key_responder_handle_event(responder, event1, 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)); @@ -1228,11 +1166,10 @@ TEST(FlKeyEmbedderResponderTest, state = static_cast(0); // Send a normal event (KeyA up) - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(102, kRelease, GDK_KEY_A, kKeyCodeKeyA, state, - kIsNotModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event2 = + fl_key_event_new(102, kRelease, kKeyCodeKeyA, GDK_KEY_A, state, 0); + fl_key_responder_handle_event(responder, event2, 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)); @@ -1259,11 +1196,10 @@ TEST(FlKeyEmbedderResponderTest, // Press a key with physical CapsLock and logical ControlLeft. state = static_cast(0); - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(101, kPress, GDK_KEY_Control_L, kKeyCodeCapsLock, - state, kIsModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event3 = fl_key_event_new(101, kPress, kKeyCodeCapsLock, + GDK_KEY_Control_L, state, 0); + fl_key_responder_handle_event(responder, event3, 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)); @@ -1281,11 +1217,10 @@ TEST(FlKeyEmbedderResponderTest, state = static_cast(0); // Send a normal event (KeyA down). - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(102, kPress, GDK_KEY_A, kKeyCodeKeyA, state, - kIsNotModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event4 = + fl_key_event_new(102, kPress, kKeyCodeKeyA, GDK_KEY_A, state, 0); + fl_key_responder_handle_event(responder, event4, verify_response_handled, + &user_data); // The synthesized event should have physical CapsLock and logical // ControlLeft. @@ -1328,11 +1263,10 @@ TEST(FlKeyEmbedderResponderTest, // Press a key with physical CapsLock and logical ControlLeft. GdkModifierType state = static_cast(0); - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(101, kPress, GDK_KEY_Control_L, kKeyCodeCapsLock, - state, kIsModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event1 = fl_key_event_new(101, kPress, kKeyCodeCapsLock, + GDK_KEY_Control_L, state, 0); + fl_key_responder_handle_event(responder, event1, 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)); @@ -1350,11 +1284,10 @@ TEST(FlKeyEmbedderResponderTest, state = static_cast(0); // Send a normal event (KeyA down). - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(102, kPress, GDK_KEY_A, kKeyCodeKeyA, state, - kIsNotModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event2 = + fl_key_event_new(102, kPress, kKeyCodeKeyA, GDK_KEY_A, state, 0); + fl_key_responder_handle_event(responder, event2, verify_response_handled, + &user_data); // The synthesized event should have physical CapsLock and logical // ControlLeft. @@ -1397,11 +1330,10 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { GdkModifierType state = GDK_MOD2_MASK; // Send a normal event - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(101, kPress, GDK_KEY_a, kKeyCodeKeyA, state, - kIsNotModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event1 = + fl_key_event_new(101, kPress, kKeyCodeKeyA, GDK_KEY_a, state, 0); + fl_key_responder_handle_event(responder, event1, 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)); @@ -1427,11 +1359,10 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { state = static_cast(0); // Release key A - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(102, kRelease, GDK_KEY_A, kKeyCodeKeyA, state, - kIsNotModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event2 = + fl_key_event_new(102, kRelease, kKeyCodeKeyA, GDK_KEY_A, state, 0); + fl_key_responder_handle_event(responder, event2, 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)); @@ -1472,11 +1403,10 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) { // Release NumLock. Since the previous event should have synthesized NumLock // to be released, this should result in only an empty event. 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), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event3 = fl_key_event_new( + 103, kRelease, kKeyCodeNumLock, GDK_KEY_Num_Lock, state, 0); + fl_key_responder_handle_event(responder, event3, 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)); @@ -1505,11 +1435,10 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) { GdkModifierType state = GDK_MOD2_MASK; // NumLock down - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(101, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock, - state, kIsModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event1 = fl_key_event_new(101, kPress, kKeyCodeNumLock, + GDK_KEY_Num_Lock, state, 0); + fl_key_responder_handle_event(responder, event1, 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)); @@ -1543,11 +1472,10 @@ TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) { state = GDK_MOD2_MASK; // NumLock up - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(102, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock, - state, kIsModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event2 = fl_key_event_new(102, kPress, kKeyCodeNumLock, + GDK_KEY_Num_Lock, state, 0); + fl_key_responder_handle_event(responder, event2, 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)); @@ -1606,11 +1534,10 @@ TEST(FlKeyEmbedderResponderTest, SynthesizationOccursOnIgnoredEvents) { // 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, - kIsNotModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event = + fl_key_event_new(101, kRelease, kKeyCodeKeyA, GDK_KEY_a, state, 0); + fl_key_responder_handle_event(responder, event, 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)); @@ -1659,11 +1586,10 @@ TEST(FlKeyEmbedderResponderTest, HandlesShiftAltVersusGroupNext) { GdkModifierType state) { now_time += 1; int user_data = 123; // Arbitrary user data - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(now_time, is_press, keyval, keycode, state, - kIsModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event = + fl_key_event_new(now_time, is_press, keycode, keyval, state, 0); + fl_key_responder_handle_event(responder, event, verify_response_handled, + &user_data); }; FlKeyEmbedderCallRecord* record; @@ -1768,11 +1694,10 @@ TEST(FlKeyEmbedderResponderTest, HandlesShiftAltLeftIsMetaLeft) { GdkModifierType state) { now_time += 1; int user_data = 123; // Arbitrary user data - fl_key_responder_handle_event( - responder, - fl_key_event_new_by_mock(now_time, is_press, keyval, keycode, state, - kIsModifier), - verify_response_handled, &user_data); + g_autoptr(FlKeyEvent) event = + fl_key_event_new(now_time, is_press, keycode, keyval, state, 0); + fl_key_responder_handle_event(responder, event, verify_response_handled, + &user_data); }; FlKeyEmbedderCallRecord* record; diff --git a/shell/platform/linux/fl_key_event.cc b/shell/platform/linux/fl_key_event.cc index 230bd9c53291c..b79e1b99a3c3f 100644 --- a/shell/platform/linux/fl_key_event.cc +++ b/shell/platform/linux/fl_key_event.cc @@ -4,12 +4,59 @@ #include "flutter/shell/platform/linux/fl_key_event.h" +struct _FlKeyEvent { + GObject parent_instance; + + // Time in milliseconds. + guint32 time; + + // True if is a press event, otherwise a release event. + gboolean is_press; + + // Hardware keycode. + guint16 keycode; + + // Keyval. + guint keyval; + + // Modifier state. + GdkModifierType state; + + // Keyboard group. + guint8 group; + + // The original event. + GdkEvent* origin; +}; + +G_DEFINE_TYPE(FlKeyEvent, fl_key_event, G_TYPE_OBJECT) + +FlKeyEvent* fl_key_event_new(guint32 time, + gboolean is_press, + guint16 keycode, + guint keyval, + GdkModifierType state, + guint8 group) { + FlKeyEvent* self = + FL_KEY_EVENT(g_object_new(fl_key_event_get_type(), nullptr)); + + self->time = time; + self->is_press = is_press; + self->keycode = keycode; + self->keyval = keyval; + self->state = state; + self->group = group; + + return self; +} + FlKeyEvent* fl_key_event_new_from_gdk_event(GdkEvent* event) { - g_return_val_if_fail(event != nullptr, nullptr); + FlKeyEvent* self = + FL_KEY_EVENT(g_object_new(fl_key_event_get_type(), nullptr)); + GdkEventType type = gdk_event_get_event_type(event); g_return_val_if_fail(type == GDK_KEY_PRESS || type == GDK_KEY_RELEASE, nullptr); - FlKeyEvent* result = g_new(FlKeyEvent, 1); guint16 keycode = 0; gdk_event_get_keycode(event, &keycode); @@ -18,26 +65,76 @@ FlKeyEvent* fl_key_event_new_from_gdk_event(GdkEvent* event) { GdkModifierType state = static_cast(0); gdk_event_get_state(event, &state); - result->time = gdk_event_get_time(event); - result->is_press = type == GDK_KEY_PRESS; - result->keycode = keycode; - result->keyval = keyval; - result->state = state; - result->group = event->key.group; - result->origin = event; + self->time = gdk_event_get_time(event); + self->is_press = type == GDK_KEY_PRESS; + self->keycode = keycode; + self->keyval = keyval; + self->state = state; + self->group = event->key.group; + self->origin = event; + + return self; +} + +guint32 fl_key_event_get_time(FlKeyEvent* self) { + g_return_val_if_fail(FL_IS_KEY_EVENT(self), 0); + return self->time; +} + +gboolean fl_key_event_get_is_press(FlKeyEvent* self) { + g_return_val_if_fail(FL_IS_KEY_EVENT(self), FALSE); + return self->is_press; +} + +guint16 fl_key_event_get_keycode(FlKeyEvent* self) { + g_return_val_if_fail(FL_IS_KEY_EVENT(self), 0); + return self->keycode; +} - return result; +guint fl_key_event_get_keyval(FlKeyEvent* self) { + g_return_val_if_fail(FL_IS_KEY_EVENT(self), 0); + return self->keyval; } -void fl_key_event_dispose(FlKeyEvent* event) { - if (event->origin != nullptr) { - gdk_event_free(event->origin); - } - g_free(event); +GdkModifierType fl_key_event_get_state(FlKeyEvent* self) { + g_return_val_if_fail(FL_IS_KEY_EVENT(self), static_cast(0)); + return self->state; } -FlKeyEvent* fl_key_event_clone(const FlKeyEvent* event) { - FlKeyEvent* new_event = g_new(FlKeyEvent, 1); - *new_event = *event; - return new_event; +guint8 fl_key_event_get_group(FlKeyEvent* self) { + g_return_val_if_fail(FL_IS_KEY_EVENT(self), 0); + return self->group; } + +GdkEvent* fl_key_event_get_origin(FlKeyEvent* self) { + g_return_val_if_fail(FL_IS_KEY_EVENT(self), nullptr); + return self->origin; +} + +uint64_t fl_key_event_hash(FlKeyEvent* self) { + g_return_val_if_fail(FL_IS_KEY_EVENT(self), 0); + + // 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. + guint64 type = + static_cast(self->is_press ? GDK_KEY_PRESS : GDK_KEY_RELEASE); + guint64 keycode = static_cast(self->keycode); + return (self->time & 0xffffffff) | ((type & 0xffff) << 32) | + ((keycode & 0xffff) << 48); +} + +static void fl_key_event_dispose(GObject* object) { + FlKeyEvent* self = FL_KEY_EVENT(object); + + g_clear_pointer(&self->origin, gdk_event_free); + + G_OBJECT_CLASS(fl_key_event_parent_class)->dispose(object); +} + +static void fl_key_event_class_init(FlKeyEventClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_key_event_dispose; +} + +static void fl_key_event_init(FlKeyEvent* self) {} diff --git a/shell/platform/linux/fl_key_event.h b/shell/platform/linux/fl_key_event.h index 2a3a4334ed7eb..80b5675bfc2ea 100644 --- a/shell/platform/linux/fl_key_event.h +++ b/shell/platform/linux/fl_key_event.h @@ -5,8 +5,12 @@ #ifndef FLUTTER_SHELL_PLATFORM_LINUX_FL_KEY_EVENT_H_ #define FLUTTER_SHELL_PLATFORM_LINUX_FL_KEY_EVENT_H_ +#include + #include +G_DECLARE_FINAL_TYPE(FlKeyEvent, fl_key_event, FL, KEY_EVENT, GObject); + /** * FlKeyEvent: * A struct that stores information from GdkEvent. @@ -19,42 +23,47 @@ * 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. - 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; - // Keyboard group. - guint8 group; - // The original event. - GdkEvent* origin; -} FlKeyEvent; + +FlKeyEvent* fl_key_event_new(guint32 time, + gboolean is_press, + guint16 keycode, + guint keyval, + GdkModifierType state, + guint8 group); /** * fl_key_event_new_from_gdk_event: - * @event: the #GdkEvent this #FlKeyEvent is based on. The #event must be a - * #GdkEventKey, and will be destroyed by #fl_key_event_dispose. + * @event: the #GdkEvent this #FlKeyEvent is based on. * * Create a new #FlKeyEvent based on a #GdkEvent. * - * Returns: a new #FlKeyEvent. Must be freed with #fl_key_event_dispose. + * Returns: a new #FlKeyEvent. */ FlKeyEvent* fl_key_event_new_from_gdk_event(GdkEvent* event); +guint32 fl_key_event_get_time(FlKeyEvent* event); + +gboolean fl_key_event_get_is_press(FlKeyEvent* event); + +guint16 fl_key_event_get_keycode(FlKeyEvent* event); + +guint fl_key_event_get_keyval(FlKeyEvent* event); + +GdkModifierType fl_key_event_get_state(FlKeyEvent* event); + +guint8 fl_key_event_get_group(FlKeyEvent* event); + +GdkEvent* fl_key_event_get_origin(FlKeyEvent* event); + /** - * fl_key_event_dispose: - * @event: the event to dispose. + * fl_key_event_hash: + * @event: an #FlKeyEvent. + * + * Calculates a unique ID for a given FlKeyEvent object to use for + * identification of responses from the framework. * - * Properly disposes the content of #event and then the pointer. + * Returns: a hash code. */ -void fl_key_event_dispose(FlKeyEvent* event); - -FlKeyEvent* fl_key_event_clone(const FlKeyEvent* source); +uint64_t fl_key_event_hash(FlKeyEvent* event); #endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_KEY_EVENT_H_ diff --git a/shell/platform/linux/fl_keyboard_handler.cc b/shell/platform/linux/fl_keyboard_handler.cc index 759721371aee3..46d4547292537 100644 --- a/shell/platform/linux/fl_keyboard_handler.cc +++ b/shell/platform/linux/fl_keyboard_handler.cc @@ -11,6 +11,7 @@ #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_pending_event.h" #include "flutter/shell/platform/linux/key_mapping.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_method_channel.h" #include "flutter/shell/platform/linux/public/flutter_linux/fl_standard_method_codec.h" @@ -24,12 +25,6 @@ static constexpr char kGetKeyboardStateMethod[] = "getKeyboardState"; /* Declarations of private classes */ -G_DECLARE_FINAL_TYPE(FlKeyboardPendingEvent, - fl_keyboard_pending_event, - FL, - KEYBOARD_PENDING_EVENT, - GObject); - #define FL_TYPE_KEYBOARD_HANDLER_USER_DATA \ fl_keyboard_handler_user_data_get_type() G_DECLARE_FINAL_TYPE(FlKeyboardHandlerUserData, @@ -94,10 +89,10 @@ void debug_format_layout_data(std::string& debug_layout_data, } // namespace -static uint64_t get_logical_key_from_layout(const FlKeyEvent* event, +static uint64_t get_logical_key_from_layout(FlKeyEvent* event, const DerivedLayout& layout) { - guint8 group = event->group; - guint16 keycode = event->keycode; + guint8 group = fl_key_event_get_group(event); + guint16 keycode = fl_key_event_get_keycode(event); if (keycode >= kLayoutSize) { return 0; } @@ -109,93 +104,6 @@ static uint64_t get_logical_key_from_layout(const FlKeyEvent* event, return 0; } -/* Define FlKeyboardPendingEvent */ - -/** - * FlKeyboardPendingEvent: - * A record for events that have been received by the handler, 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. - */ - -struct _FlKeyboardPendingEvent { - GObject parent_instance; - - // The target event. - // - // This is freed by #FlKeyboardPendingEvent if not null. - std::unique_ptr 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; - // 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; -}; - -G_DEFINE_TYPE(FlKeyboardPendingEvent, fl_keyboard_pending_event, G_TYPE_OBJECT) - -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); - if (self->event != nullptr) { - fl_key_event_dispose(self->event.release()); - } - G_OBJECT_CLASS(fl_keyboard_pending_event_parent_class)->dispose(object); -} - -static void fl_keyboard_pending_event_class_init( - FlKeyboardPendingEventClass* klass) { - G_OBJECT_CLASS(klass)->dispose = fl_keyboard_pending_event_dispose; -} - -static void fl_keyboard_pending_event_init(FlKeyboardPendingEvent* self) {} - -// Calculates a unique ID for a given FlKeyEvent object to use for -// identification of responses from the framework. -static uint64_t fl_keyboard_handler_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. - 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) | - ((keycode & 0xffff) << 48); -} - -// Create a new FlKeyboardPendingEvent by providing the target event, -// the sequence ID, and the number of responders that will reply. -// -// This will acquire the ownership of the event. -static FlKeyboardPendingEvent* fl_keyboard_pending_event_new( - std::unique_ptr 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)); - - self->event = std::move(event); - self->sequence_id = sequence_id; - self->unreplied = to_reply; - self->any_handled = false; - self->hash = fl_keyboard_handler_get_event_hash(self->event.get()); - return self; -} - /* Define FlKeyboardHandlerUserData */ /** @@ -299,60 +207,6 @@ struct _FlKeyboardHandler { G_DEFINE_TYPE(FlKeyboardHandler, fl_keyboard_handler, G_TYPE_OBJECT); -static void fl_keyboard_handler_dispose(GObject* object); - -static void fl_keyboard_handler_class_init(FlKeyboardHandlerClass* klass) { - G_OBJECT_CLASS(klass)->dispose = fl_keyboard_handler_dispose; -} - -static void fl_keyboard_handler_init(FlKeyboardHandler* self) { - self->derived_layout = std::make_unique(); - - self->keycode_to_goals = - std::make_unique>(); - self->logical_to_mandatory_goals = - std::make_unique>(); - for (const LayoutGoal& goal : layout_goals) { - (*self->keycode_to_goals)[goal.keycode] = &goal; - if (goal.mandatory) { - (*self->logical_to_mandatory_goals)[goal.logical_key] = &goal; - } - } - - 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_with_free_func(g_object_unref); - - self->last_sequence_id = 1; -} - -static void fl_keyboard_handler_dispose(GObject* object) { - FlKeyboardHandler* self = FL_KEYBOARD_HANDLER(object); - - if (self->view_delegate != nullptr) { - fl_keyboard_view_delegate_subscribe_to_layout_change(self->view_delegate, - nullptr); - g_object_remove_weak_pointer( - G_OBJECT(self->view_delegate), - reinterpret_cast(&(self->view_delegate))); - self->view_delegate = nullptr; - } - - self->derived_layout.reset(); - self->keycode_to_goals.reset(); - self->logical_to_mandatory_goals.reset(); - - 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); - g_ptr_array_free(self->pending_redispatches, TRUE); - - G_OBJECT_CLASS(fl_keyboard_handler_parent_class)->dispose(object); -} - -/* Implement FlKeyboardHandler */ - // 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. @@ -377,22 +231,21 @@ static gboolean g_ptr_array_find_with_equal_func1(GPtrArray* haystack, 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( - 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 sequence_id. +static gboolean compare_pending_by_sequence_id(gconstpointer a, + gconstpointer b) { + FlKeyboardPendingEvent* pending = + FL_KEYBOARD_PENDING_EVENT(const_cast(a)); + uint64_t sequence_id = *reinterpret_cast(b); + return fl_keyboard_pending_event_get_sequence_id(pending) == 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) { - uint64_t hash = *reinterpret_cast(needle_hash); - return static_cast(pending)->hash == hash; +// Compare a #FlKeyboardPendingEvent with the given hash. +static gboolean compare_pending_by_hash(gconstpointer a, gconstpointer b) { + FlKeyboardPendingEvent* pending = + FL_KEYBOARD_PENDING_EVENT(const_cast(a)); + uint64_t hash = *reinterpret_cast(b); + return fl_keyboard_pending_event_get_hash(pending) == hash; } // Try to remove a pending event from `pending_redispatches` with the target @@ -431,22 +284,22 @@ static void responder_handle_event_callback(bool handled, FlKeyboardPendingEvent* pending = FL_KEYBOARD_PENDING_EVENT( 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; + fl_keyboard_pending_event_mark_replied(pending, handled); // All responders have replied. - if (pending->unreplied == 0) { + if (fl_keyboard_pending_event_is_complete(pending)) { g_object_unref(user_data_ptr); gpointer removed = g_ptr_array_remove_index_fast(self->pending_responds, result_index); g_return_if_fail(removed == pending); - bool should_redispatch = !pending->any_handled && - !fl_keyboard_view_delegate_text_filter_key_press( - self->view_delegate, pending->event.get()); + bool should_redispatch = + !fl_keyboard_pending_event_get_any_handled(pending) && + !fl_keyboard_view_delegate_text_filter_key_press( + self->view_delegate, fl_keyboard_pending_event_get_event(pending)); if (should_redispatch) { g_ptr_array_add(self->pending_redispatches, pending); - fl_keyboard_view_delegate_redispatch_event(self->view_delegate, - std::move(pending->event)); + fl_keyboard_view_delegate_redispatch_event( + self->view_delegate, + FL_KEY_EVENT(fl_keyboard_pending_event_get_event(pending))); } else { g_object_unref(pending); } @@ -466,11 +319,11 @@ static uint16_t convert_key_to_char(FlKeyboardViewDelegate* view_delegate, // Make sure that Flutter has derived the layout for the group of the event, // if the event contains a goal keycode. static void guarantee_layout(FlKeyboardHandler* self, FlKeyEvent* event) { - guint8 group = event->group; + guint8 group = fl_key_event_get_group(event); if (self->derived_layout->find(group) != self->derived_layout->end()) { return; } - if (self->keycode_to_goals->find(event->keycode) == + if (self->keycode_to_goals->find(fl_key_event_get_keycode(event)) == self->keycode_to_goals->end()) { return; } @@ -541,7 +394,7 @@ static void guarantee_layout(FlKeyboardHandler* self, FlKeyEvent* event) { } // Returns the keyboard pressed state. -FlMethodResponse* get_keyboard_state(FlKeyboardHandler* self) { +static FlMethodResponse* get_keyboard_state(FlKeyboardHandler* self) { g_autoptr(FlValue) result = fl_value_new_map(); GHashTable* pressing_records = @@ -582,6 +435,67 @@ static void method_call_handler(FlMethodChannel* channel, } } +// 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, context->event, responder_handle_event_callback, + context->user_data, context->specified_logical_key); +} + +static void fl_keyboard_handler_dispose(GObject* object) { + FlKeyboardHandler* self = FL_KEYBOARD_HANDLER(object); + + if (self->view_delegate != nullptr) { + fl_keyboard_view_delegate_subscribe_to_layout_change(self->view_delegate, + nullptr); + g_object_remove_weak_pointer( + G_OBJECT(self->view_delegate), + reinterpret_cast(&(self->view_delegate))); + self->view_delegate = nullptr; + } + + self->derived_layout.reset(); + self->keycode_to_goals.reset(); + self->logical_to_mandatory_goals.reset(); + + 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); + g_ptr_array_free(self->pending_redispatches, TRUE); + + G_OBJECT_CLASS(fl_keyboard_handler_parent_class)->dispose(object); +} + +static void fl_keyboard_handler_class_init(FlKeyboardHandlerClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_keyboard_handler_dispose; +} + +static void fl_keyboard_handler_init(FlKeyboardHandler* self) { + self->derived_layout = std::make_unique(); + + self->keycode_to_goals = + std::make_unique>(); + self->logical_to_mandatory_goals = + std::make_unique>(); + for (const LayoutGoal& goal : layout_goals) { + (*self->keycode_to_goals)[goal.keycode] = &goal; + if (goal.mandatory) { + (*self->logical_to_mandatory_goals)[goal.logical_key] = &goal; + } + } + + 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_with_free_func(g_object_unref); + + self->last_sequence_id = 1; +} + FlKeyboardHandler* fl_keyboard_handler_new( FlBinaryMessenger* messenger, FlKeyboardViewDelegate* view_delegate) { @@ -624,17 +538,6 @@ FlKeyboardHandler* fl_keyboard_handler_new( return self; } -// 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, context->event, responder_handle_event_callback, - context->user_data, context->specified_logical_key); -} - gboolean fl_keyboard_handler_handle_event(FlKeyboardHandler* self, FlKeyEvent* event) { g_return_val_if_fail(FL_IS_KEYBOARD_HANDLER(self), FALSE); @@ -643,18 +546,17 @@ gboolean fl_keyboard_handler_handle_event(FlKeyboardHandler* self, guarantee_layout(self, event); - uint64_t incoming_hash = fl_keyboard_handler_get_event_hash(event); + uint64_t incoming_hash = fl_key_event_hash(event); if (fl_keyboard_handler_remove_redispatched(self, incoming_hash)) { return FALSE; } FlKeyboardPendingEvent* pending = fl_keyboard_pending_event_new( - std::unique_ptr(event), ++self->last_sequence_id, - self->responder_list->len); + event, ++self->last_sequence_id, self->responder_list->len); g_ptr_array_add(self->pending_responds, pending); - FlKeyboardHandlerUserData* user_data = - fl_keyboard_handler_user_data_new(self, pending->sequence_id); + FlKeyboardHandlerUserData* user_data = fl_keyboard_handler_user_data_new( + self, fl_keyboard_pending_event_get_sequence_id(pending)); DispatchToResponderLoopContext data{ .event = event, .specified_logical_key = diff --git a/shell/platform/linux/fl_keyboard_handler_test.cc b/shell/platform/linux/fl_keyboard_handler_test.cc index 6acb2abf79540..194df9bd86cce 100644 --- a/shell/platform/linux/fl_keyboard_handler_test.cc +++ b/shell/platform/linux/fl_keyboard_handler_test.cc @@ -71,7 +71,7 @@ typedef std::function ChannelCallHandler; typedef std::function EmbedderCallHandler; -typedef std::function)> RedispatchHandler; +typedef std::function RedispatchHandler; // A type that can record all kinds of effects that the keyboard handler // triggers. @@ -377,11 +377,11 @@ static FlBinaryMessenger* fl_mock_view_keyboard_get_messenger( static void fl_mock_view_keyboard_redispatch_event( FlKeyboardViewDelegate* view_delegate, - std::unique_ptr event) { + FlKeyEvent* event) { FlMockViewDelegatePrivate* priv = FL_MOCK_VIEW_DELEGATE_GET_PRIVATE(view_delegate); if (priv->redispatch_handler) { - priv->redispatch_handler(std::move(event)); + priv->redispatch_handler(event); } } @@ -467,23 +467,6 @@ static void fl_mock_view_set_layout(FlMockViewDelegate* self, /***** End FlMockViewDelegate *****/ -// Create a new #FlKeyEvent with the given information. -static FlKeyEvent* fl_key_event_new_by_mock(bool is_press, - guint keyval, - guint16 keycode, - GdkModifierType state, - gboolean is_modifier, - guint8 group = 0) { - FlKeyEvent* event = g_new0(FlKeyEvent, 1); - event->is_press = is_press; - event->time = 0; - event->state = state; - event->keyval = keyval; - event->group = group; - event->keycode = keycode; - return event; -} - class KeyboardTester { public: KeyboardTester() { @@ -502,6 +485,7 @@ class KeyboardTester { ~KeyboardTester() { g_clear_object(&view_); g_clear_object(&handler_); + g_clear_pointer(&redispatched_events_, g_ptr_array_unref); } FlKeyboardHandler* handler() { return handler_; } @@ -520,21 +504,20 @@ class KeyboardTester { // Returns the number of events redispatched. If any result is unexpected // (handled), return a minus number `-x` instead, where `x` is the index of // the first unexpected redispatch. - int redispatchEventsAndClear( - std::vector>& events) { - size_t event_count = events.size(); + int redispatchEventsAndClear(GPtrArray* events) { + guint event_count = events->len; int first_error = -1; during_redispatch_ = true; - for (size_t event_id = 0; event_id < event_count; event_id += 1) { - bool handled = fl_keyboard_handler_handle_event( - handler_, events[event_id].release()); + for (guint event_id = 0; event_id < event_count; event_id += 1) { + FlKeyEvent* event = FL_KEY_EVENT(g_ptr_array_index(events, event_id)); + bool handled = fl_keyboard_handler_handle_event(handler_, event); EXPECT_FALSE(handled); if (handled) { first_error = first_error == -1 ? event_id : first_error; } } during_redispatch_ = false; - events.clear(); + g_ptr_array_set_size(events, 0); return first_error < 0 ? event_count : -first_error; } @@ -610,12 +593,11 @@ class KeyboardTester { fl_mock_view_set_text_filter_result(view_, response); } - void recordRedispatchedEventsTo( - std::vector>& storage) { - fl_mock_view_set_redispatch_handler( - view_, [&storage](std::unique_ptr key) { - storage.push_back(std::move(key)); - }); + void recordRedispatchedEventsTo(GPtrArray* storage) { + redispatched_events_ = g_ptr_array_ref(storage); + fl_mock_view_set_redispatch_handler(view_, [this](FlKeyEvent* key) { + g_ptr_array_add(redispatched_events_, g_object_ref(key)); + }); } void setLayout(const MockLayoutData& layout) { @@ -625,6 +607,7 @@ class KeyboardTester { private: FlMockViewDelegate* view_; FlKeyboardHandler* handler_; + GPtrArray* redispatched_events_ = nullptr; bool during_redispatch_ = false; static gboolean _flushChannelMessagesCb(gpointer data) { @@ -642,16 +625,14 @@ TEST(FlKeyboardHandlerTest, DisposeWithUnresolvedPends) { // Record calls so that they aren't responded. tester.recordEmbedderCallsTo(call_records); - fl_keyboard_handler_handle_event( - tester.handler(), - fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA, - static_cast(0), false)); + g_autoptr(FlKeyEvent) event1 = fl_key_event_new( + 0, TRUE, kKeyCodeKeyA, GDK_KEY_a, static_cast(0), 0); + fl_keyboard_handler_handle_event(tester.handler(), event1); tester.respondToEmbedderCallsWith(true); - fl_keyboard_handler_handle_event( - tester.handler(), - fl_key_event_new_by_mock(false, GDK_KEY_a, kKeyCodeKeyA, - static_cast(0), false)); + g_autoptr(FlKeyEvent) event2 = fl_key_event_new( + 0, FALSE, kKeyCodeKeyA, GDK_KEY_a, static_cast(0), 0); + fl_keyboard_handler_handle_event(tester.handler(), event2); tester.flushChannelMessages(); @@ -661,7 +642,8 @@ TEST(FlKeyboardHandlerTest, DisposeWithUnresolvedPends) { TEST(FlKeyboardHandlerTest, SingleDelegateWithAsyncResponds) { KeyboardTester tester; std::vector call_records; - std::vector> redispatched; + g_autoptr(GPtrArray) redispatched = + g_ptr_array_new_with_free_func(g_object_unref); gboolean handler_handled = false; @@ -670,55 +652,56 @@ TEST(FlKeyboardHandlerTest, SingleDelegateWithAsyncResponds) { tester.recordRedispatchedEventsTo(redispatched); // Dispatch a key event - handler_handled = fl_keyboard_handler_handle_event( - tester.handler(), - fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA, - static_cast(0), false)); + g_autoptr(FlKeyEvent) event1 = fl_key_event_new( + 0, TRUE, kKeyCodeKeyA, GDK_KEY_a, static_cast(0), 0); + handler_handled = fl_keyboard_handler_handle_event(tester.handler(), event1); tester.flushChannelMessages(); EXPECT_EQ(handler_handled, true); - EXPECT_EQ(redispatched.size(), 0u); + EXPECT_EQ(redispatched->len, 0u); EXPECT_EQ(call_records.size(), 1u); EXPECT_KEY_EVENT(call_records[0], kFlutterKeyEventTypeDown, kPhysicalKeyA, kLogicalKeyA, "a", false); call_records[0].callback(true); tester.flushChannelMessages(); - EXPECT_EQ(redispatched.size(), 0u); + EXPECT_EQ(redispatched->len, 0u); EXPECT_TRUE(fl_keyboard_handler_is_state_clear(tester.handler())); call_records.clear(); /// Test 2: Two events that are unhandled by the framework - handler_handled = fl_keyboard_handler_handle_event( - tester.handler(), - fl_key_event_new_by_mock(false, GDK_KEY_a, kKeyCodeKeyA, - static_cast(0), false)); + g_autoptr(FlKeyEvent) event2 = fl_key_event_new( + 0, FALSE, kKeyCodeKeyA, GDK_KEY_a, static_cast(0), 0); + handler_handled = fl_keyboard_handler_handle_event(tester.handler(), event2); tester.flushChannelMessages(); EXPECT_EQ(handler_handled, true); - EXPECT_EQ(redispatched.size(), 0u); + EXPECT_EQ(redispatched->len, 0u); EXPECT_EQ(call_records.size(), 1u); EXPECT_KEY_EVENT(call_records[0], kFlutterKeyEventTypeUp, kPhysicalKeyA, kLogicalKeyA, nullptr, false); // Dispatch another key event - handler_handled = fl_keyboard_handler_handle_event( - tester.handler(), - fl_key_event_new_by_mock(true, GDK_KEY_b, kKeyCodeKeyB, - static_cast(0), false)); + g_autoptr(FlKeyEvent) event3 = fl_key_event_new( + 0, TRUE, kKeyCodeKeyB, GDK_KEY_b, static_cast(0), 0); + handler_handled = fl_keyboard_handler_handle_event(tester.handler(), event3); tester.flushChannelMessages(); EXPECT_EQ(handler_handled, true); - EXPECT_EQ(redispatched.size(), 0u); + EXPECT_EQ(redispatched->len, 0u); EXPECT_EQ(call_records.size(), 2u); EXPECT_KEY_EVENT(call_records[1], kFlutterKeyEventTypeDown, kPhysicalKeyB, kLogicalKeyB, "b", false); // Resolve the second event first to test out-of-order response call_records[1].callback(false); - EXPECT_EQ(redispatched.size(), 1u); - EXPECT_EQ(redispatched[0]->keyval, 0x62u); + EXPECT_EQ(redispatched->len, 1u); + EXPECT_EQ( + fl_key_event_get_keyval(FL_KEY_EVENT(g_ptr_array_index(redispatched, 0))), + 0x62u); call_records[0].callback(false); tester.flushChannelMessages(); - EXPECT_EQ(redispatched.size(), 2u); - EXPECT_EQ(redispatched[1]->keyval, 0x61u); + EXPECT_EQ(redispatched->len, 2u); + EXPECT_EQ( + fl_key_event_get_keyval(FL_KEY_EVENT(g_ptr_array_index(redispatched, 1))), + 0x61u); EXPECT_FALSE(fl_keyboard_handler_is_state_clear(tester.handler())); call_records.clear(); @@ -731,13 +714,12 @@ TEST(FlKeyboardHandlerTest, SingleDelegateWithAsyncResponds) { /// Test 3: Dispatch the same event again to ensure that prevention from /// redispatching only works once. - handler_handled = fl_keyboard_handler_handle_event( - tester.handler(), - fl_key_event_new_by_mock(false, GDK_KEY_a, kKeyCodeKeyA, - static_cast(0), false)); + g_autoptr(FlKeyEvent) event4 = fl_key_event_new( + 0, FALSE, kKeyCodeKeyA, GDK_KEY_a, static_cast(0), 0); + handler_handled = fl_keyboard_handler_handle_event(tester.handler(), event4); tester.flushChannelMessages(); EXPECT_EQ(handler_handled, true); - EXPECT_EQ(redispatched.size(), 0u); + EXPECT_EQ(redispatched->len, 0u); EXPECT_EQ(call_records.size(), 1u); call_records[0].callback(true); @@ -748,40 +730,39 @@ TEST(FlKeyboardHandlerTest, SingleDelegateWithSyncResponds) { KeyboardTester tester; gboolean handler_handled = false; std::vector call_records; - std::vector> redispatched; + g_autoptr(GPtrArray) redispatched = + g_ptr_array_new_with_free_func(g_object_unref); /// Test 1: One event that is handled by the framework tester.respondToEmbedderCallsWithAndRecordsTo(true, call_records); tester.recordRedispatchedEventsTo(redispatched); // Dispatch a key event - handler_handled = fl_keyboard_handler_handle_event( - tester.handler(), - fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA, - static_cast(0), false)); + g_autoptr(FlKeyEvent) event1 = fl_key_event_new( + 0, TRUE, kKeyCodeKeyA, GDK_KEY_a, static_cast(0), 0); + handler_handled = fl_keyboard_handler_handle_event(tester.handler(), event1); tester.flushChannelMessages(); EXPECT_EQ(handler_handled, true); EXPECT_EQ(call_records.size(), 1u); EXPECT_KEY_EVENT(call_records[0], kFlutterKeyEventTypeDown, kPhysicalKeyA, kLogicalKeyA, "a", false); - EXPECT_EQ(redispatched.size(), 0u); + EXPECT_EQ(redispatched->len, 0u); call_records.clear(); EXPECT_TRUE(fl_keyboard_handler_is_state_clear(tester.handler())); - redispatched.clear(); + g_ptr_array_set_size(redispatched, 0); /// Test 2: An event unhandled by the framework tester.respondToEmbedderCallsWithAndRecordsTo(false, call_records); - handler_handled = fl_keyboard_handler_handle_event( - tester.handler(), - fl_key_event_new_by_mock(false, GDK_KEY_a, kKeyCodeKeyA, - static_cast(0), false)); + g_autoptr(FlKeyEvent) event2 = fl_key_event_new( + 0, FALSE, kKeyCodeKeyA, GDK_KEY_a, static_cast(0), 0); + handler_handled = fl_keyboard_handler_handle_event(tester.handler(), event2); tester.flushChannelMessages(); EXPECT_EQ(handler_handled, true); EXPECT_EQ(call_records.size(), 1u); EXPECT_KEY_EVENT(call_records[0], kFlutterKeyEventTypeUp, kPhysicalKeyA, kLogicalKeyA, nullptr, false); - EXPECT_EQ(redispatched.size(), 1u); + EXPECT_EQ(redispatched->len, 1u); call_records.clear(); EXPECT_FALSE(fl_keyboard_handler_is_state_clear(tester.handler())); @@ -795,7 +776,8 @@ TEST(FlKeyboardHandlerTest, SingleDelegateWithSyncResponds) { TEST(FlKeyboardHandlerTest, WithTwoAsyncDelegates) { KeyboardTester tester; std::vector call_records; - std::vector> redispatched; + g_autoptr(GPtrArray) redispatched = + g_ptr_array_new_with_free_func(g_object_unref); gboolean handler_handled = false; @@ -805,13 +787,12 @@ TEST(FlKeyboardHandlerTest, WithTwoAsyncDelegates) { /// Test 1: One delegate responds true, the other false - handler_handled = fl_keyboard_handler_handle_event( - tester.handler(), - fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA, - static_cast(0), false)); + g_autoptr(FlKeyEvent) event1 = fl_key_event_new( + 0, TRUE, kKeyCodeKeyA, GDK_KEY_a, static_cast(0), 0); + handler_handled = fl_keyboard_handler_handle_event(tester.handler(), event1); EXPECT_EQ(handler_handled, true); - EXPECT_EQ(redispatched.size(), 0u); + EXPECT_EQ(redispatched->len, 0u); EXPECT_EQ(call_records.size(), 2u); EXPECT_EQ(call_records[0].type, CallRecord::kKeyCallEmbedder); @@ -820,19 +801,18 @@ TEST(FlKeyboardHandlerTest, WithTwoAsyncDelegates) { call_records[0].callback(true); call_records[1].callback(false); tester.flushChannelMessages(); - EXPECT_EQ(redispatched.size(), 0u); + EXPECT_EQ(redispatched->len, 0u); EXPECT_TRUE(fl_keyboard_handler_is_state_clear(tester.handler())); call_records.clear(); /// Test 2: All delegates respond false - handler_handled = fl_keyboard_handler_handle_event( - tester.handler(), - fl_key_event_new_by_mock(false, GDK_KEY_a, kKeyCodeKeyA, - static_cast(0), false)); + g_autoptr(FlKeyEvent) event2 = fl_key_event_new( + 0, FALSE, kKeyCodeKeyA, GDK_KEY_a, static_cast(0), 0); + handler_handled = fl_keyboard_handler_handle_event(tester.handler(), event2); EXPECT_EQ(handler_handled, true); - EXPECT_EQ(redispatched.size(), 0u); + EXPECT_EQ(redispatched->len, 0u); EXPECT_EQ(call_records.size(), 2u); EXPECT_EQ(call_records[0].type, CallRecord::kKeyCallEmbedder); @@ -845,7 +825,7 @@ TEST(FlKeyboardHandlerTest, WithTwoAsyncDelegates) { // Resolve redispatch tester.flushChannelMessages(); - EXPECT_EQ(redispatched.size(), 1u); + EXPECT_EQ(redispatched->len, 1u); EXPECT_EQ(tester.redispatchEventsAndClear(redispatched), 1); EXPECT_EQ(call_records.size(), 0u); @@ -854,20 +834,20 @@ TEST(FlKeyboardHandlerTest, WithTwoAsyncDelegates) { TEST(FlKeyboardHandlerTest, TextInputHandlerReturnsFalse) { KeyboardTester tester; - std::vector> redispatched; + g_autoptr(GPtrArray) redispatched = + g_ptr_array_new_with_free_func(g_object_unref); gboolean handler_handled = false; tester.recordRedispatchedEventsTo(redispatched); tester.respondToTextInputWith(false); // Dispatch a key event. - handler_handled = fl_keyboard_handler_handle_event( - tester.handler(), - fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA, - static_cast(0), false)); + g_autoptr(FlKeyEvent) event = fl_key_event_new( + 0, TRUE, kKeyCodeKeyA, GDK_KEY_a, static_cast(0), 0); + handler_handled = fl_keyboard_handler_handle_event(tester.handler(), event); tester.flushChannelMessages(); EXPECT_EQ(handler_handled, true); // The event was redispatched because no one handles it. - EXPECT_EQ(redispatched.size(), 1u); + EXPECT_EQ(redispatched->len, 1u); // Resolve redispatched event. EXPECT_EQ(tester.redispatchEventsAndClear(redispatched), 1); @@ -877,20 +857,20 @@ TEST(FlKeyboardHandlerTest, TextInputHandlerReturnsFalse) { TEST(FlKeyboardHandlerTest, TextInputHandlerReturnsTrue) { KeyboardTester tester; - std::vector> redispatched; + g_autoptr(GPtrArray) redispatched = + g_ptr_array_new_with_free_func(g_object_unref); gboolean handler_handled = false; tester.recordRedispatchedEventsTo(redispatched); tester.respondToTextInputWith(true); // Dispatch a key event. - handler_handled = fl_keyboard_handler_handle_event( - tester.handler(), - fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA, - static_cast(0), false)); + g_autoptr(FlKeyEvent) event = fl_key_event_new( + 0, TRUE, kKeyCodeKeyA, GDK_KEY_a, static_cast(0), 0); + handler_handled = fl_keyboard_handler_handle_event(tester.handler(), event); tester.flushChannelMessages(); EXPECT_EQ(handler_handled, true); // The event was not redispatched because handler handles it. - EXPECT_EQ(redispatched.size(), 0u); + EXPECT_EQ(redispatched->len, 0u); EXPECT_TRUE(fl_keyboard_handler_is_state_clear(tester.handler())); } @@ -902,14 +882,12 @@ TEST(FlKeyboardHandlerTest, CorrectLogicalKeyForLayouts) { tester.recordEmbedderCallsTo(call_records); auto sendTap = [&](guint8 keycode, guint keyval, guint8 group) { - fl_keyboard_handler_handle_event( - tester.handler(), fl_key_event_new_by_mock( - true, keyval, keycode, - static_cast(0), false, group)); - fl_keyboard_handler_handle_event( - tester.handler(), fl_key_event_new_by_mock( - false, keyval, keycode, - static_cast(0), false, group)); + g_autoptr(FlKeyEvent) event1 = fl_key_event_new( + 0, TRUE, keycode, keyval, static_cast(0), group); + fl_keyboard_handler_handle_event(tester.handler(), event1); + g_autoptr(FlKeyEvent) event2 = fl_key_event_new( + 0, FALSE, keycode, keyval, static_cast(0), group); + fl_keyboard_handler_handle_event(tester.handler(), event2); }; /* US keyboard layout */ @@ -1033,10 +1011,9 @@ TEST(FlKeyboardHandlerTest, GetPressedState) { tester.respondToTextInputWith(true); // Dispatch a key event. - fl_keyboard_handler_handle_event( - tester.handler(), - fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA, - static_cast(0), false)); + g_autoptr(FlKeyEvent) event = fl_key_event_new( + 0, TRUE, kKeyCodeKeyA, GDK_KEY_a, static_cast(0), 0); + fl_keyboard_handler_handle_event(tester.handler(), event); GHashTable* pressedState = fl_keyboard_handler_get_pressed_state(tester.handler()); diff --git a/shell/platform/linux/fl_keyboard_pending_event.cc b/shell/platform/linux/fl_keyboard_pending_event.cc new file mode 100644 index 0000000000000..eb9b6c37e4cfc --- /dev/null +++ b/shell/platform/linux/fl_keyboard_pending_event.cc @@ -0,0 +1,105 @@ +// 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_pending_event.h" + +/** + * FlKeyboardPendingEvent: + * A record for events that have been received by the handler, 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. + */ + +struct _FlKeyboardPendingEvent { + GObject parent_instance; + + // The target event. + FlKeyEvent* event; + + // Unique ID to identify pending responds. + 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; +}; + +G_DEFINE_TYPE(FlKeyboardPendingEvent, fl_keyboard_pending_event, G_TYPE_OBJECT) + +static void fl_keyboard_pending_event_dispose(GObject* object) { + FlKeyboardPendingEvent* self = FL_KEYBOARD_PENDING_EVENT(object); + + g_clear_object(&self->event); + + G_OBJECT_CLASS(fl_keyboard_pending_event_parent_class)->dispose(object); +} + +static void fl_keyboard_pending_event_class_init( + FlKeyboardPendingEventClass* klass) { + G_OBJECT_CLASS(klass)->dispose = fl_keyboard_pending_event_dispose; +} + +static void fl_keyboard_pending_event_init(FlKeyboardPendingEvent* self) {} + +// Creates 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(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)); + + self->event = FL_KEY_EVENT(g_object_ref(event)); + self->sequence_id = sequence_id; + self->unreplied = to_reply; + self->any_handled = false; + self->hash = fl_key_event_hash(self->event); + + return self; +} + +FlKeyEvent* fl_keyboard_pending_event_get_event(FlKeyboardPendingEvent* self) { + g_return_val_if_fail(FL_IS_KEYBOARD_PENDING_EVENT(self), nullptr); + return self->event; +} + +uint64_t fl_keyboard_pending_event_get_sequence_id( + FlKeyboardPendingEvent* self) { + g_return_val_if_fail(FL_IS_KEYBOARD_PENDING_EVENT(self), 0); + return self->sequence_id; +} + +uint64_t fl_keyboard_pending_event_get_hash(FlKeyboardPendingEvent* self) { + g_return_val_if_fail(FL_IS_KEYBOARD_PENDING_EVENT(self), 0); + return self->hash; +} + +void fl_keyboard_pending_event_mark_replied(FlKeyboardPendingEvent* self, + gboolean handled) { + g_return_if_fail(FL_IS_KEYBOARD_PENDING_EVENT(self)); + g_return_if_fail(self->unreplied > 0); + self->unreplied -= 1; + if (handled) { + self->any_handled = TRUE; + } +} + +gboolean fl_keyboard_pending_event_get_any_handled( + FlKeyboardPendingEvent* self) { + g_return_val_if_fail(FL_IS_KEYBOARD_PENDING_EVENT(self), FALSE); + return self->any_handled; +} + +gboolean fl_keyboard_pending_event_is_complete(FlKeyboardPendingEvent* self) { + g_return_val_if_fail(FL_IS_KEYBOARD_PENDING_EVENT(self), FALSE); + return self->unreplied == 0; +} diff --git a/shell/platform/linux/fl_keyboard_pending_event.h b/shell/platform/linux/fl_keyboard_pending_event.h new file mode 100644 index 0000000000000..50204d681b429 --- /dev/null +++ b/shell/platform/linux/fl_keyboard_pending_event.h @@ -0,0 +1,39 @@ +// 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_PENDING_EVENT_H_ +#define FLUTTER_SHELL_PLATFORM_LINUX_FL_KEYBOARD_PENDING_EVENT_H_ + +#include "fl_key_event.h" + +G_BEGIN_DECLS + +G_DECLARE_FINAL_TYPE(FlKeyboardPendingEvent, + fl_keyboard_pending_event, + FL, + KEYBOARD_PENDING_EVENT, + GObject); + +FlKeyboardPendingEvent* fl_keyboard_pending_event_new(FlKeyEvent* event, + uint64_t sequence_id, + size_t to_reply); + +FlKeyEvent* fl_keyboard_pending_event_get_event(FlKeyboardPendingEvent* event); + +uint64_t fl_keyboard_pending_event_get_sequence_id( + FlKeyboardPendingEvent* event); + +uint64_t fl_keyboard_pending_event_get_hash(FlKeyboardPendingEvent* event); + +void fl_keyboard_pending_event_mark_replied(FlKeyboardPendingEvent* event, + gboolean handled); + +gboolean fl_keyboard_pending_event_get_any_handled( + FlKeyboardPendingEvent* event); + +gboolean fl_keyboard_pending_event_is_complete(FlKeyboardPendingEvent* event); + +G_END_DECLS + +#endif // FLUTTER_SHELL_PLATFORM_LINUX_FL_KEYBOARD_PENDING_EVENT_H_ diff --git a/shell/platform/linux/fl_keyboard_view_delegate.cc b/shell/platform/linux/fl_keyboard_view_delegate.cc index 3c5fac95a8c4d..e3c79c223cdcd 100644 --- a/shell/platform/linux/fl_keyboard_view_delegate.cc +++ b/shell/platform/linux/fl_keyboard_view_delegate.cc @@ -39,14 +39,13 @@ FlBinaryMessenger* fl_keyboard_view_delegate_get_messenger( return FL_KEYBOARD_VIEW_DELEGATE_GET_IFACE(self)->get_messenger(self); } -void fl_keyboard_view_delegate_redispatch_event( - FlKeyboardViewDelegate* self, - std::unique_ptr event) { +void fl_keyboard_view_delegate_redispatch_event(FlKeyboardViewDelegate* self, + FlKeyEvent* event) { g_return_if_fail(FL_IS_KEYBOARD_VIEW_DELEGATE(self)); g_return_if_fail(event != nullptr); - return FL_KEYBOARD_VIEW_DELEGATE_GET_IFACE(self)->redispatch_event( - self, std::move(event)); + return FL_KEYBOARD_VIEW_DELEGATE_GET_IFACE(self)->redispatch_event(self, + event); } void fl_keyboard_view_delegate_subscribe_to_layout_change( diff --git a/shell/platform/linux/fl_keyboard_view_delegate.h b/shell/platform/linux/fl_keyboard_view_delegate.h index 59fdc3f29e360..a84cc58cbd160 100644 --- a/shell/platform/linux/fl_keyboard_view_delegate.h +++ b/shell/platform/linux/fl_keyboard_view_delegate.h @@ -46,8 +46,7 @@ struct _FlKeyboardViewDelegateInterface { FlBinaryMessenger* (*get_messenger)(FlKeyboardViewDelegate* delegate); - void (*redispatch_event)(FlKeyboardViewDelegate* delegate, - std::unique_ptr event); + void (*redispatch_event)(FlKeyboardViewDelegate* delegate, FlKeyEvent* event); void (*subscribe_to_layout_change)(FlKeyboardViewDelegate* delegate, KeyboardLayoutNotifier notifier); @@ -103,13 +102,10 @@ FlBinaryMessenger* fl_keyboard_view_delegate_get_messenger( * * Handles `FlKeyboardHandler`'s request to insert a GDK event to the system for * redispatching. - * - * The ownership of event will be transferred to the view delegate. The view - * delegate is responsible to call fl_key_event_dispose. */ void fl_keyboard_view_delegate_redispatch_event( FlKeyboardViewDelegate* delegate, - std::unique_ptr event); + FlKeyEvent* event); void fl_keyboard_view_delegate_subscribe_to_layout_change( FlKeyboardViewDelegate* delegate, diff --git a/shell/platform/linux/fl_text_input_handler.cc b/shell/platform/linux/fl_text_input_handler.cc index afc8afc09858c..f4d3eb70113c9 100644 --- a/shell/platform/linux/fl_text_input_handler.cc +++ b/shell/platform/linux/fl_text_input_handler.cc @@ -627,7 +627,8 @@ static gboolean fl_text_input_handler_filter_keypress_default( } if (gtk_im_context_filter_keypress( - priv->im_context, reinterpret_cast(event->origin))) { + priv->im_context, + reinterpret_cast(fl_key_event_get_origin(event)))) { return TRUE; } @@ -639,11 +640,11 @@ static gboolean fl_text_input_handler_filter_keypress_default( gboolean do_action = FALSE; // Handle navigation keys. gboolean changed = FALSE; - if (event->is_press) { - switch (event->keyval) { + if (fl_key_event_get_is_press(event)) { + switch (fl_key_event_get_keyval(event)) { case GDK_KEY_End: case GDK_KEY_KP_End: - if (event->state & GDK_SHIFT_MASK) { + if (fl_key_event_get_state(event) & GDK_SHIFT_MASK) { changed = priv->text_model->SelectToEnd(); } else { changed = priv->text_model->MoveCursorToEnd(); @@ -662,7 +663,7 @@ static gboolean fl_text_input_handler_filter_keypress_default( break; case GDK_KEY_Home: case GDK_KEY_KP_Home: - if (event->state & GDK_SHIFT_MASK) { + if (fl_key_event_get_state(event) & GDK_SHIFT_MASK) { changed = priv->text_model->SelectToBeginning(); } else { changed = priv->text_model->MoveCursorToBeginning(); diff --git a/shell/platform/linux/fl_text_input_handler_test.cc b/shell/platform/linux/fl_text_input_handler_test.cc index 4c4606ac7809e..7787b422c3c6c 100644 --- a/shell/platform/linux/fl_text_input_handler_test.cc +++ b/shell/platform/linux/fl_text_input_handler_test.cc @@ -184,9 +184,8 @@ static void send_key_event(FlTextInputHandler* handler, GdkEvent* gdk_event = gdk_event_new(GDK_KEY_PRESS); gdk_event->key.keyval = keyval; gdk_event->key.state = state; - FlKeyEvent* key_event = fl_key_event_new_from_gdk_event(gdk_event); + g_autoptr(FlKeyEvent) key_event = fl_key_event_new_from_gdk_event(gdk_event); fl_text_input_handler_filter_keypress(handler, key_event); - fl_key_event_dispose(key_event); } TEST(FlTextInputHandlerTest, MessageHandler) { diff --git a/shell/platform/linux/fl_view.cc b/shell/platform/linux/fl_view.cc index bfaedc5496423..e84b144142a0c 100644 --- a/shell/platform/linux/fl_view.cc +++ b/shell/platform/linux/fl_view.cc @@ -357,13 +357,12 @@ static void fl_view_keyboard_delegate_iface_init( }; iface->redispatch_event = [](FlKeyboardViewDelegate* view_delegate, - std::unique_ptr in_event) { - FlKeyEvent* event = in_event.release(); - GdkEventType event_type = gdk_event_get_event_type(event->origin); + FlKeyEvent* event) { + GdkEventType event_type = + gdk_event_get_event_type(fl_key_event_get_origin(event)); g_return_if_fail(event_type == GDK_KEY_PRESS || event_type == GDK_KEY_RELEASE); - gdk_event_put(event->origin); - fl_key_event_dispose(event); + gdk_event_put(fl_key_event_get_origin(event)); }; iface->subscribe_to_layout_change = [](FlKeyboardViewDelegate* view_delegate,