Skip to content

Commit 4228b72

Browse files
[Linux, Keyboard] Derive keyboard layout using printable information from system (flutter#32665)
* Workable layout deduction * Compilable test * Tests * Remove print, format * Use new way to pass logical key * Use unique_ptr * Format * Fix matrix format * Format * Cleanup * Remove duplicate * Remove printf * Update shell/platform/linux/fl_keyboard_manager.cc Co-authored-by: Greg Spencer <gspencergoog@users.noreply.github.com> Co-authored-by: Greg Spencer <gspencergoog@users.noreply.github.com>
1 parent 183156c commit 4228b72

18 files changed

+848
-66
lines changed

shell/platform/darwin/macos/framework/Source/FlutterKeyboardManager.mm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ - (void)buildLayout {
283283
//
284284
// - Mandatory goal, if it matches any clue. This ensures that all alnum
285285
// keys can be found somewhere.
286-
// - US layout, if neither clue of the key is EASCII. This ensures that
286+
// - US layout, if neither clue of the key is EASCII. This ensures that
287287
// there are no non-latin logical keys.
288288
// - Derived on the fly from keyCode & characters.
289289
for (const LayoutClue& clue : thisKeyClues) {

shell/platform/embedder/test_utils/key_codes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ constexpr uint64_t kPhysicalSuspend = 0x00000014;
3535
constexpr uint64_t kPhysicalResume = 0x00000015;
3636
constexpr uint64_t kPhysicalTurbo = 0x00000016;
3737
constexpr uint64_t kPhysicalPrivacyScreenToggle = 0x00000017;
38+
constexpr uint64_t kPhysicalMicrophoneMuteToggle = 0x00000018;
3839
constexpr uint64_t kPhysicalSleep = 0x00010082;
3940
constexpr uint64_t kPhysicalWakeUp = 0x00010083;
4041
constexpr uint64_t kPhysicalDisplayToggleIntExt = 0x000100b5;

shell/platform/linux/fl_key_channel_responder.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ static constexpr char kKeyCodeKey[] = "keyCode";
1919
static constexpr char kScanCodeKey[] = "scanCode";
2020
static constexpr char kModifiersKey[] = "modifiers";
2121
static constexpr char kToolkitKey[] = "toolkit";
22+
static constexpr char kSpecifiedLogicalKey[] = "specifiedLogicalKey";
2223
static constexpr char kUnicodeScalarValuesKey[] = "unicodeScalarValues";
2324

2425
static constexpr char kGtkToolkit[] = "gtk";
@@ -115,6 +116,7 @@ G_DEFINE_TYPE_WITH_CODE(
115116
static void fl_key_channel_responder_handle_event(
116117
FlKeyResponder* responder,
117118
FlKeyEvent* event,
119+
uint64_t specified_logical_key,
118120
FlKeyResponderAsyncCallback callback,
119121
gpointer user_data);
120122

@@ -203,6 +205,7 @@ FlKeyChannelResponder* fl_key_channel_responder_new(
203205
static void fl_key_channel_responder_handle_event(
204206
FlKeyResponder* responder,
205207
FlKeyEvent* event,
208+
uint64_t specified_logical_key,
206209
FlKeyResponderAsyncCallback callback,
207210
gpointer user_data) {
208211
FlKeyChannelResponder* self = FL_KEY_CHANNEL_RESPONDER(responder);
@@ -273,6 +276,11 @@ static void fl_key_channel_responder_handle_event(
273276
fl_value_new_int(unicode_scarlar_values));
274277
}
275278

279+
if (specified_logical_key != 0) {
280+
fl_value_set_string_take(message, kSpecifiedLogicalKey,
281+
fl_value_new_int(specified_logical_key));
282+
}
283+
276284
FlKeyChannelUserData* data =
277285
fl_key_channel_user_data_new(self, callback, user_data);
278286
// Send the message off to the framework for handling (or not).

shell/platform/linux/fl_key_channel_responder_test.cc

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,3 +203,30 @@ TEST(FlKeyChannelResponderTest, TestKeyEventHandledByFramework) {
203203
// Blocks here until echo_response_cb is called.
204204
g_main_loop_run(loop);
205205
}
206+
207+
TEST(FlKeyChannelResponderTest, UseSpecifiedLogicalKey) {
208+
g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
209+
210+
g_autoptr(FlEngine) engine = make_mock_engine();
211+
g_autoptr(FlBinaryMessenger) messenger = fl_binary_messenger_new(engine);
212+
FlKeyChannelResponderMock mock{
213+
.value_converter = echo_response_cb,
214+
.channel_name = "test/echo",
215+
};
216+
g_autoptr(FlKeyResponder) responder =
217+
FL_KEY_RESPONDER(fl_key_channel_responder_new(messenger, &mock));
218+
219+
fl_key_responder_handle_event(
220+
responder,
221+
fl_key_event_new_by_mock(12345, true, GDK_KEY_A, 0x04, 0x0, nullptr,
222+
false),
223+
responder_callback, loop, 888);
224+
expected_handled = TRUE;
225+
expected_value =
226+
"{type: keydown, keymap: linux, scanCode: 4, toolkit: gtk, "
227+
"keyCode: 65, modifiers: 0, unicodeScalarValues: 65, "
228+
"specifiedLogicalKey: 888}";
229+
230+
// Blocks here until echo_response_cb is called.
231+
g_main_loop_run(loop);
232+
}

shell/platform/linux/fl_key_embedder_responder.cc

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ G_DEFINE_TYPE_WITH_CODE(
212212
static void fl_key_embedder_responder_handle_event(
213213
FlKeyResponder* responder,
214214
FlKeyEvent* event,
215+
uint64_t specified_logical_key,
215216
FlKeyResponderAsyncCallback callback,
216217
gpointer user_data);
217218

@@ -698,6 +699,7 @@ static void synchronize_lock_states_loop_body(gpointer key,
698699
static void fl_key_embedder_responder_handle_event_impl(
699700
FlKeyResponder* responder,
700701
FlKeyEvent* event,
702+
uint64_t specified_logical_key,
701703
FlKeyResponderAsyncCallback callback,
702704
gpointer user_data) {
703705
FlKeyEmbedderResponder* self = FL_KEY_EMBEDDER_RESPONDER(responder);
@@ -706,7 +708,9 @@ static void fl_key_embedder_responder_handle_event_impl(
706708
g_return_if_fail(callback != nullptr);
707709

708710
const uint64_t physical_key = event_to_physical_key(event);
709-
const uint64_t logical_key = event_to_logical_key(event);
711+
const uint64_t logical_key = specified_logical_key != 0
712+
? specified_logical_key
713+
: event_to_logical_key(event);
710714
const double timestamp = event_to_timestamp(event);
711715
const bool is_down_event = event->is_press;
712716

@@ -777,12 +781,13 @@ static void fl_key_embedder_responder_handle_event_impl(
777781
static void fl_key_embedder_responder_handle_event(
778782
FlKeyResponder* responder,
779783
FlKeyEvent* event,
784+
uint64_t specified_logical_key,
780785
FlKeyResponderAsyncCallback callback,
781786
gpointer user_data) {
782787
FlKeyEmbedderResponder* self = FL_KEY_EMBEDDER_RESPONDER(responder);
783788
self->sent_any_events = false;
784-
fl_key_embedder_responder_handle_event_impl(responder, event, callback,
785-
user_data);
789+
fl_key_embedder_responder_handle_event_impl(
790+
responder, event, specified_logical_key, callback, user_data);
786791
if (!self->sent_any_events) {
787792
self->send_key_event(&empty_event, nullptr, nullptr);
788793
}

shell/platform/linux/fl_key_embedder_responder_test.cc

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,6 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) {
194194
invoke_record_callback_and_verify(record, TRUE, &user_data);
195195
g_ptr_array_clear(g_call_records);
196196

197-
// Skip testing key repeats, which is not present on GDK.
198-
199197
// Key up
200198
fl_key_responder_handle_event(
201199
responder,
@@ -261,6 +259,41 @@ TEST(FlKeyEmbedderResponderTest, SendKeyEvent) {
261259
g_object_unref(responder);
262260
}
263261

262+
// Basic key presses, but uses the specified logical key if it is not 0.
263+
TEST(FlKeyEmbedderResponderTest, UsesSpecifiedLogicalKey) {
264+
EXPECT_EQ(g_call_records, nullptr);
265+
g_call_records = g_ptr_array_new_with_free_func(g_object_unref);
266+
FlKeyResponder* responder = FL_KEY_RESPONDER(
267+
fl_key_embedder_responder_new(record_calls_in(g_call_records)));
268+
int user_data = 123; // Arbitrary user data
269+
270+
FlKeyEmbedderCallRecord* record;
271+
272+
// On an AZERTY keyboard, press physical key 1, and release.
273+
// Key down
274+
fl_key_responder_handle_event(
275+
responder,
276+
fl_key_event_new_by_mock(12345, kPress, GDK_KEY_ampersand, kKeyCodeDigit1,
277+
0, kIsNotModifier),
278+
verify_response_handled, &user_data, kLogicalDigit1);
279+
280+
EXPECT_EQ(g_call_records->len, 1u);
281+
record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
282+
EXPECT_EQ(record->event->struct_size, sizeof(FlutterKeyEvent));
283+
EXPECT_EQ(record->event->timestamp, 12345000);
284+
EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
285+
EXPECT_EQ(record->event->physical, kPhysicalDigit1);
286+
EXPECT_EQ(record->event->logical, kLogicalDigit1);
287+
EXPECT_STREQ(record->event->character, "&");
288+
EXPECT_EQ(record->event->synthesized, false);
289+
290+
invoke_record_callback_and_verify(record, TRUE, &user_data);
291+
g_ptr_array_clear(g_call_records);
292+
293+
clear_g_call_records();
294+
g_object_unref(responder);
295+
}
296+
264297
// Press Shift, key A, then release Shift, key A.
265298
TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) {
266299
EXPECT_EQ(g_call_records, nullptr);

shell/platform/linux/fl_key_event.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ FlKeyEvent* fl_key_event_new_from_gdk_event(GdkEvent* raw_event) {
3333
result->keyval = event->keyval;
3434
result->state = event->state;
3535
result->string = clone_string(event->string);
36+
result->group = event->group;
3637
result->origin = event;
3738
result->dispose_origin = dispose_origin_from_gdk_event;
3839

shell/platform/linux/fl_key_event.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ typedef struct _FlKeyEvent {
3939
guint keyval;
4040
// Modifier state.
4141
int state;
42+
// Keyboard group.
43+
guint8 group;
4244
// String, null-terminated.
4345
//
4446
// Can be nullptr.

shell/platform/linux/fl_key_responder.cc

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,12 @@ static void fl_key_responder_default_init(FlKeyResponderInterface* iface) {}
1111
void fl_key_responder_handle_event(FlKeyResponder* self,
1212
FlKeyEvent* event,
1313
FlKeyResponderAsyncCallback callback,
14-
gpointer user_data) {
14+
gpointer user_data,
15+
uint64_t specified_logical_key) {
1516
g_return_if_fail(FL_IS_KEY_RESPONDER(self));
1617
g_return_if_fail(event != nullptr);
1718
g_return_if_fail(callback != nullptr);
1819

19-
FL_KEY_RESPONDER_GET_IFACE(self)->handle_event(self, event, callback,
20-
user_data);
20+
FL_KEY_RESPONDER_GET_IFACE(self)->handle_event(
21+
self, event, specified_logical_key, callback, user_data);
2122
}

shell/platform/linux/fl_key_responder.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ struct _FlKeyResponderInterface {
5353
*/
5454
void (*handle_event)(FlKeyResponder* responder,
5555
FlKeyEvent* event,
56+
uint64_t specified_logical_key,
5657
FlKeyResponderAsyncCallback callback,
5758
gpointer user_data);
5859
};
@@ -74,7 +75,8 @@ struct _FlKeyResponderInterface {
7475
void fl_key_responder_handle_event(FlKeyResponder* responder,
7576
FlKeyEvent* event,
7677
FlKeyResponderAsyncCallback callback,
77-
gpointer user_data);
78+
gpointer user_data,
79+
uint64_t specified_logical_key = 0);
7880

7981
G_END_DECLS
8082

0 commit comments

Comments
 (0)