Flutter Linux Embedder
fl_keyboard_manager_test.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
6 
7 #include <cstring>
8 #include <vector>
9 
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"
15 
16 #include "gtest/gtest.h"
17 
18 // Define compound `expect` in macros. If they were defined in functions, the
19 // stacktrace wouldn't print where the function is called in the unit tests.
20 
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));
27 
28 #define VERIFY_DOWN(OUT_LOGICAL, OUT_CHAR) \
29  EXPECT_EQ(static_cast<CallRecord*>(g_ptr_array_index(call_records, 0)) \
30  ->event_type, \
31  kFlutterKeyEventTypeDown); \
32  EXPECT_EQ(static_cast<CallRecord*>(g_ptr_array_index(call_records, 0)) \
33  ->event_logical, \
34  (OUT_LOGICAL)); \
35  EXPECT_STREQ(static_cast<CallRecord*>(g_ptr_array_index(call_records, 0)) \
36  ->event_character, \
37  (OUT_CHAR)); \
38  EXPECT_EQ(static_cast<CallRecord*>(g_ptr_array_index(call_records, 0)) \
39  ->event_synthesized, \
40  false); \
41  g_ptr_array_set_size(call_records, 0)
42 
43 typedef struct {
44  FlutterKeyEventType event_type;
45  uint64_t event_physical;
46  uint64_t event_logical;
49  FlutterKeyEventCallback callback;
51 } CallRecord;
52 
53 static CallRecord* call_record_new(const FlutterKeyEvent* event,
54  FlutterKeyEventCallback callback,
55  void* callback_user_data) {
56  CallRecord* record = g_new0(CallRecord, 1);
57  record->event_type = event->type;
58  record->event_physical = event->physical;
59  record->event_logical = event->logical;
60  record->event_character = g_strdup(event->character);
61  record->event_synthesized = event->synthesized;
62  record->callback = callback;
63  record->callback_user_data = callback_user_data;
64  return record;
65 }
66 
67 static void call_record_free(CallRecord* record) {
68  g_free(record->event_character);
69  g_free(record);
70 }
71 
72 static void call_record_respond(CallRecord* record, bool handled) {
73  if (record->callback != nullptr) {
74  record->callback(handled, record->callback_user_data);
75  }
76 }
77 
78 namespace {
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;
94 
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;
101 
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;
109 
110 // All key clues for a keyboard layout.
111 //
112 // The index is (keyCode * 2 + hasShift), where each value is the character for
113 // this key (GTK only supports UTF-16.) Since the maximum keycode of interest
114 // is 128, it has a total of 256 entries..
115 typedef std::array<uint32_t, 256> MockGroupLayoutData;
116 typedef std::vector<const MockGroupLayoutData*> MockLayoutData;
117 
118 extern const MockLayoutData kLayoutRussian;
119 extern const MockLayoutData kLayoutFrench;
120 
121 G_BEGIN_DECLS
122 
123 G_DECLARE_FINAL_TYPE(FlMockViewDelegate,
124  fl_mock_view_delegate,
125  FL,
126  MOCK_VIEW_DELEGATE,
127  GObject);
128 
129 G_END_DECLS
130 
131 struct _FlMockViewDelegate {
132  GObject parent_instance;
133  bool text_filter_result;
134 };
135 
136 static void fl_mock_view_keyboard_delegate_iface_init(
137  FlKeyboardViewDelegateInterface* iface);
138 
140  FlMockViewDelegate,
141  fl_mock_view_delegate,
142  G_TYPE_OBJECT,
143  G_IMPLEMENT_INTERFACE(fl_keyboard_view_delegate_get_type(),
144  fl_mock_view_keyboard_delegate_iface_init))
145 
146 static void fl_mock_view_delegate_init(FlMockViewDelegate* self) {}
147 
148 static void fl_mock_view_delegate_class_init(FlMockViewDelegateClass* klass) {}
149 
150 static gboolean fl_mock_view_keyboard_text_filter_key_press(
151  FlKeyboardViewDelegate* view_delegate,
152  FlKeyEvent* event) {
153  FlMockViewDelegate* self = FL_MOCK_VIEW_DELEGATE(view_delegate);
154  return self->text_filter_result;
155 }
156 
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;
160 }
161 
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));
165 
166  // Added to stop compiler complaining about an unused function.
167  FL_IS_MOCK_VIEW_DELEGATE(self);
168 
169  return self;
170 }
171 
172 static void fl_mock_view_set_text_filter_result(FlMockViewDelegate* self,
173  bool result) {
174  self->text_filter_result = result;
175 }
176 
177 // Block until all GdkMainLoop messages are processed, which is basically used
178 // only for channel messages.
179 static void flush_channel_messages() {
180  GMainLoop* loop = g_main_loop_new(nullptr, 0);
181  g_idle_add(
182  [](gpointer data) {
183  g_autoptr(GMainLoop) loop = reinterpret_cast<GMainLoop*>(data);
184  g_main_loop_quit(loop);
185  return FALSE;
186  },
187  loop);
188  g_main_loop_run(loop);
189 }
190 
191 // Dispatch each of the given events, expect their results to be false
192 // (unhandled), and clear the event array.
193 //
194 // Returns the number of events redispatched. If any result is unexpected
195 // (handled), return a minus number `-x` instead, where `x` is the index of
196 // the first unexpected redispatch.
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));
201  EXPECT_FALSE(fl_keyboard_manager_handle_event(manager, event));
202  }
203  g_ptr_array_set_size(events, 0);
204  return event_count;
205 }
206 
207 // Make sure that the keyboard can be disposed without crashes when there are
208 // unresolved pending events.
209 TEST(FlKeyboardManagerTest, DisposeWithUnresolvedPends) {
210  ::testing::NiceMock<flutter::testing::MockKeymap> mock_keymap;
211 
212  g_autoptr(FlDartProject) project = fl_dart_project_new();
213  g_autoptr(FlEngine) engine = fl_engine_new(project);
214  g_autoptr(FlMockViewDelegate) view = fl_mock_view_delegate_new();
215  g_autoptr(FlKeyboardManager) manager =
216  fl_keyboard_manager_new(engine, FL_KEYBOARD_VIEW_DELEGATE(view));
217 
218  g_autoptr(GError) error = nullptr;
219  EXPECT_TRUE(fl_engine_start(engine, &error));
220  EXPECT_EQ(error, nullptr);
221 
222  // Don't handle first event.
224  manager,
225  [](const FlutterKeyEvent* event, FlutterKeyEventCallback callback,
226  void* callback_user_data, gpointer user_data) {},
227  nullptr);
228  g_autoptr(FlKeyEvent) event1 = fl_key_event_new(
229  0, TRUE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0);
230  fl_keyboard_manager_handle_event(manager, event1);
231 
232  // Handle second event.
234  manager,
235  [](const FlutterKeyEvent* event, FlutterKeyEventCallback callback,
236  void* callback_user_data,
237  gpointer user_data) { callback(true, callback_user_data); },
238  nullptr);
239  g_autoptr(FlKeyEvent) event2 = fl_key_event_new(
240  0, FALSE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0);
241  fl_keyboard_manager_handle_event(manager, event2);
242 
243  // Passes if the cleanup does not crash.
244 }
245 
246 TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) {
247  ::testing::NiceMock<flutter::testing::MockKeymap> mock_keymap;
248 
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,
253  gpointer user_data) {
254  g_autoptr(FlValue) return_value = fl_value_new_map();
255  fl_value_set_string_take(return_value, "handled",
256  fl_value_new_bool(FALSE));
257  return fl_value_ref(return_value);
258  },
259  nullptr);
260 
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 =
266  fl_keyboard_manager_new(engine, FL_KEYBOARD_VIEW_DELEGATE(view));
268  manager, [](const GdkKeymapKey* key, gpointer user_data) { return 0u; },
269  nullptr);
270 
271  /// Test 1: One event that is handled by the framework
272  g_autoptr(GPtrArray) call_records = g_ptr_array_new_with_free_func(
273  reinterpret_cast<GDestroyNotify>(call_record_free));
275  manager,
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,
280  call_record_new(event, callback, callback_user_data));
281  },
282  call_records);
283  g_autoptr(GPtrArray) redispatched =
284  g_ptr_array_new_with_free_func(g_object_unref);
286  manager,
287  [](FlKeyEvent* event, gpointer user_data) {
288  GPtrArray* redispatched = static_cast<GPtrArray*>(user_data);
289  g_ptr_array_add(redispatched, g_object_ref(event));
290  },
291  redispatched);
292 
293  // Dispatch a key event
294  g_autoptr(FlKeyEvent) event1 = fl_key_event_new(
295  0, TRUE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0);
296  EXPECT_TRUE(fl_keyboard_manager_handle_event(manager, event1));
297  flush_channel_messages();
298  EXPECT_EQ(redispatched->len, 0u);
299  EXPECT_EQ(call_records->len, 1u);
300  EXPECT_KEY_EVENT(static_cast<CallRecord*>(g_ptr_array_index(call_records, 0)),
301  kFlutterKeyEventTypeDown, kPhysicalKeyA, kLogicalKeyA, "a",
302  false);
303 
305  static_cast<CallRecord*>(g_ptr_array_index(call_records, 0)), true);
306  flush_channel_messages();
307  EXPECT_EQ(redispatched->len, 0u);
308  EXPECT_TRUE(fl_keyboard_manager_is_state_clear(manager));
309  g_ptr_array_set_size(call_records, 0);
310 
311  /// Test 2: Two events that are unhandled by the framework
312  g_autoptr(FlKeyEvent) event2 = fl_key_event_new(
313  0, FALSE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0);
314  EXPECT_TRUE(fl_keyboard_manager_handle_event(manager, event2));
315  flush_channel_messages();
316  EXPECT_EQ(redispatched->len, 0u);
317  EXPECT_EQ(call_records->len, 1u);
318  EXPECT_KEY_EVENT(static_cast<CallRecord*>(g_ptr_array_index(call_records, 0)),
319  kFlutterKeyEventTypeUp, kPhysicalKeyA, kLogicalKeyA, nullptr,
320  false);
321 
322  // Dispatch another key event
323  g_autoptr(FlKeyEvent) event3 = fl_key_event_new(
324  0, TRUE, kKeyCodeKeyB, GDK_KEY_b, static_cast<GdkModifierType>(0), 0);
325  EXPECT_TRUE(fl_keyboard_manager_handle_event(manager, event3));
326  flush_channel_messages();
327  EXPECT_EQ(redispatched->len, 0u);
328  EXPECT_EQ(call_records->len, 2u);
329  EXPECT_KEY_EVENT(static_cast<CallRecord*>(g_ptr_array_index(call_records, 1)),
330  kFlutterKeyEventTypeDown, kPhysicalKeyB, kLogicalKeyB, "b",
331  false);
332 
333  // Resolve the second event first to test out-of-order response
335  static_cast<CallRecord*>(g_ptr_array_index(call_records, 1)), false);
336  EXPECT_EQ(redispatched->len, 1u);
337  EXPECT_EQ(
338  fl_key_event_get_keyval(FL_KEY_EVENT(g_ptr_array_index(redispatched, 0))),
339  0x62u);
341  static_cast<CallRecord*>(g_ptr_array_index(call_records, 0)), false);
342  flush_channel_messages();
343  EXPECT_EQ(redispatched->len, 2u);
344  EXPECT_EQ(
345  fl_key_event_get_keyval(FL_KEY_EVENT(g_ptr_array_index(redispatched, 1))),
346  0x61u);
347 
348  EXPECT_FALSE(fl_keyboard_manager_is_state_clear(manager));
349  g_ptr_array_set_size(call_records, 0);
350 
351  // Resolve redispatches
352  EXPECT_EQ(redispatch_events_and_clear(manager, redispatched), 2);
353  flush_channel_messages();
354  EXPECT_EQ(call_records->len, 0u);
355  EXPECT_TRUE(fl_keyboard_manager_is_state_clear(manager));
356 
357  /// Test 3: Dispatch the same event again to ensure that prevention from
358  /// redispatching only works once.
359  g_autoptr(FlKeyEvent) event4 = fl_key_event_new(
360  0, FALSE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0);
361  EXPECT_TRUE(fl_keyboard_manager_handle_event(manager, event4));
362  flush_channel_messages();
363  EXPECT_EQ(redispatched->len, 0u);
364  EXPECT_EQ(call_records->len, 1u);
365 
367  static_cast<CallRecord*>(g_ptr_array_index(call_records, 0)), true);
368  EXPECT_TRUE(fl_keyboard_manager_is_state_clear(manager));
369 }
370 
371 TEST(FlKeyboardManagerTest, SingleDelegateWithSyncResponds) {
372  ::testing::NiceMock<flutter::testing::MockKeymap> mock_keymap;
373 
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,
378  gpointer user_data) {
379  g_autoptr(FlValue) return_value = fl_value_new_map();
380  fl_value_set_string_take(return_value, "handled",
381  fl_value_new_bool(FALSE));
382  return fl_value_ref(return_value);
383  },
384  nullptr);
385 
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 =
391  fl_keyboard_manager_new(engine, FL_KEYBOARD_VIEW_DELEGATE(view));
393  manager, [](const GdkKeymapKey* key, gpointer user_data) { return 0u; },
394  nullptr);
395 
396  /// Test 1: One event that is handled by the framework
397  g_autoptr(GPtrArray) call_records = g_ptr_array_new_with_free_func(
398  reinterpret_cast<GDestroyNotify>(call_record_free));
400  manager,
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,
405  call_record_new(event, callback, callback_user_data));
406  callback(true, callback_user_data);
407  },
408  call_records);
409  g_autoptr(GPtrArray) redispatched =
410  g_ptr_array_new_with_free_func(g_object_unref);
412  manager,
413  [](FlKeyEvent* event, gpointer user_data) {
414  GPtrArray* redispatched = static_cast<GPtrArray*>(user_data);
415  g_ptr_array_add(redispatched, g_object_ref(event));
416  },
417  redispatched);
418 
419  // Dispatch a key event
420  g_autoptr(FlKeyEvent) event1 = fl_key_event_new(
421  0, TRUE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0);
422  EXPECT_TRUE(fl_keyboard_manager_handle_event(manager, event1));
423  flush_channel_messages();
424  EXPECT_EQ(call_records->len, 1u);
425  EXPECT_KEY_EVENT(static_cast<CallRecord*>(g_ptr_array_index(call_records, 0)),
426  kFlutterKeyEventTypeDown, kPhysicalKeyA, kLogicalKeyA, "a",
427  false);
428  EXPECT_EQ(redispatched->len, 0u);
429  g_ptr_array_set_size(call_records, 0);
430 
431  EXPECT_TRUE(fl_keyboard_manager_is_state_clear(manager));
432  g_ptr_array_set_size(redispatched, 0);
433 
434  /// Test 2: An event unhandled by the framework
436  manager,
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,
441  call_record_new(event, callback, callback_user_data));
442  callback(false, callback_user_data);
443  },
444  call_records);
445  g_autoptr(FlKeyEvent) event2 = fl_key_event_new(
446  0, FALSE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0);
447  EXPECT_TRUE(fl_keyboard_manager_handle_event(manager, event2));
448  flush_channel_messages();
449  EXPECT_EQ(call_records->len, 1u);
450  EXPECT_KEY_EVENT(static_cast<CallRecord*>(g_ptr_array_index(call_records, 0)),
451  kFlutterKeyEventTypeUp, kPhysicalKeyA, kLogicalKeyA, nullptr,
452  false);
453  EXPECT_EQ(redispatched->len, 1u);
454  g_ptr_array_set_size(call_records, 0);
455 
456  EXPECT_FALSE(fl_keyboard_manager_is_state_clear(manager));
457 
458  EXPECT_EQ(redispatch_events_and_clear(manager, redispatched), 1);
459  EXPECT_EQ(call_records->len, 0u);
460 
461  EXPECT_TRUE(fl_keyboard_manager_is_state_clear(manager));
462 }
463 
464 static void channel_respond(FlMockBinaryMessenger* messenger,
465  GTask* task,
466  gboolean handled) {
467  g_autoptr(FlValue) value = fl_value_new_map();
468  fl_value_set_string_take(value, "handled", fl_value_new_bool(handled));
469  fl_mock_binary_messenger_json_message_channel_respond(messenger, task, value);
470 }
471 
472 TEST(FlKeyboardManagerTest, WithTwoAsyncDelegates) {
473  ::testing::NiceMock<flutter::testing::MockKeymap> mock_keymap;
474 
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,
481  gpointer user_data) {
482  GPtrArray* call_records = static_cast<GPtrArray*>(user_data);
483  g_ptr_array_add(call_records, g_object_ref(task));
484  // Will respond async
485  return static_cast<FlValue*>(nullptr);
486  },
487  channel_calls);
488 
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 =
494  fl_keyboard_manager_new(engine, FL_KEYBOARD_VIEW_DELEGATE(view));
496  manager, [](const GdkKeymapKey* key, gpointer user_data) { return 0u; },
497  nullptr);
498 
499  g_autoptr(GPtrArray) embedder_call_records = g_ptr_array_new_with_free_func(
500  reinterpret_cast<GDestroyNotify>(call_record_free));
502  manager,
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,
507  call_record_new(event, callback, callback_user_data));
508  },
509  embedder_call_records);
510  g_autoptr(GPtrArray) redispatched =
511  g_ptr_array_new_with_free_func(g_object_unref);
513  manager,
514  [](FlKeyEvent* event, gpointer user_data) {
515  GPtrArray* redispatched = static_cast<GPtrArray*>(user_data);
516  g_ptr_array_add(redispatched, g_object_ref(event));
517  },
518  redispatched);
519 
520  /// Test 1: One delegate responds true, the other false
521 
522  g_autoptr(FlKeyEvent) event1 = fl_key_event_new(
523  0, TRUE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0);
524  EXPECT_TRUE(fl_keyboard_manager_handle_event(manager, event1));
525 
526  EXPECT_EQ(redispatched->len, 0u);
527  EXPECT_EQ(embedder_call_records->len, 1u);
528  EXPECT_EQ(channel_calls->len, 1u);
529 
531  static_cast<CallRecord*>(g_ptr_array_index(embedder_call_records, 0)),
532  true);
533  channel_respond(messenger,
534  static_cast<GTask*>(g_ptr_array_index(channel_calls, 0)),
535  FALSE);
536  flush_channel_messages();
537  EXPECT_EQ(redispatched->len, 0u);
538 
539  EXPECT_TRUE(fl_keyboard_manager_is_state_clear(manager));
540  g_ptr_array_set_size(embedder_call_records, 0);
541  g_ptr_array_set_size(channel_calls, 0);
542 
543  /// Test 2: All delegates respond false
544  g_autoptr(FlKeyEvent) event2 = fl_key_event_new(
545  0, FALSE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0);
546  EXPECT_TRUE(fl_keyboard_manager_handle_event(manager, event2));
547 
548  EXPECT_EQ(redispatched->len, 0u);
549  EXPECT_EQ(embedder_call_records->len, 1u);
550  EXPECT_EQ(channel_calls->len, 1u);
551 
553  static_cast<CallRecord*>(g_ptr_array_index(embedder_call_records, 0)),
554  false);
555  channel_respond(messenger,
556  static_cast<GTask*>(g_ptr_array_index(channel_calls, 0)),
557  FALSE);
558 
559  g_ptr_array_set_size(embedder_call_records, 0);
560  g_ptr_array_set_size(channel_calls, 0);
561 
562  // Resolve redispatch
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);
568 
569  EXPECT_TRUE(fl_keyboard_manager_is_state_clear(manager));
570 }
571 
572 TEST(FlKeyboardManagerTest, TextInputHandlerReturnsFalse) {
573  ::testing::NiceMock<flutter::testing::MockKeymap> mock_keymap;
574 
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,
579  gpointer user_data) {
580  g_autoptr(FlValue) return_value = fl_value_new_map();
581  fl_value_set_string_take(return_value, "handled",
582  fl_value_new_bool(FALSE));
583  return fl_value_ref(return_value);
584  },
585  nullptr);
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 =
591  fl_keyboard_manager_new(engine, FL_KEYBOARD_VIEW_DELEGATE(view));
592 
593  // Dispatch a key event.
594  fl_mock_view_set_text_filter_result(view, FALSE);
595  gboolean redispatched = FALSE;
597  manager,
598  [](FlKeyEvent* event, gpointer user_data) {
599  gboolean* redispatched = static_cast<gboolean*>(user_data);
600  *redispatched = TRUE;
601  },
602  &redispatched);
604  manager,
605  [](const FlutterKeyEvent* event, FlutterKeyEventCallback callback,
606  void* callback_user_data,
607  gpointer user_data) { callback(false, callback_user_data); },
608  nullptr);
609  g_autoptr(FlKeyEvent) event = fl_key_event_new(
610  0, TRUE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0);
611  EXPECT_TRUE(fl_keyboard_manager_handle_event(manager, event));
612  flush_channel_messages();
613  // The event was redispatched because no one handles it.
614  EXPECT_TRUE(redispatched);
615 }
616 
617 TEST(FlKeyboardManagerTest, TextInputHandlerReturnsTrue) {
618  ::testing::NiceMock<flutter::testing::MockKeymap> mock_keymap;
619 
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,
624  gpointer user_data) {
625  g_autoptr(FlValue) return_value = fl_value_new_map();
626  fl_value_set_string_take(return_value, "handled",
627  fl_value_new_bool(FALSE));
628  return fl_value_ref(return_value);
629  },
630  nullptr);
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 =
636  fl_keyboard_manager_new(engine, FL_KEYBOARD_VIEW_DELEGATE(view));
637 
638  // Dispatch a key event.
639  fl_mock_view_set_text_filter_result(view, TRUE);
640  gboolean redispatched = FALSE;
642  manager,
643  [](FlKeyEvent* event, gpointer user_data) {
644  gboolean* redispatched = static_cast<gboolean*>(user_data);
645  *redispatched = TRUE;
646  },
647  &redispatched);
649  manager,
650  [](const FlutterKeyEvent* event, FlutterKeyEventCallback callback,
651  void* callback_user_data,
652  gpointer user_data) { callback(false, callback_user_data); },
653  nullptr);
654  g_autoptr(FlKeyEvent) event = fl_key_event_new(
655  0, TRUE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0);
656  EXPECT_TRUE(fl_keyboard_manager_handle_event(manager, event));
657  flush_channel_messages();
658  // The event was not redispatched because handler handles it.
659  EXPECT_FALSE(redispatched);
660 }
661 
662 TEST(FlKeyboardManagerTest, CorrectLogicalKeyForLayouts) {
663  ::testing::NiceMock<flutter::testing::MockKeymap> mock_keymap;
664 
665  g_autoptr(FlDartProject) project = fl_dart_project_new();
666  g_autoptr(FlEngine) engine = fl_engine_new(project);
667  g_autoptr(FlMockViewDelegate) view = fl_mock_view_delegate_new();
668  g_autoptr(FlKeyboardManager) manager =
669  fl_keyboard_manager_new(engine, FL_KEYBOARD_VIEW_DELEGATE(view));
670 
671  g_autoptr(GPtrArray) call_records = g_ptr_array_new_with_free_func(
672  reinterpret_cast<GDestroyNotify>(call_record_free));
674  manager,
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,
679  call_record_new(event, callback, callback_user_data));
680  },
681  call_records);
683  manager, [](const GdkKeymapKey* key, gpointer user_data) { return 0u; },
684  nullptr);
685 
686  auto sendTap = [&](guint8 keycode, guint keyval, guint8 group) {
687  g_autoptr(FlKeyEvent) event1 = fl_key_event_new(
688  0, TRUE, keycode, keyval, static_cast<GdkModifierType>(0), group);
689  fl_keyboard_manager_handle_event(manager, event1);
690  g_autoptr(FlKeyEvent) event2 = fl_key_event_new(
691  0, FALSE, keycode, keyval, static_cast<GdkModifierType>(0), group);
692  fl_keyboard_manager_handle_event(manager, event2);
693  };
694 
695  /* US keyboard layout */
696 
697  sendTap(kKeyCodeKeyA, GDK_KEY_a, 0); // KeyA
698  VERIFY_DOWN(kLogicalKeyA, "a");
699 
700  sendTap(kKeyCodeKeyA, GDK_KEY_A, 0); // Shift-KeyA
701  VERIFY_DOWN(kLogicalKeyA, "A");
702 
703  sendTap(kKeyCodeDigit1, GDK_KEY_1, 0); // Digit1
704  VERIFY_DOWN(kLogicalDigit1, "1");
705 
706  sendTap(kKeyCodeDigit1, GDK_KEY_exclam, 0); // Shift-Digit1
707  VERIFY_DOWN(kLogicalDigit1, "!");
708 
709  sendTap(kKeyCodeMinus, GDK_KEY_minus, 0); // Minus
710  VERIFY_DOWN(kLogicalMinus, "-");
711 
712  sendTap(kKeyCodeMinus, GDK_KEY_underscore, 0); // Shift-Minus
713  VERIFY_DOWN(kLogicalUnderscore, "_");
714 
715  /* French keyboard layout, group 3, which is when the input method is showing
716  * "Fr" */
717 
719  manager,
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];
729  },
730  reinterpret_cast<gpointer>(const_cast<MockLayoutData*>(&kLayoutFrench)));
731 
732  sendTap(kKeyCodeKeyA, GDK_KEY_q, 3); // KeyA
733  VERIFY_DOWN(kLogicalKeyQ, "q");
734 
735  sendTap(kKeyCodeKeyA, GDK_KEY_Q, 3); // Shift-KeyA
736  VERIFY_DOWN(kLogicalKeyQ, "Q");
737 
738  sendTap(kKeyCodeSemicolon, GDK_KEY_m, 3); // ; but prints M
739  VERIFY_DOWN(kLogicalKeyM, "m");
740 
741  sendTap(kKeyCodeKeyM, GDK_KEY_comma, 3); // M but prints ,
742  VERIFY_DOWN(kLogicalComma, ",");
743 
744  sendTap(kKeyCodeDigit1, GDK_KEY_ampersand, 3); // Digit1
745  VERIFY_DOWN(kLogicalDigit1, "&");
746 
747  sendTap(kKeyCodeDigit1, GDK_KEY_1, 3); // Shift-Digit1
748  VERIFY_DOWN(kLogicalDigit1, "1");
749 
750  sendTap(kKeyCodeMinus, GDK_KEY_parenright, 3); // Minus
751  VERIFY_DOWN(kLogicalParenthesisRight, ")");
752 
753  sendTap(kKeyCodeMinus, GDK_KEY_degree, 3); // Shift-Minus
754  VERIFY_DOWN(static_cast<uint32_t>(L'°'), "°");
755 
756  /* French keyboard layout, group 0, which is pressing the "extra key for
757  * triggering input method" key once after switching to French IME. */
758 
759  sendTap(kKeyCodeKeyA, GDK_KEY_a, 0); // KeyA
760  VERIFY_DOWN(kLogicalKeyA, "a");
761 
762  sendTap(kKeyCodeDigit1, GDK_KEY_1, 0); // Digit1
763  VERIFY_DOWN(kLogicalDigit1, "1");
764 
765  /* Russian keyboard layout, group 2 */
767  manager,
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];
777  },
778  reinterpret_cast<gpointer>(const_cast<MockLayoutData*>(&kLayoutRussian)));
779 
780  sendTap(kKeyCodeKeyA, GDK_KEY_Cyrillic_ef, 2); // KeyA
781  VERIFY_DOWN(kLogicalKeyA, "ф");
782 
783  sendTap(kKeyCodeDigit1, GDK_KEY_1, 2); // Shift-Digit1
784  VERIFY_DOWN(kLogicalDigit1, "1");
785 
786  sendTap(kKeyCodeKeyLeftBracket, GDK_KEY_Cyrillic_ha, 2);
787  VERIFY_DOWN(kLogicalBracketLeft, "х");
788 
789  /* Russian keyboard layout, group 0 */
790  sendTap(kKeyCodeKeyA, GDK_KEY_a, 0); // KeyA
791  VERIFY_DOWN(kLogicalKeyA, "a");
792 
793  sendTap(kKeyCodeKeyLeftBracket, GDK_KEY_bracketleft, 0);
794  VERIFY_DOWN(kLogicalBracketLeft, "[");
795 }
796 
797 TEST(FlKeyboardManagerTest, SynthesizeModifiersIfNeeded) {
798  ::testing::NiceMock<flutter::testing::MockKeymap> mock_keymap;
799 
800  g_autoptr(FlDartProject) project = fl_dart_project_new();
801  g_autoptr(FlEngine) engine = fl_engine_new(project);
802  g_autoptr(FlMockViewDelegate) view = fl_mock_view_delegate_new();
803  g_autoptr(FlKeyboardManager) manager =
804  fl_keyboard_manager_new(engine, FL_KEYBOARD_VIEW_DELEGATE(view));
805 
806  g_autoptr(GPtrArray) call_records = g_ptr_array_new_with_free_func(
807  reinterpret_cast<GDestroyNotify>(call_record_free));
809  manager,
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,
814  call_record_new(event, callback, callback_user_data));
815  },
816  call_records);
817 
818  auto verifyModifierIsSynthesized = [&](GdkModifierType mask,
819  uint64_t physical, uint64_t logical) {
820  // Modifier is pressed.
821  guint state = mask;
823  EXPECT_EQ(call_records->len, 1u);
825  static_cast<CallRecord*>(g_ptr_array_index(call_records, 0)),
826  kFlutterKeyEventTypeDown, physical, logical, NULL, true);
827  // Modifier is released.
828  state = state ^ mask;
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);
835  };
836 
837  // No modifiers pressed.
838  guint state = 0;
840  EXPECT_EQ(call_records->len, 0u);
841  g_ptr_array_set_size(call_records, 0);
842 
843  // Press and release each modifier once.
844  verifyModifierIsSynthesized(GDK_CONTROL_MASK, kPhysicalControlLeft,
845  kLogicalControlLeft);
846  verifyModifierIsSynthesized(GDK_META_MASK, kPhysicalMetaLeft,
847  kLogicalMetaLeft);
848  verifyModifierIsSynthesized(GDK_MOD1_MASK, kPhysicalAltLeft, kLogicalAltLeft);
849  verifyModifierIsSynthesized(GDK_SHIFT_MASK, kPhysicalShiftLeft,
850  kLogicalShiftLeft);
851 }
852 
853 TEST(FlKeyboardManagerTest, GetPressedState) {
854  ::testing::NiceMock<flutter::testing::MockKeymap> mock_keymap;
855 
856  g_autoptr(FlDartProject) project = fl_dart_project_new();
857  g_autoptr(FlEngine) engine = fl_engine_new(project);
858  g_autoptr(FlMockViewDelegate) view = fl_mock_view_delegate_new();
859  g_autoptr(FlKeyboardManager) manager =
860  fl_keyboard_manager_new(engine, FL_KEYBOARD_VIEW_DELEGATE(view));
861 
862  // Dispatch a key event.
863  g_autoptr(FlKeyEvent) event = fl_key_event_new(
864  0, TRUE, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0);
865  fl_keyboard_manager_handle_event(manager, event);
866 
867  GHashTable* pressedState = fl_keyboard_manager_get_pressed_state(manager);
868  EXPECT_EQ(g_hash_table_size(pressedState), 1u);
869 
870  gpointer physical_key =
871  g_hash_table_lookup(pressedState, uint64_to_gpointer(kPhysicalKeyA));
872  EXPECT_EQ(gpointer_to_uint64(physical_key), kLogicalKeyA);
873 }
874 
875 // The following layout data is generated using DEBUG_PRINT_LAYOUT.
876 
877 const MockGroupLayoutData kLayoutRussian0{
878  // +0x0 Shift +0x1 Shift +0x2 Shift +0x3 Shift
879  0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, // 0x00
880  0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, // 0x04
881  0x0000, 0xffff, 0xffff, 0x0031, 0x0031, 0x0021, 0x0032, 0x0040, // 0x08
882  0x0033, 0x0023, 0x0034, 0x0024, 0x0035, 0x0025, 0x0036, 0x005e, // 0x0c
883  0x0037, 0x0026, 0x0038, 0x002a, 0x0039, 0x0028, 0x0030, 0x0029, // 0x10
884  0x002d, 0x005f, 0x003d, 0x002b, 0xffff, 0xffff, 0xffff, 0xffff, // 0x14
885  0x0071, 0x0051, 0x0077, 0x0057, 0x0065, 0x0045, 0x0072, 0x0052, // 0x18
886  0x0074, 0x0054, 0x0079, 0x0059, 0x0075, 0x0055, 0x0069, 0x0049, // 0x1c
887  0x006f, 0x004f, 0x0070, 0x0050, 0x005b, 0x007b, 0x005d, 0x007d, // 0x20
888  0xffff, 0xffff, 0xffff, 0x0061, 0x0061, 0x0041, 0x0073, 0x0053, // 0x24
889  0x0064, 0x0044, 0x0066, 0x0046, 0x0067, 0x0047, 0x0068, 0x0048, // 0x28
890  0x006a, 0x004a, 0x006b, 0x004b, 0x006c, 0x004c, 0x003b, 0x003a, // 0x2c
891  0x0027, 0x0022, 0x0060, 0x007e, 0xffff, 0x005c, 0x005c, 0x007c, // 0x30
892  0x007a, 0x005a, 0x0078, 0x0058, 0x0063, 0x0043, 0x0076, 0x0056, // 0x34
893  0x0062, 0x0042, 0x006e, 0x004e, 0x006d, 0x004d, 0x002c, 0x003c, // 0x38
894  0x002e, 0x003e, 0x002f, 0x003f, 0xffff, 0xffff, 0xffff, 0xffff, // 0x3c
895  0xffff, 0xffff, 0x0020, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x40
896  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x44
897  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x48
898  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x4c
899  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x50
900  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x54
901  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x58
902  0xffff, 0xffff, 0x0000, 0xffff, 0x003c, 0x003e, 0xffff, 0xffff, // 0x5c
903  0xffff, 0xffff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x60
904  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0xffff, // 0x64
905  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x68
906  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x6c
907  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x70
908  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x74
909  0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x78
910  0xffff, 0xffff, 0xffff, 0x00b1, 0x00b1, 0xffff, 0xffff, 0xffff, // 0x7c
911 };
912 
913 const MockGroupLayoutData kLayoutRussian2{{
914  // +0x0 Shift +0x1 Shift +0x2 Shift +0x3 Shift
915  0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, // 0x00
916  0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, // 0x04
917  0xffff, 0x0031, 0x0021, 0x0000, 0x0031, 0x0021, 0x0032, 0x0022, // 0x08
918  0x0033, 0x06b0, 0x0034, 0x003b, 0x0035, 0x0025, 0x0036, 0x003a, // 0x0c
919  0x0037, 0x003f, 0x0038, 0x002a, 0x0039, 0x0028, 0x0030, 0x0029, // 0x10
920  0x002d, 0x005f, 0x003d, 0x002b, 0x0071, 0x0051, 0x0000, 0x0000, // 0x14
921  0x06ca, 0x06ea, 0x06c3, 0x06e3, 0x06d5, 0x06f5, 0x06cb, 0x06eb, // 0x18
922  0x06c5, 0x06e5, 0x06ce, 0x06ee, 0x06c7, 0x06e7, 0x06db, 0x06fb, // 0x1c
923  0x06dd, 0x06fd, 0x06da, 0x06fa, 0x06c8, 0x06e8, 0x06df, 0x06ff, // 0x20
924  0x0061, 0x0041, 0x0041, 0x0000, 0x06c6, 0x06e6, 0x06d9, 0x06f9, // 0x24
925  0x06d7, 0x06f7, 0x06c1, 0x06e1, 0x06d0, 0x06f0, 0x06d2, 0x06f2, // 0x28
926  0x06cf, 0x06ef, 0x06cc, 0x06ec, 0x06c4, 0x06e4, 0x06d6, 0x06f6, // 0x2c
927  0x06dc, 0x06fc, 0x06a3, 0x06b3, 0x007c, 0x0000, 0x005c, 0x002f, // 0x30
928  0x06d1, 0x06f1, 0x06de, 0x06fe, 0x06d3, 0x06f3, 0x06cd, 0x06ed, // 0x34
929  0x06c9, 0x06e9, 0x06d4, 0x06f4, 0x06d8, 0x06f8, 0x06c2, 0x06e2, // 0x38
930  0x06c0, 0x06e0, 0x002e, 0x002c, 0xffff, 0xffff, 0xffff, 0xffff, // 0x3c
931  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x40
932  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x44
933  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x48
934  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x4c
935  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x50
936  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x54
937  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x58
938  0xffff, 0xffff, 0x003c, 0x003e, 0x002f, 0x007c, 0xffff, 0xffff, // 0x5c
939  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x60
940  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x64
941  0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0xffff, 0xffff, 0x0000, // 0x68
942  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x6c
943  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x70
944  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x74
945  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x00b1, // 0x78
946  0x00b1, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x7c
947 }};
948 
949 const MockGroupLayoutData kLayoutFrench0 = {
950  // +0x0 Shift +0x1 Shift +0x2 Shift +0x3 Shift
951  0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, // 0x00
952  0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, // 0x04
953  0x0000, 0xffff, 0xffff, 0x0031, 0x0031, 0x0021, 0x0032, 0x0040, // 0x08
954  0x0033, 0x0023, 0x0034, 0x0024, 0x0035, 0x0025, 0x0036, 0x005e, // 0x0c
955  0x0037, 0x0026, 0x0038, 0x002a, 0x0039, 0x0028, 0x0030, 0x0029, // 0x10
956  0x002d, 0x005f, 0x003d, 0x002b, 0xffff, 0xffff, 0xffff, 0xffff, // 0x14
957  0x0071, 0x0051, 0x0077, 0x0057, 0x0065, 0x0045, 0x0072, 0x0052, // 0x18
958  0x0074, 0x0054, 0x0079, 0x0059, 0x0075, 0x0055, 0x0069, 0x0049, // 0x1c
959  0x006f, 0x004f, 0x0070, 0x0050, 0x005b, 0x007b, 0x005d, 0x007d, // 0x20
960  0xffff, 0xffff, 0xffff, 0x0061, 0x0061, 0x0041, 0x0073, 0x0053, // 0x24
961  0x0064, 0x0044, 0x0066, 0x0046, 0x0067, 0x0047, 0x0068, 0x0048, // 0x28
962  0x006a, 0x004a, 0x006b, 0x004b, 0x006c, 0x004c, 0x003b, 0x003a, // 0x2c
963  0x0027, 0x0022, 0x0060, 0x007e, 0xffff, 0x005c, 0x005c, 0x007c, // 0x30
964  0x007a, 0x005a, 0x0078, 0x0058, 0x0063, 0x0043, 0x0076, 0x0056, // 0x34
965  0x0062, 0x0042, 0x006e, 0x004e, 0x006d, 0x004d, 0x002c, 0x003c, // 0x38
966  0x002e, 0x003e, 0x002f, 0x003f, 0xffff, 0xffff, 0xffff, 0xffff, // 0x3c
967  0xffff, 0xffff, 0x0020, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x40
968  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x44
969  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x48
970  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x4c
971  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x50
972  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x54
973  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x58
974  0xffff, 0xffff, 0x0000, 0xffff, 0x003c, 0x003e, 0xffff, 0xffff, // 0x5c
975  0xffff, 0xffff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x60
976  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0xffff, // 0x64
977  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x68
978  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x6c
979  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x70
980  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x74
981  0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x78
982  0xffff, 0xffff, 0xffff, 0x00b1, 0x00b1, 0xffff, 0xffff, 0xffff, // 0x7c
983 };
984 
985 const MockGroupLayoutData kLayoutFrench3 = {
986  // +0x0 Shift +0x1 Shift +0x2 Shift +0x3 Shift
987  0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, // 0x00
988  0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, // 0x04
989  0x0000, 0xffff, 0x0000, 0x0000, 0x0026, 0x0031, 0x00e9, 0x0032, // 0x08
990  0x0022, 0x0033, 0x0027, 0x0034, 0x0028, 0x0035, 0x002d, 0x0036, // 0x0c
991  0x00e8, 0x0037, 0x005f, 0x0038, 0x00e7, 0x0039, 0x00e0, 0x0030, // 0x10
992  0x0029, 0x00b0, 0x003d, 0x002b, 0x0000, 0x0000, 0x0061, 0x0041, // 0x14
993  0x0061, 0x0041, 0x007a, 0x005a, 0x0065, 0x0045, 0x0072, 0x0052, // 0x18
994  0x0074, 0x0054, 0x0079, 0x0059, 0x0075, 0x0055, 0x0069, 0x0049, // 0x1c
995  0x006f, 0x004f, 0x0070, 0x0050, 0xffff, 0xffff, 0x0024, 0x00a3, // 0x20
996  0x0041, 0x0000, 0x0000, 0x0000, 0x0071, 0x0051, 0x0073, 0x0053, // 0x24
997  0x0064, 0x0044, 0x0066, 0x0046, 0x0067, 0x0047, 0x0068, 0x0048, // 0x28
998  0x006a, 0x004a, 0x006b, 0x004b, 0x006c, 0x004c, 0x006d, 0x004d, // 0x2c
999  0x00f9, 0x0025, 0x00b2, 0x007e, 0x0000, 0x0000, 0x002a, 0x00b5, // 0x30
1000  0x0077, 0x0057, 0x0078, 0x0058, 0x0063, 0x0043, 0x0076, 0x0056, // 0x34
1001  0x0062, 0x0042, 0x006e, 0x004e, 0x002c, 0x003f, 0x003b, 0x002e, // 0x38
1002  0x003a, 0x002f, 0x0021, 0x00a7, 0xffff, 0xffff, 0xffff, 0xffff, // 0x3c
1003  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x40
1004  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x44
1005  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x48
1006  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x4c
1007  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x50
1008  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x54
1009  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x58
1010  0xffff, 0x003c, 0x0000, 0xffff, 0x003c, 0x003e, 0xffff, 0xffff, // 0x5c
1011  0xffff, 0xffff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x60
1012  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0xffff, // 0x64
1013  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x68
1014  0xffff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x6c
1015  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x70
1016  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x74
1017  0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0x00b1, 0x00b1, 0xffff, // 0x78
1018  0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x7c
1019 };
1020 
1021 const MockLayoutData kLayoutRussian{&kLayoutRussian0, nullptr,
1022  &kLayoutRussian2};
1023 const MockLayoutData kLayoutFrench{&kLayoutFrench0, nullptr, nullptr,
1024  &kLayoutFrench3};
1025 
1026 } // namespace
CallRecord::event_synthesized
bool event_synthesized
Definition: fl_keyboard_manager_test.cc:48
fl_keyboard_manager_set_redispatch_handler
void fl_keyboard_manager_set_redispatch_handler(FlKeyboardManager *self, FlKeyboardManagerRedispatchEventHandler redispatch_handler, gpointer user_data)
Definition: fl_keyboard_manager.cc:595
fl_value_set_string_take
G_MODULE_EXPORT void fl_value_set_string_take(FlValue *self, const gchar *key, FlValue *value)
Definition: fl_value.cc:650
CallRecord::event_logical
uint64_t event_logical
Definition: fl_keyboard_manager_test.cc:46
fl_keyboard_manager.h
CallRecord::event_physical
uint64_t event_physical
Definition: fl_keyboard_manager_test.cc:45
CallRecord
Definition: fl_keyboard_manager_test.cc:43
fl_value_new_bool
G_MODULE_EXPORT FlValue * fl_value_new_bool(bool value)
Definition: fl_value.cc:255
FlValue
typedefG_BEGIN_DECLS struct _FlValue FlValue
Definition: fl_value.h:42
uint64_to_gpointer
gpointer uint64_to_gpointer(uint64_t number)
Definition: key_mapping.h:17
fl_dart_project_new
G_MODULE_EXPORT FlDartProject * fl_dart_project_new()
Definition: fl_dart_project.cc:50
call_record_free
static void call_record_free(CallRecord *record)
Definition: fl_keyboard_manager_test.cc:67
fl_keyboard_manager_is_state_clear
gboolean fl_keyboard_manager_is_state_clear(FlKeyboardManager *self)
Definition: fl_keyboard_manager.cc:552
state
AtkStateType state
Definition: fl_accessible_node.cc:10
fl_keyboard_manager_handle_event
gboolean fl_keyboard_manager_handle_event(FlKeyboardManager *self, FlKeyEvent *event)
Definition: fl_keyboard_manager.cc:522
user_data
G_BEGIN_DECLS G_MODULE_EXPORT FlValue gpointer user_data
Definition: fl_event_channel.h:90
fl_value_ref
G_MODULE_EXPORT FlValue * fl_value_ref(FlValue *self)
Definition: fl_value.cc:394
call_record_respond
static void call_record_respond(CallRecord *record, bool handled)
Definition: fl_keyboard_manager_test.cc:72
fl_key_event_get_keyval
guint fl_key_event_get_keyval(FlKeyEvent *self)
Definition: fl_key_event.cc:94
fl_value_new_map
G_MODULE_EXPORT FlValue * fl_value_new_map()
Definition: fl_value.cc:366
call_record_new
static CallRecord * call_record_new(const FlutterKeyEvent *event, FlutterKeyEventCallback callback, void *callback_user_data)
Definition: fl_keyboard_manager_test.cc:53
fl_keyboard_manager_set_lookup_key_handler
void fl_keyboard_manager_set_lookup_key_handler(FlKeyboardManager *self, FlKeyboardManagerLookupKeyHandler lookup_key_handler, gpointer user_data)
Definition: fl_keyboard_manager.cc:586
CallRecord::event_type
FlutterKeyEventType event_type
Definition: fl_keyboard_manager_test.cc:44
fl_engine_private.h
key_mapping.h
TRUE
return TRUE
Definition: fl_pixel_buffer_texture_test.cc:53
G_DECLARE_FINAL_TYPE
G_BEGIN_DECLS G_DECLARE_FINAL_TYPE(FlAccessibleTextField, fl_accessible_text_field, FL, ACCESSIBLE_TEXT_FIELD, FlAccessibleNode)
FL
FL
Definition: fl_binary_messenger.cc:27
EXPECT_KEY_EVENT
#define EXPECT_KEY_EVENT(RECORD, TYPE, PHYSICAL, LOGICAL, CHAR, SYNTHESIZED)
Definition: fl_keyboard_manager_test.cc:21
fl_keyboard_manager_sync_modifier_if_needed
void fl_keyboard_manager_sync_modifier_if_needed(FlKeyboardManager *self, guint state, double event_time)
Definition: fl_keyboard_manager.cc:558
CallRecord::callback
FlutterKeyEventCallback callback
Definition: fl_keyboard_manager_test.cc:49
fl_keyboard_manager_get_pressed_state
GHashTable * fl_keyboard_manager_get_pressed_state(FlKeyboardManager *self)
Definition: fl_keyboard_manager.cc:566
fl_engine_new
G_MODULE_EXPORT FlEngine * fl_engine_new(FlDartProject *project)
Definition: fl_engine.cc:524
view
FlView * view
Definition: fl_application.cc:35
error
const uint8_t uint32_t uint32_t GError ** error
Definition: fl_pixel_buffer_texture_test.cc:40
CallRecord::callback_user_data
void * callback_user_data
Definition: fl_keyboard_manager_test.cc:50
TEST
TEST(FlAccessibleNodeTest, BuildTree)
Definition: fl_accessible_node_test.cc:11
fl_engine_start
gboolean fl_engine_start(FlEngine *self, GError **error)
Definition: fl_engine.cc:544
fl_key_event_new
FlKeyEvent * fl_key_event_new(guint32 time, gboolean is_press, guint16 keycode, guint keyval, GdkModifierType state, guint8 group)
Definition: fl_key_event.cc:34
fl_keyboard_manager_set_send_key_event_handler
void fl_keyboard_manager_set_send_key_event_handler(FlKeyboardManager *self, FlKeyboardManagerSendKeyEventHandler send_key_event_handler, gpointer user_data)
Definition: fl_keyboard_manager.cc:577
CallRecord::event_character
gchar * event_character
Definition: fl_keyboard_manager_test.cc:47
fl_keyboard_manager_new
FlKeyboardManager * fl_keyboard_manager_new(FlEngine *engine, FlKeyboardViewDelegate *view_delegate)
Definition: fl_keyboard_manager.cc:462
VERIFY_DOWN
#define VERIFY_DOWN(OUT_LOGICAL, OUT_CHAR)
Definition: fl_keyboard_manager_test.cc:28
value
uint8_t value
Definition: fl_standard_message_codec.cc:36
gpointer_to_uint64
uint64_t gpointer_to_uint64(gpointer pointer)
Definition: key_mapping.h:13
G_DEFINE_TYPE_WITH_CODE
G_DEFINE_TYPE_WITH_CODE(FlAccessibleNode, fl_accessible_node, ATK_TYPE_OBJECT, G_IMPLEMENT_INTERFACE(ATK_TYPE_COMPONENT, fl_accessible_node_component_interface_init) G_IMPLEMENT_INTERFACE(ATK_TYPE_ACTION, fl_accessible_node_action_interface_init)) static gboolean flag_is_changed(FlutterSemanticsFlag old_flags