10 #include "flutter/shell/platform/embedder/test_utils/key_codes.g.h"
13 #include "flutter/shell/platform/linux/testing/fl_mock_binary_messenger.h"
14 #include "flutter/shell/platform/linux/testing/mock_keymap.h"
16 #include "gtest/gtest.h"
21 #define EXPECT_KEY_EVENT(RECORD, TYPE, PHYSICAL, LOGICAL, CHAR, SYNTHESIZED) \
22 EXPECT_EQ((RECORD)->event_type, (TYPE)); \
23 EXPECT_EQ((RECORD)->event_physical, (PHYSICAL)); \
24 EXPECT_EQ((RECORD)->event_logical, (LOGICAL)); \
25 EXPECT_STREQ((RECORD)->event_character, (CHAR)); \
26 EXPECT_EQ((RECORD)->event_synthesized, (SYNTHESIZED));
28 #define VERIFY_DOWN(OUT_LOGICAL, OUT_CHAR) \
29 EXPECT_EQ(static_cast<CallRecord*>(g_ptr_array_index(call_records, 0)) \
31 kFlutterKeyEventTypeDown); \
32 EXPECT_EQ(static_cast<CallRecord*>(g_ptr_array_index(call_records, 0)) \
35 EXPECT_STREQ(static_cast<CallRecord*>(g_ptr_array_index(call_records, 0)) \
38 EXPECT_EQ(static_cast<CallRecord*>(g_ptr_array_index(call_records, 0)) \
39 ->event_synthesized, \
41 g_ptr_array_set_size(call_records, 0)
54 FlutterKeyEventCallback callback,
55 void* callback_user_data) {
79 using ::flutter::testing::keycodes::kLogicalAltLeft;
80 using ::flutter::testing::keycodes::kLogicalBracketLeft;
81 using ::flutter::testing::keycodes::kLogicalComma;
82 using ::flutter::testing::keycodes::kLogicalControlLeft;
83 using ::flutter::testing::keycodes::kLogicalDigit1;
84 using ::flutter::testing::keycodes::kLogicalKeyA;
85 using ::flutter::testing::keycodes::kLogicalKeyB;
86 using ::flutter::testing::keycodes::kLogicalKeyM;
87 using ::flutter::testing::keycodes::kLogicalKeyQ;
88 using ::flutter::testing::keycodes::kLogicalMetaLeft;
89 using ::flutter::testing::keycodes::kLogicalMinus;
90 using ::flutter::testing::keycodes::kLogicalParenthesisRight;
91 using ::flutter::testing::keycodes::kLogicalSemicolon;
92 using ::flutter::testing::keycodes::kLogicalShiftLeft;
93 using ::flutter::testing::keycodes::kLogicalUnderscore;
95 using ::flutter::testing::keycodes::kPhysicalAltLeft;
96 using ::flutter::testing::keycodes::kPhysicalControlLeft;
97 using ::flutter::testing::keycodes::kPhysicalKeyA;
98 using ::flutter::testing::keycodes::kPhysicalKeyB;
99 using ::flutter::testing::keycodes::kPhysicalMetaLeft;
100 using ::flutter::testing::keycodes::kPhysicalShiftLeft;
102 constexpr guint16 kKeyCodeKeyA = 0x26u;
103 constexpr guint16 kKeyCodeKeyB = 0x38u;
104 constexpr guint16 kKeyCodeKeyM = 0x3au;
105 constexpr guint16 kKeyCodeDigit1 = 0x0au;
106 constexpr guint16 kKeyCodeMinus = 0x14u;
107 constexpr guint16 kKeyCodeSemicolon = 0x2fu;
108 constexpr guint16 kKeyCodeKeyLeftBracket = 0x22u;
115 typedef std::array<uint32_t, 256> MockGroupLayoutData;
116 typedef std::vector<const MockGroupLayoutData*> MockLayoutData;
118 extern const MockLayoutData kLayoutRussian;
119 extern const MockLayoutData kLayoutFrench;
124 fl_mock_view_delegate,
131 struct _FlMockViewDelegate {
132 GObject parent_instance;
133 bool text_filter_result;
136 static void fl_mock_view_keyboard_delegate_iface_init(
137 FlKeyboardViewDelegateInterface* iface);
141 fl_mock_view_delegate,
143 G_IMPLEMENT_INTERFACE(fl_keyboard_view_delegate_get_type(),
144 fl_mock_view_keyboard_delegate_iface_init))
146 static void fl_mock_view_delegate_init(FlMockViewDelegate*
self) {}
148 static void fl_mock_view_delegate_class_init(FlMockViewDelegateClass* klass) {}
150 static gboolean fl_mock_view_keyboard_text_filter_key_press(
151 FlKeyboardViewDelegate* view_delegate,
153 FlMockViewDelegate*
self = FL_MOCK_VIEW_DELEGATE(view_delegate);
154 return self->text_filter_result;
157 static void fl_mock_view_keyboard_delegate_iface_init(
158 FlKeyboardViewDelegateInterface* iface) {
159 iface->text_filter_key_press = fl_mock_view_keyboard_text_filter_key_press;
162 static FlMockViewDelegate* fl_mock_view_delegate_new() {
163 FlMockViewDelegate*
self = FL_MOCK_VIEW_DELEGATE(
164 g_object_new(fl_mock_view_delegate_get_type(),
nullptr));
167 FL_IS_MOCK_VIEW_DELEGATE(
self);
172 static void fl_mock_view_set_text_filter_result(FlMockViewDelegate*
self,
174 self->text_filter_result = result;
179 static void flush_channel_messages() {
180 GMainLoop* loop = g_main_loop_new(
nullptr, 0);
183 g_autoptr(GMainLoop) loop =
reinterpret_cast<GMainLoop*
>(data);
184 g_main_loop_quit(loop);
188 g_main_loop_run(loop);
197 int redispatch_events_and_clear(FlKeyboardManager* manager, GPtrArray* events) {
198 guint event_count = events->len;
199 for (guint event_id = 0; event_id < event_count; event_id += 1) {
200 FlKeyEvent*
event = FL_KEY_EVENT(g_ptr_array_index(events, event_id));
203 g_ptr_array_set_size(events, 0);
209 TEST(FlKeyboardManagerTest, DisposeWithUnresolvedPends) {
210 ::testing::NiceMock<flutter::testing::MockKeymap> mock_keymap;
214 g_autoptr(FlMockViewDelegate)
view = fl_mock_view_delegate_new();
215 g_autoptr(FlKeyboardManager) manager =
218 g_autoptr(GError)
error =
nullptr;
220 EXPECT_EQ(
error,
nullptr);
225 [](
const FlutterKeyEvent* event, FlutterKeyEventCallback callback,
226 void* callback_user_data, gpointer
user_data) {},
229 0,
TRUE, kKeyCodeKeyA, GDK_KEY_a,
static_cast<GdkModifierType
>(0), 0);
235 [](
const FlutterKeyEvent* event, FlutterKeyEventCallback callback,
236 void* callback_user_data,
237 gpointer
user_data) { callback(
true, callback_user_data); },
240 0, FALSE, kKeyCodeKeyA, GDK_KEY_a,
static_cast<GdkModifierType
>(0), 0);
246 TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) {
247 ::testing::NiceMock<flutter::testing::MockKeymap> mock_keymap;
249 g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new();
250 fl_mock_binary_messenger_set_json_message_channel(
251 messenger,
"flutter/keyevent",
252 [](FlMockBinaryMessenger* messenger, GTask* task,
FlValue* message,
261 g_autoptr(FlMockViewDelegate)
view = fl_mock_view_delegate_new();
262 g_autoptr(FlEngine) engine =
263 FL_ENGINE(g_object_new(fl_engine_get_type(),
"binary-messenger",
264 FL_BINARY_MESSENGER(messenger),
nullptr));
265 g_autoptr(FlKeyboardManager) manager =
268 manager, [](
const GdkKeymapKey* key, gpointer
user_data) {
return 0u; },
272 g_autoptr(GPtrArray) call_records = g_ptr_array_new_with_free_func(
276 [](
const FlutterKeyEvent* event, FlutterKeyEventCallback callback,
277 void* callback_user_data, gpointer
user_data) {
278 GPtrArray* call_records =
static_cast<GPtrArray*
>(
user_data);
279 g_ptr_array_add(call_records,
283 g_autoptr(GPtrArray) redispatched =
284 g_ptr_array_new_with_free_func(g_object_unref);
287 [](FlKeyEvent* event, gpointer
user_data) {
288 GPtrArray* redispatched =
static_cast<GPtrArray*
>(
user_data);
289 g_ptr_array_add(redispatched, g_object_ref(event));
295 0,
TRUE, kKeyCodeKeyA, GDK_KEY_a,
static_cast<GdkModifierType
>(0), 0);
297 flush_channel_messages();
298 EXPECT_EQ(redispatched->len, 0u);
299 EXPECT_EQ(call_records->len, 1u);
301 kFlutterKeyEventTypeDown, kPhysicalKeyA, kLogicalKeyA,
"a",
305 static_cast<CallRecord*
>(g_ptr_array_index(call_records, 0)),
true);
306 flush_channel_messages();
307 EXPECT_EQ(redispatched->len, 0u);
309 g_ptr_array_set_size(call_records, 0);
313 0, FALSE, kKeyCodeKeyA, GDK_KEY_a,
static_cast<GdkModifierType
>(0), 0);
315 flush_channel_messages();
316 EXPECT_EQ(redispatched->len, 0u);
317 EXPECT_EQ(call_records->len, 1u);
319 kFlutterKeyEventTypeUp, kPhysicalKeyA, kLogicalKeyA,
nullptr,
324 0,
TRUE, kKeyCodeKeyB, GDK_KEY_b,
static_cast<GdkModifierType
>(0), 0);
326 flush_channel_messages();
327 EXPECT_EQ(redispatched->len, 0u);
328 EXPECT_EQ(call_records->len, 2u);
330 kFlutterKeyEventTypeDown, kPhysicalKeyB, kLogicalKeyB,
"b",
335 static_cast<CallRecord*
>(g_ptr_array_index(call_records, 1)),
false);
336 EXPECT_EQ(redispatched->len, 1u);
341 static_cast<CallRecord*
>(g_ptr_array_index(call_records, 0)),
false);
342 flush_channel_messages();
343 EXPECT_EQ(redispatched->len, 2u);
349 g_ptr_array_set_size(call_records, 0);
352 EXPECT_EQ(redispatch_events_and_clear(manager, redispatched), 2);
353 flush_channel_messages();
354 EXPECT_EQ(call_records->len, 0u);
360 0, FALSE, kKeyCodeKeyA, GDK_KEY_a,
static_cast<GdkModifierType
>(0), 0);
362 flush_channel_messages();
363 EXPECT_EQ(redispatched->len, 0u);
364 EXPECT_EQ(call_records->len, 1u);
367 static_cast<CallRecord*
>(g_ptr_array_index(call_records, 0)),
true);
371 TEST(FlKeyboardManagerTest, SingleDelegateWithSyncResponds) {
372 ::testing::NiceMock<flutter::testing::MockKeymap> mock_keymap;
374 g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new();
375 fl_mock_binary_messenger_set_json_message_channel(
376 messenger,
"flutter/keyevent",
377 [](FlMockBinaryMessenger* messenger, GTask* task,
FlValue* message,
386 g_autoptr(FlMockViewDelegate)
view = fl_mock_view_delegate_new();
387 g_autoptr(FlEngine) engine =
388 FL_ENGINE(g_object_new(fl_engine_get_type(),
"binary-messenger",
389 FL_BINARY_MESSENGER(messenger),
nullptr));
390 g_autoptr(FlKeyboardManager) manager =
393 manager, [](
const GdkKeymapKey* key, gpointer
user_data) {
return 0u; },
397 g_autoptr(GPtrArray) call_records = g_ptr_array_new_with_free_func(
401 [](
const FlutterKeyEvent* event, FlutterKeyEventCallback callback,
402 void* callback_user_data, gpointer
user_data) {
403 GPtrArray* call_records =
static_cast<GPtrArray*
>(
user_data);
404 g_ptr_array_add(call_records,
406 callback(
true, callback_user_data);
409 g_autoptr(GPtrArray) redispatched =
410 g_ptr_array_new_with_free_func(g_object_unref);
413 [](FlKeyEvent* event, gpointer
user_data) {
414 GPtrArray* redispatched =
static_cast<GPtrArray*
>(
user_data);
415 g_ptr_array_add(redispatched, g_object_ref(event));
421 0,
TRUE, kKeyCodeKeyA, GDK_KEY_a,
static_cast<GdkModifierType
>(0), 0);
423 flush_channel_messages();
424 EXPECT_EQ(call_records->len, 1u);
426 kFlutterKeyEventTypeDown, kPhysicalKeyA, kLogicalKeyA,
"a",
428 EXPECT_EQ(redispatched->len, 0u);
429 g_ptr_array_set_size(call_records, 0);
432 g_ptr_array_set_size(redispatched, 0);
437 [](
const FlutterKeyEvent* event, FlutterKeyEventCallback callback,
438 void* callback_user_data, gpointer
user_data) {
439 GPtrArray* call_records =
static_cast<GPtrArray*
>(
user_data);
440 g_ptr_array_add(call_records,
442 callback(
false, callback_user_data);
446 0, FALSE, kKeyCodeKeyA, GDK_KEY_a,
static_cast<GdkModifierType
>(0), 0);
448 flush_channel_messages();
449 EXPECT_EQ(call_records->len, 1u);
451 kFlutterKeyEventTypeUp, kPhysicalKeyA, kLogicalKeyA,
nullptr,
453 EXPECT_EQ(redispatched->len, 1u);
454 g_ptr_array_set_size(call_records, 0);
458 EXPECT_EQ(redispatch_events_and_clear(manager, redispatched), 1);
459 EXPECT_EQ(call_records->len, 0u);
464 static void channel_respond(FlMockBinaryMessenger* messenger,
469 fl_mock_binary_messenger_json_message_channel_respond(messenger, task,
value);
472 TEST(FlKeyboardManagerTest, WithTwoAsyncDelegates) {
473 ::testing::NiceMock<flutter::testing::MockKeymap> mock_keymap;
475 g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new();
476 g_autoptr(GPtrArray) channel_calls =
477 g_ptr_array_new_with_free_func(g_object_unref);
478 fl_mock_binary_messenger_set_json_message_channel(
479 messenger,
"flutter/keyevent",
480 [](FlMockBinaryMessenger* messenger, GTask* task,
FlValue* message,
482 GPtrArray* call_records =
static_cast<GPtrArray*
>(
user_data);
483 g_ptr_array_add(call_records, g_object_ref(task));
485 return static_cast<FlValue*
>(
nullptr);
489 g_autoptr(FlMockViewDelegate)
view = fl_mock_view_delegate_new();
490 g_autoptr(FlEngine) engine =
491 FL_ENGINE(g_object_new(fl_engine_get_type(),
"binary-messenger",
492 FL_BINARY_MESSENGER(messenger),
nullptr));
493 g_autoptr(FlKeyboardManager) manager =
496 manager, [](
const GdkKeymapKey* key, gpointer
user_data) {
return 0u; },
499 g_autoptr(GPtrArray) embedder_call_records = g_ptr_array_new_with_free_func(
503 [](
const FlutterKeyEvent* event, FlutterKeyEventCallback callback,
504 void* callback_user_data, gpointer
user_data) {
505 GPtrArray* call_records =
static_cast<GPtrArray*
>(
user_data);
506 g_ptr_array_add(call_records,
509 embedder_call_records);
510 g_autoptr(GPtrArray) redispatched =
511 g_ptr_array_new_with_free_func(g_object_unref);
514 [](FlKeyEvent* event, gpointer
user_data) {
515 GPtrArray* redispatched =
static_cast<GPtrArray*
>(
user_data);
516 g_ptr_array_add(redispatched, g_object_ref(event));
523 0,
TRUE, kKeyCodeKeyA, GDK_KEY_a,
static_cast<GdkModifierType
>(0), 0);
526 EXPECT_EQ(redispatched->len, 0u);
527 EXPECT_EQ(embedder_call_records->len, 1u);
528 EXPECT_EQ(channel_calls->len, 1u);
531 static_cast<CallRecord*
>(g_ptr_array_index(embedder_call_records, 0)),
533 channel_respond(messenger,
534 static_cast<GTask*
>(g_ptr_array_index(channel_calls, 0)),
536 flush_channel_messages();
537 EXPECT_EQ(redispatched->len, 0u);
540 g_ptr_array_set_size(embedder_call_records, 0);
541 g_ptr_array_set_size(channel_calls, 0);
545 0, FALSE, kKeyCodeKeyA, GDK_KEY_a,
static_cast<GdkModifierType
>(0), 0);
548 EXPECT_EQ(redispatched->len, 0u);
549 EXPECT_EQ(embedder_call_records->len, 1u);
550 EXPECT_EQ(channel_calls->len, 1u);
553 static_cast<CallRecord*
>(g_ptr_array_index(embedder_call_records, 0)),
555 channel_respond(messenger,
556 static_cast<GTask*
>(g_ptr_array_index(channel_calls, 0)),
559 g_ptr_array_set_size(embedder_call_records, 0);
560 g_ptr_array_set_size(channel_calls, 0);
563 flush_channel_messages();
564 EXPECT_EQ(redispatched->len, 1u);
565 EXPECT_EQ(redispatch_events_and_clear(manager, redispatched), 1);
566 EXPECT_EQ(embedder_call_records->len, 0u);
567 EXPECT_EQ(channel_calls->len, 0u);
572 TEST(FlKeyboardManagerTest, TextInputHandlerReturnsFalse) {
573 ::testing::NiceMock<flutter::testing::MockKeymap> mock_keymap;
575 g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new();
576 fl_mock_binary_messenger_set_json_message_channel(
577 messenger,
"flutter/keyevent",
578 [](FlMockBinaryMessenger* messenger, GTask* task,
FlValue* message,
586 g_autoptr(FlEngine) engine =
587 FL_ENGINE(g_object_new(fl_engine_get_type(),
"binary-messenger",
588 FL_BINARY_MESSENGER(messenger),
nullptr));
589 g_autoptr(FlMockViewDelegate)
view = fl_mock_view_delegate_new();
590 g_autoptr(FlKeyboardManager) manager =
594 fl_mock_view_set_text_filter_result(
view, FALSE);
595 gboolean redispatched = FALSE;
598 [](FlKeyEvent* event, gpointer
user_data) {
599 gboolean* redispatched =
static_cast<gboolean*
>(
user_data);
600 *redispatched =
TRUE;
605 [](
const FlutterKeyEvent* event, FlutterKeyEventCallback callback,
606 void* callback_user_data,
607 gpointer
user_data) { callback(
false, callback_user_data); },
610 0,
TRUE, kKeyCodeKeyA, GDK_KEY_a,
static_cast<GdkModifierType
>(0), 0);
612 flush_channel_messages();
614 EXPECT_TRUE(redispatched);
617 TEST(FlKeyboardManagerTest, TextInputHandlerReturnsTrue) {
618 ::testing::NiceMock<flutter::testing::MockKeymap> mock_keymap;
620 g_autoptr(FlMockBinaryMessenger) messenger = fl_mock_binary_messenger_new();
621 fl_mock_binary_messenger_set_json_message_channel(
622 messenger,
"flutter/keyevent",
623 [](FlMockBinaryMessenger* messenger, GTask* task,
FlValue* message,
631 g_autoptr(FlEngine) engine =
632 FL_ENGINE(g_object_new(fl_engine_get_type(),
"binary-messenger",
633 FL_BINARY_MESSENGER(messenger),
nullptr));
634 g_autoptr(FlMockViewDelegate)
view = fl_mock_view_delegate_new();
635 g_autoptr(FlKeyboardManager) manager =
639 fl_mock_view_set_text_filter_result(
view,
TRUE);
640 gboolean redispatched = FALSE;
643 [](FlKeyEvent* event, gpointer
user_data) {
644 gboolean* redispatched =
static_cast<gboolean*
>(
user_data);
645 *redispatched =
TRUE;
650 [](
const FlutterKeyEvent* event, FlutterKeyEventCallback callback,
651 void* callback_user_data,
652 gpointer
user_data) { callback(
false, callback_user_data); },
655 0,
TRUE, kKeyCodeKeyA, GDK_KEY_a,
static_cast<GdkModifierType
>(0), 0);
657 flush_channel_messages();
659 EXPECT_FALSE(redispatched);
662 TEST(FlKeyboardManagerTest, CorrectLogicalKeyForLayouts) {
663 ::testing::NiceMock<flutter::testing::MockKeymap> mock_keymap;
667 g_autoptr(FlMockViewDelegate)
view = fl_mock_view_delegate_new();
668 g_autoptr(FlKeyboardManager) manager =
671 g_autoptr(GPtrArray) call_records = g_ptr_array_new_with_free_func(
675 [](
const FlutterKeyEvent* event, FlutterKeyEventCallback callback,
676 void* callback_user_data, gpointer
user_data) {
677 GPtrArray* call_records =
static_cast<GPtrArray*
>(
user_data);
678 g_ptr_array_add(call_records,
683 manager, [](
const GdkKeymapKey* key, gpointer
user_data) {
return 0u; },
686 auto sendTap = [&](guint8 keycode, guint keyval, guint8 group) {
688 0,
TRUE, keycode, keyval,
static_cast<GdkModifierType
>(0), group);
691 0, FALSE, keycode, keyval,
static_cast<GdkModifierType
>(0), group);
697 sendTap(kKeyCodeKeyA, GDK_KEY_a, 0);
700 sendTap(kKeyCodeKeyA, GDK_KEY_A, 0);
703 sendTap(kKeyCodeDigit1, GDK_KEY_1, 0);
706 sendTap(kKeyCodeDigit1, GDK_KEY_exclam, 0);
709 sendTap(kKeyCodeMinus, GDK_KEY_minus, 0);
712 sendTap(kKeyCodeMinus, GDK_KEY_underscore, 0);
720 [](
const GdkKeymapKey* key, gpointer
user_data) {
721 MockLayoutData* layout_data =
static_cast<MockLayoutData*
>(
user_data);
722 guint8 group =
static_cast<guint8
>(key->group);
723 EXPECT_LT(group, layout_data->size());
724 const MockGroupLayoutData* group_layout = (*layout_data)[group];
725 EXPECT_NE(group_layout,
nullptr);
726 EXPECT_TRUE(key->level == 0 || key->level == 1);
727 bool shift = key->level == 1;
728 return (*group_layout)[key->keycode * 2 + shift];
730 reinterpret_cast<gpointer
>(
const_cast<MockLayoutData*
>(&kLayoutFrench)));
732 sendTap(kKeyCodeKeyA, GDK_KEY_q, 3);
735 sendTap(kKeyCodeKeyA, GDK_KEY_Q, 3);
738 sendTap(kKeyCodeSemicolon, GDK_KEY_m, 3);
741 sendTap(kKeyCodeKeyM, GDK_KEY_comma, 3);
744 sendTap(kKeyCodeDigit1, GDK_KEY_ampersand, 3);
747 sendTap(kKeyCodeDigit1, GDK_KEY_1, 3);
750 sendTap(kKeyCodeMinus, GDK_KEY_parenright, 3);
753 sendTap(kKeyCodeMinus, GDK_KEY_degree, 3);
759 sendTap(kKeyCodeKeyA, GDK_KEY_a, 0);
762 sendTap(kKeyCodeDigit1, GDK_KEY_1, 0);
768 [](
const GdkKeymapKey* key, gpointer
user_data) {
769 MockLayoutData* layout_data =
static_cast<MockLayoutData*
>(
user_data);
770 guint8 group =
static_cast<guint8
>(key->group);
771 EXPECT_LT(group, layout_data->size());
772 const MockGroupLayoutData* group_layout = (*layout_data)[group];
773 EXPECT_NE(group_layout,
nullptr);
774 EXPECT_TRUE(key->level == 0 || key->level == 1);
775 bool shift = key->level == 1;
776 return (*group_layout)[key->keycode * 2 + shift];
778 reinterpret_cast<gpointer
>(
const_cast<MockLayoutData*
>(&kLayoutRussian)));
780 sendTap(kKeyCodeKeyA, GDK_KEY_Cyrillic_ef, 2);
783 sendTap(kKeyCodeDigit1, GDK_KEY_1, 2);
786 sendTap(kKeyCodeKeyLeftBracket, GDK_KEY_Cyrillic_ha, 2);
790 sendTap(kKeyCodeKeyA, GDK_KEY_a, 0);
793 sendTap(kKeyCodeKeyLeftBracket, GDK_KEY_bracketleft, 0);
797 TEST(FlKeyboardManagerTest, SynthesizeModifiersIfNeeded) {
798 ::testing::NiceMock<flutter::testing::MockKeymap> mock_keymap;
802 g_autoptr(FlMockViewDelegate)
view = fl_mock_view_delegate_new();
803 g_autoptr(FlKeyboardManager) manager =
806 g_autoptr(GPtrArray) call_records = g_ptr_array_new_with_free_func(
810 [](
const FlutterKeyEvent* event, FlutterKeyEventCallback callback,
811 void* callback_user_data, gpointer
user_data) {
812 GPtrArray* call_records =
static_cast<GPtrArray*
>(
user_data);
813 g_ptr_array_add(call_records,
818 auto verifyModifierIsSynthesized = [&](GdkModifierType mask,
819 uint64_t physical, uint64_t logical) {
823 EXPECT_EQ(call_records->len, 1u);
825 static_cast<CallRecord*
>(g_ptr_array_index(call_records, 0)),
826 kFlutterKeyEventTypeDown, physical, logical, NULL,
true);
830 EXPECT_EQ(call_records->len, 2u);
832 static_cast<CallRecord*
>(g_ptr_array_index(call_records, 1)),
833 kFlutterKeyEventTypeUp, physical, logical, NULL,
true);
834 g_ptr_array_set_size(call_records, 0);
840 EXPECT_EQ(call_records->len, 0u);
841 g_ptr_array_set_size(call_records, 0);
844 verifyModifierIsSynthesized(GDK_CONTROL_MASK, kPhysicalControlLeft,
845 kLogicalControlLeft);
846 verifyModifierIsSynthesized(GDK_META_MASK, kPhysicalMetaLeft,
848 verifyModifierIsSynthesized(GDK_MOD1_MASK, kPhysicalAltLeft, kLogicalAltLeft);
849 verifyModifierIsSynthesized(GDK_SHIFT_MASK, kPhysicalShiftLeft,
853 TEST(FlKeyboardManagerTest, GetPressedState) {
854 ::testing::NiceMock<flutter::testing::MockKeymap> mock_keymap;
858 g_autoptr(FlMockViewDelegate)
view = fl_mock_view_delegate_new();
859 g_autoptr(FlKeyboardManager) manager =
864 0,
TRUE, kKeyCodeKeyA, GDK_KEY_a,
static_cast<GdkModifierType
>(0), 0);
868 EXPECT_EQ(g_hash_table_size(pressedState), 1u);
870 gpointer physical_key =
877 const MockGroupLayoutData kLayoutRussian0{
879 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
880 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
881 0x0000, 0xffff, 0xffff, 0x0031, 0x0031, 0x0021, 0x0032, 0x0040,
882 0x0033, 0x0023, 0x0034, 0x0024, 0x0035, 0x0025, 0x0036, 0x005e,
883 0x0037, 0x0026, 0x0038, 0x002a, 0x0039, 0x0028, 0x0030, 0x0029,
884 0x002d, 0x005f, 0x003d, 0x002b, 0xffff, 0xffff, 0xffff, 0xffff,
885 0x0071, 0x0051, 0x0077, 0x0057, 0x0065, 0x0045, 0x0072, 0x0052,
886 0x0074, 0x0054, 0x0079, 0x0059, 0x0075, 0x0055, 0x0069, 0x0049,
887 0x006f, 0x004f, 0x0070, 0x0050, 0x005b, 0x007b, 0x005d, 0x007d,
888 0xffff, 0xffff, 0xffff, 0x0061, 0x0061, 0x0041, 0x0073, 0x0053,
889 0x0064, 0x0044, 0x0066, 0x0046, 0x0067, 0x0047, 0x0068, 0x0048,
890 0x006a, 0x004a, 0x006b, 0x004b, 0x006c, 0x004c, 0x003b, 0x003a,
891 0x0027, 0x0022, 0x0060, 0x007e, 0xffff, 0x005c, 0x005c, 0x007c,
892 0x007a, 0x005a, 0x0078, 0x0058, 0x0063, 0x0043, 0x0076, 0x0056,
893 0x0062, 0x0042, 0x006e, 0x004e, 0x006d, 0x004d, 0x002c, 0x003c,
894 0x002e, 0x003e, 0x002f, 0x003f, 0xffff, 0xffff, 0xffff, 0xffff,
895 0xffff, 0xffff, 0x0020, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
896 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
897 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
898 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
899 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
900 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
901 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
902 0xffff, 0xffff, 0x0000, 0xffff, 0x003c, 0x003e, 0xffff, 0xffff,
903 0xffff, 0xffff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
904 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0xffff,
905 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
906 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
907 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
908 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
909 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
910 0xffff, 0xffff, 0xffff, 0x00b1, 0x00b1, 0xffff, 0xffff, 0xffff,
913 const MockGroupLayoutData kLayoutRussian2{{
915 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
916 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
917 0xffff, 0x0031, 0x0021, 0x0000, 0x0031, 0x0021, 0x0032, 0x0022,
918 0x0033, 0x06b0, 0x0034, 0x003b, 0x0035, 0x0025, 0x0036, 0x003a,
919 0x0037, 0x003f, 0x0038, 0x002a, 0x0039, 0x0028, 0x0030, 0x0029,
920 0x002d, 0x005f, 0x003d, 0x002b, 0x0071, 0x0051, 0x0000, 0x0000,
921 0x06ca, 0x06ea, 0x06c3, 0x06e3, 0x06d5, 0x06f5, 0x06cb, 0x06eb,
922 0x06c5, 0x06e5, 0x06ce, 0x06ee, 0x06c7, 0x06e7, 0x06db, 0x06fb,
923 0x06dd, 0x06fd, 0x06da, 0x06fa, 0x06c8, 0x06e8, 0x06df, 0x06ff,
924 0x0061, 0x0041, 0x0041, 0x0000, 0x06c6, 0x06e6, 0x06d9, 0x06f9,
925 0x06d7, 0x06f7, 0x06c1, 0x06e1, 0x06d0, 0x06f0, 0x06d2, 0x06f2,
926 0x06cf, 0x06ef, 0x06cc, 0x06ec, 0x06c4, 0x06e4, 0x06d6, 0x06f6,
927 0x06dc, 0x06fc, 0x06a3, 0x06b3, 0x007c, 0x0000, 0x005c, 0x002f,
928 0x06d1, 0x06f1, 0x06de, 0x06fe, 0x06d3, 0x06f3, 0x06cd, 0x06ed,
929 0x06c9, 0x06e9, 0x06d4, 0x06f4, 0x06d8, 0x06f8, 0x06c2, 0x06e2,
930 0x06c0, 0x06e0, 0x002e, 0x002c, 0xffff, 0xffff, 0xffff, 0xffff,
931 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
932 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
933 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
934 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
935 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
936 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
937 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
938 0xffff, 0xffff, 0x003c, 0x003e, 0x002f, 0x007c, 0xffff, 0xffff,
939 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
940 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
941 0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0xffff, 0xffff, 0x0000,
942 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
943 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
944 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
945 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x00b1,
946 0x00b1, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
949 const MockGroupLayoutData kLayoutFrench0 = {
951 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
952 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
953 0x0000, 0xffff, 0xffff, 0x0031, 0x0031, 0x0021, 0x0032, 0x0040,
954 0x0033, 0x0023, 0x0034, 0x0024, 0x0035, 0x0025, 0x0036, 0x005e,
955 0x0037, 0x0026, 0x0038, 0x002a, 0x0039, 0x0028, 0x0030, 0x0029,
956 0x002d, 0x005f, 0x003d, 0x002b, 0xffff, 0xffff, 0xffff, 0xffff,
957 0x0071, 0x0051, 0x0077, 0x0057, 0x0065, 0x0045, 0x0072, 0x0052,
958 0x0074, 0x0054, 0x0079, 0x0059, 0x0075, 0x0055, 0x0069, 0x0049,
959 0x006f, 0x004f, 0x0070, 0x0050, 0x005b, 0x007b, 0x005d, 0x007d,
960 0xffff, 0xffff, 0xffff, 0x0061, 0x0061, 0x0041, 0x0073, 0x0053,
961 0x0064, 0x0044, 0x0066, 0x0046, 0x0067, 0x0047, 0x0068, 0x0048,
962 0x006a, 0x004a, 0x006b, 0x004b, 0x006c, 0x004c, 0x003b, 0x003a,
963 0x0027, 0x0022, 0x0060, 0x007e, 0xffff, 0x005c, 0x005c, 0x007c,
964 0x007a, 0x005a, 0x0078, 0x0058, 0x0063, 0x0043, 0x0076, 0x0056,
965 0x0062, 0x0042, 0x006e, 0x004e, 0x006d, 0x004d, 0x002c, 0x003c,
966 0x002e, 0x003e, 0x002f, 0x003f, 0xffff, 0xffff, 0xffff, 0xffff,
967 0xffff, 0xffff, 0x0020, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
968 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
969 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
970 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
971 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
972 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
973 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
974 0xffff, 0xffff, 0x0000, 0xffff, 0x003c, 0x003e, 0xffff, 0xffff,
975 0xffff, 0xffff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
976 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0xffff,
977 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
978 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
979 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
980 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
981 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
982 0xffff, 0xffff, 0xffff, 0x00b1, 0x00b1, 0xffff, 0xffff, 0xffff,
985 const MockGroupLayoutData kLayoutFrench3 = {
987 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
988 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff,
989 0x0000, 0xffff, 0x0000, 0x0000, 0x0026, 0x0031, 0x00e9, 0x0032,
990 0x0022, 0x0033, 0x0027, 0x0034, 0x0028, 0x0035, 0x002d, 0x0036,
991 0x00e8, 0x0037, 0x005f, 0x0038, 0x00e7, 0x0039, 0x00e0, 0x0030,
992 0x0029, 0x00b0, 0x003d, 0x002b, 0x0000, 0x0000, 0x0061, 0x0041,
993 0x0061, 0x0041, 0x007a, 0x005a, 0x0065, 0x0045, 0x0072, 0x0052,
994 0x0074, 0x0054, 0x0079, 0x0059, 0x0075, 0x0055, 0x0069, 0x0049,
995 0x006f, 0x004f, 0x0070, 0x0050, 0xffff, 0xffff, 0x0024, 0x00a3,
996 0x0041, 0x0000, 0x0000, 0x0000, 0x0071, 0x0051, 0x0073, 0x0053,
997 0x0064, 0x0044, 0x0066, 0x0046, 0x0067, 0x0047, 0x0068, 0x0048,
998 0x006a, 0x004a, 0x006b, 0x004b, 0x006c, 0x004c, 0x006d, 0x004d,
999 0x00f9, 0x0025, 0x00b2, 0x007e, 0x0000, 0x0000, 0x002a, 0x00b5,
1000 0x0077, 0x0057, 0x0078, 0x0058, 0x0063, 0x0043, 0x0076, 0x0056,
1001 0x0062, 0x0042, 0x006e, 0x004e, 0x002c, 0x003f, 0x003b, 0x002e,
1002 0x003a, 0x002f, 0x0021, 0x00a7, 0xffff, 0xffff, 0xffff, 0xffff,
1003 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
1004 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
1005 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
1006 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
1007 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
1008 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
1009 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
1010 0xffff, 0x003c, 0x0000, 0xffff, 0x003c, 0x003e, 0xffff, 0xffff,
1011 0xffff, 0xffff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
1012 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0xffff,
1013 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
1014 0xffff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
1015 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
1016 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
1017 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0x00b1, 0x00b1, 0xffff,
1018 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
1021 const MockLayoutData kLayoutRussian{&kLayoutRussian0,
nullptr,
1023 const MockLayoutData kLayoutFrench{&kLayoutFrench0,
nullptr,
nullptr,