diff --git a/shell/platform/linux/fl_key_embedder_responder.cc b/shell/platform/linux/fl_key_embedder_responder.cc index 982273ffb746e..cdb46b73cbc35 100644 --- a/shell/platform/linux/fl_key_embedder_responder.cc +++ b/shell/platform/linux/fl_key_embedder_responder.cc @@ -714,7 +714,8 @@ static void fl_key_embedder_responder_handle_event_impl( out_event.struct_size = sizeof(out_event); out_event.timestamp = timestamp; out_event.physical = physical_key; - out_event.logical = logical_key; + out_event.logical = + last_logical_record != 0 ? last_logical_record : logical_key; out_event.character = nullptr; out_event.synthesized = false; diff --git a/shell/platform/linux/fl_key_embedder_responder_test.cc b/shell/platform/linux/fl_key_embedder_responder_test.cc index 48d2681f0dac3..0fae15d0a1275 100644 --- a/shell/platform/linux/fl_key_embedder_responder_test.cc +++ b/shell/platform/linux/fl_key_embedder_responder_test.cc @@ -19,7 +19,9 @@ constexpr gboolean kPress = TRUE; constexpr gboolean kIsModifier = TRUE; constexpr gboolean kIsNotModifier = FALSE; +constexpr guint16 kKeyCodeDigit1 = 0x0au; constexpr guint16 kKeyCodeKeyA = 0x26u; +constexpr guint16 kKeyCodeShiftLeft = 0x32u; constexpr guint16 kKeyCodeShiftRight = 0x3Eu; constexpr guint16 kKeyCodeNumpad1 = 0x57u; constexpr guint16 kKeyCodeNumLock = 0x4Du; @@ -527,6 +529,103 @@ TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) { g_object_unref(responder); } +// Press or release digit 1 between presses/releases of Shift. +// +// GTK will change the virtual key during a key tap, and the embedder +// should regularize it. +TEST(FlKeyEmbedderResponderTest, ReleaseShiftKeyBetweenDigitKeyEvents) { + EXPECT_EQ(g_call_records, nullptr); + g_call_records = g_ptr_array_new_with_free_func(g_object_unref); + FlEngine* engine = make_mock_engine_with_records(); + FlKeyResponder* responder = + FL_KEY_RESPONDER(fl_key_embedder_responder_new(engine)); + int user_data = 123; // Arbitrary user data + + FlKeyEmbedderCallRecord* record; + + guint state = 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); + + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->physical, kPhysicalShiftLeft); + EXPECT_EQ(record->event->logical, kLogicalShiftLeft); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + 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); + + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown); + EXPECT_EQ(record->event->physical, kPhysicalDigit1); + EXPECT_EQ(record->event->logical, kLogicalExclamation); + EXPECT_STREQ(record->event->character, "!"); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + 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); + + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); + EXPECT_EQ(record->event->physical, kPhysicalShiftLeft); + EXPECT_EQ(record->event->logical, kLogicalShiftLeft); + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + state = 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); + + EXPECT_EQ(g_call_records->len, 1u); + record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0)); + EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp); + EXPECT_EQ(record->event->physical, kPhysicalDigit1); + EXPECT_EQ(record->event->logical, kLogicalExclamation); // Important + EXPECT_STREQ(record->event->character, nullptr); + EXPECT_EQ(record->event->synthesized, false); + + invoke_record_callback_and_verify(record, TRUE, &user_data); + g_ptr_array_clear(g_call_records); + + clear_g_call_records(); + g_object_unref(engine); + g_object_unref(responder); +} + // Press or release letter key between presses/releases of CapsLock. // // This tests interaction between lock keys and non-lock keys in cases that do