Flutter Linux Embedder
fl_key_embedder_responder_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 "gtest/gtest.h"
8 
9 #include "flutter/shell/platform/embedder/test_utils/key_codes.g.h"
10 #include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h"
13 #include "flutter/shell/platform/linux/testing/fl_test.h"
14 
15 namespace {
16 constexpr gboolean kRelease = FALSE;
17 constexpr gboolean kPress = TRUE;
18 
19 constexpr gboolean kIsModifier = TRUE;
20 constexpr gboolean kIsNotModifier = FALSE;
21 
22 constexpr guint16 kKeyCodeDigit1 = 0x0au;
23 constexpr guint16 kKeyCodeKeyA = 0x26u;
24 constexpr guint16 kKeyCodeShiftLeft = 0x32u;
25 constexpr guint16 kKeyCodeShiftRight = 0x3Eu;
26 constexpr guint16 kKeyCodeAltLeft = 0x40u;
27 constexpr guint16 kKeyCodeAltRight = 0x6Cu;
28 constexpr guint16 kKeyCodeNumpad1 = 0x57u;
29 constexpr guint16 kKeyCodeNumLock = 0x4Du;
30 constexpr guint16 kKeyCodeCapsLock = 0x42u;
31 constexpr guint16 kKeyCodeControlLeft = 0x25u;
32 constexpr guint16 kKeyCodeControlRight = 0x69u;
33 
34 using namespace ::flutter::testing::keycodes;
35 } // namespace
36 
37 static void g_ptr_array_clear(GPtrArray* array) {
38  g_ptr_array_remove_range(array, 0, array->len);
39 }
40 
41 G_DECLARE_FINAL_TYPE(FlKeyEmbedderCallRecord,
42  fl_key_embedder_call_record,
43  FL,
44  KEY_EMBEDDER_CALL_RECORD,
45  GObject);
46 
48  GObject parent_instance;
49 
50  FlutterKeyEvent* event;
51  FlutterKeyEventCallback callback;
52  gpointer user_data;
53 };
54 
55 G_DEFINE_TYPE(FlKeyEmbedderCallRecord,
56  fl_key_embedder_call_record,
57  G_TYPE_OBJECT)
58 
59 static void fl_key_embedder_call_record_init(FlKeyEmbedderCallRecord* self) {}
60 
61 // Dispose method for FlKeyEmbedderCallRecord.
62 static void fl_key_embedder_call_record_dispose(GObject* object) {
63  g_return_if_fail(FL_IS_KEY_EMBEDDER_CALL_RECORD(object));
64 
65  FlKeyEmbedderCallRecord* self = FL_KEY_EMBEDDER_CALL_RECORD(object);
66  if (self->event != nullptr) {
67  g_free(const_cast<char*>(self->event->character));
68  g_free(self->event);
69  }
70  G_OBJECT_CLASS(fl_key_embedder_call_record_parent_class)->dispose(object);
71 }
72 
73 // Class Initialization method for FlKeyEmbedderCallRecord class.
75  FlKeyEmbedderCallRecordClass* klass) {
76  G_OBJECT_CLASS(klass)->dispose = fl_key_embedder_call_record_dispose;
77 }
78 
79 static FlKeyEmbedderCallRecord* fl_key_embedder_call_record_new(
80  const FlutterKeyEvent* event,
81  FlutterKeyEventCallback callback,
82  gpointer user_data) {
83  g_return_val_if_fail(event != nullptr, nullptr);
84 
85  FlKeyEmbedderCallRecord* self = FL_KEY_EMBEDDER_CALL_RECORD(
86  g_object_new(fl_key_embedder_call_record_get_type(), nullptr));
87 
88  FlutterKeyEvent* clone_event = g_new(FlutterKeyEvent, 1);
89  *clone_event = *event;
90  if (event->character != nullptr) {
91  size_t character_length = strlen(event->character);
92  char* clone_character = g_new(char, character_length + 1);
93  strncpy(clone_character, event->character, character_length + 1);
94  clone_event->character = clone_character;
95  }
96  self->event = clone_event;
97  self->callback = callback;
98  self->user_data = user_data;
99 
100  return self;
101 }
102 
103 namespace {
104 // A global variable to store new event. It is a global variable so that it can
105 // be returned by #fl_key_event_new_by_mock for easy use.
106 FlKeyEvent _g_key_event;
107 } // namespace
108 
109 // Create a new #FlKeyEvent with the given information.
110 //
111 // This event is passed to #fl_key_responder_handle_event,
112 // which assumes that the event is managed by callee.
113 // Therefore #fl_key_event_new_by_mock doesn't need to
114 // dynamically allocate, but reuses the same global object.
115 static FlKeyEvent* fl_key_event_new_by_mock(guint32 time_in_milliseconds,
116  bool is_press,
117  guint keyval,
118  guint16 keycode,
119  GdkModifierType state,
120  gboolean is_modifier) {
121  _g_key_event.is_press = is_press;
122  _g_key_event.time = time_in_milliseconds;
123  _g_key_event.state = state;
124  _g_key_event.keyval = keyval;
125  _g_key_event.keycode = keycode;
126  _g_key_event.origin = nullptr;
127  return &_g_key_event;
128 }
129 
130 static gboolean g_expected_handled;
131 static gpointer g_expected_user_data;
132 
133 static void verify_response_handled(bool handled, gpointer user_data) {
134  EXPECT_EQ(handled, g_expected_handled);
135 }
136 
137 static void invoke_record_callback_and_verify(FlKeyEmbedderCallRecord* record,
138  bool expected_handled,
139  void* expected_user_data) {
140  g_return_if_fail(record->callback != nullptr);
142  g_expected_user_data = expected_user_data;
143  record->callback(expected_handled, record->user_data);
144 }
145 
146 namespace {
147 GPtrArray* g_call_records;
148 }
149 
150 static void record_calls(const FlutterKeyEvent* event,
151  FlutterKeyEventCallback callback,
152  void* callback_user_data,
153  void* send_key_event_user_data) {
154  GPtrArray* records_array =
155  reinterpret_cast<GPtrArray*>(send_key_event_user_data);
156  if (records_array != nullptr) {
157  g_ptr_array_add(records_array, fl_key_embedder_call_record_new(
158  event, callback, callback_user_data));
159  }
160 }
161 
162 static void clear_g_call_records() {
163  g_ptr_array_free(g_call_records, TRUE);
164  g_call_records = nullptr;
165 }
166 
167 // Basic key presses
168 TEST(FlKeyEmbedderResponderTest, SendKeyEvent) {
169  EXPECT_EQ(g_call_records, nullptr);
170  g_call_records = g_ptr_array_new_with_free_func(g_object_unref);
171  FlKeyResponder* responder = FL_KEY_RESPONDER(
173  int user_data = 123; // Arbitrary user data
174 
175  FlKeyEmbedderCallRecord* record;
176 
177  // On a QWERTY keyboard, press key Q (physically key A), and release.
178  // Key down
180  responder,
181  fl_key_event_new_by_mock(12345, kPress, GDK_KEY_a, kKeyCodeKeyA,
182  static_cast<GdkModifierType>(0), kIsNotModifier),
184 
185  EXPECT_EQ(g_call_records->len, 1u);
186  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
187  EXPECT_EQ(record->event->struct_size, sizeof(FlutterKeyEvent));
188  EXPECT_EQ(record->event->timestamp, 12345000);
189  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
190  EXPECT_EQ(record->event->physical, kPhysicalKeyA);
191  EXPECT_EQ(record->event->logical, kLogicalKeyA);
192  EXPECT_STREQ(record->event->character, "a");
193  EXPECT_EQ(record->event->synthesized, false);
194 
196  g_ptr_array_clear(g_call_records);
197 
198  // Key up
200  responder,
201  fl_key_event_new_by_mock(12346, kRelease, GDK_KEY_a, kKeyCodeKeyA,
202  static_cast<GdkModifierType>(0), kIsNotModifier),
204 
205  EXPECT_EQ(g_call_records->len, 1u);
206  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
207  EXPECT_EQ(record->event->struct_size, sizeof(FlutterKeyEvent));
208  EXPECT_EQ(record->event->timestamp, 12346000);
209  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
210  EXPECT_EQ(record->event->physical, kPhysicalKeyA);
211  EXPECT_EQ(record->event->logical, kLogicalKeyA);
212  EXPECT_STREQ(record->event->character, nullptr);
213  EXPECT_EQ(record->event->synthesized, false);
214 
216  g_ptr_array_clear(g_call_records);
217 
218  // On an AZERTY keyboard, press key Q (physically key A), and release.
219  // Key down
221  responder,
222  fl_key_event_new_by_mock(12347, kPress, GDK_KEY_q, kKeyCodeKeyA,
223  static_cast<GdkModifierType>(0), kIsNotModifier),
225 
226  EXPECT_EQ(g_call_records->len, 1u);
227  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
228  EXPECT_EQ(record->event->struct_size, sizeof(FlutterKeyEvent));
229  EXPECT_EQ(record->event->timestamp, 12347000);
230  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
231  EXPECT_EQ(record->event->physical, kPhysicalKeyA);
232  EXPECT_EQ(record->event->logical, kLogicalKeyQ);
233  EXPECT_STREQ(record->event->character, "q");
234  EXPECT_EQ(record->event->synthesized, false);
235 
237  g_ptr_array_clear(g_call_records);
238 
239  // Key up
241  responder,
242  fl_key_event_new_by_mock(12348, kRelease, GDK_KEY_q, kKeyCodeKeyA,
243  static_cast<GdkModifierType>(0), kIsNotModifier),
245 
246  EXPECT_EQ(g_call_records->len, 1u);
247  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
248  EXPECT_EQ(record->event->struct_size, sizeof(FlutterKeyEvent));
249  EXPECT_EQ(record->event->timestamp, 12348000);
250  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
251  EXPECT_EQ(record->event->physical, kPhysicalKeyA);
252  EXPECT_EQ(record->event->logical, kLogicalKeyQ);
253  EXPECT_STREQ(record->event->character, nullptr);
254  EXPECT_EQ(record->event->synthesized, false);
255 
257  g_ptr_array_clear(g_call_records);
258 
260  g_object_unref(responder);
261 }
262 
263 // Basic key presses, but uses the specified logical key if it is not 0.
264 TEST(FlKeyEmbedderResponderTest, UsesSpecifiedLogicalKey) {
265  EXPECT_EQ(g_call_records, nullptr);
266  g_call_records = g_ptr_array_new_with_free_func(g_object_unref);
267  FlKeyResponder* responder = FL_KEY_RESPONDER(
269  int user_data = 123; // Arbitrary user data
270 
271  FlKeyEmbedderCallRecord* record;
272 
273  // On an AZERTY keyboard, press physical key 1, and release.
274  // Key down
276  responder,
277  fl_key_event_new_by_mock(12345, kPress, GDK_KEY_ampersand, kKeyCodeDigit1,
278  static_cast<GdkModifierType>(0), kIsNotModifier),
279  verify_response_handled, &user_data, kLogicalDigit1);
280 
281  EXPECT_EQ(g_call_records->len, 1u);
282  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
283  EXPECT_EQ(record->event->struct_size, sizeof(FlutterKeyEvent));
284  EXPECT_EQ(record->event->timestamp, 12345000);
285  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
286  EXPECT_EQ(record->event->physical, kPhysicalDigit1);
287  EXPECT_EQ(record->event->logical, kLogicalDigit1);
288  EXPECT_STREQ(record->event->character, "&");
289  EXPECT_EQ(record->event->synthesized, false);
290 
292  g_ptr_array_clear(g_call_records);
293 
295  g_object_unref(responder);
296 }
297 
298 // Press Shift, key A, then release Shift, key A.
299 TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) {
300  EXPECT_EQ(g_call_records, nullptr);
301  g_call_records = g_ptr_array_new_with_free_func(g_object_unref);
302  FlKeyResponder* responder = FL_KEY_RESPONDER(
304  int user_data = 123; // Arbitrary user data
305 
306  FlKeyEmbedderCallRecord* record;
307 
308  // Press shift right
310  responder,
311  fl_key_event_new_by_mock(101, kPress, GDK_KEY_Shift_R, kKeyCodeShiftRight,
312  static_cast<GdkModifierType>(0), kIsModifier),
314 
315  EXPECT_EQ(g_call_records->len, 1u);
316  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
317  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
318  EXPECT_EQ(record->event->physical, kPhysicalShiftRight);
319  EXPECT_EQ(record->event->logical, kLogicalShiftRight);
320  EXPECT_STREQ(record->event->character, nullptr);
321  EXPECT_EQ(record->event->synthesized, false);
322 
324  g_ptr_array_clear(g_call_records);
325 
326  // Press key A
328  responder,
329  fl_key_event_new_by_mock(102, kPress, GDK_KEY_A, kKeyCodeKeyA,
330  GDK_SHIFT_MASK, kIsNotModifier),
332 
333  EXPECT_EQ(g_call_records->len, 1u);
334  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
335  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
336  EXPECT_EQ(record->event->physical, kPhysicalKeyA);
337  EXPECT_EQ(record->event->logical, kLogicalKeyA);
338  EXPECT_STREQ(record->event->character, "A");
339  EXPECT_EQ(record->event->synthesized, false);
340 
342  g_ptr_array_clear(g_call_records);
343 
344  // Release shift right
346  responder,
347  fl_key_event_new_by_mock(103, kRelease, GDK_KEY_Shift_R,
348  kKeyCodeShiftRight, GDK_SHIFT_MASK, kIsModifier),
350 
351  EXPECT_EQ(g_call_records->len, 1u);
352  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
353  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
354  EXPECT_EQ(record->event->physical, kPhysicalShiftRight);
355  EXPECT_EQ(record->event->logical, kLogicalShiftRight);
356  EXPECT_STREQ(record->event->character, nullptr);
357  EXPECT_EQ(record->event->synthesized, false);
358 
360  g_ptr_array_clear(g_call_records);
361 
362  // Release key A
364  responder,
365  fl_key_event_new_by_mock(104, kRelease, GDK_KEY_A, kKeyCodeKeyA,
366  static_cast<GdkModifierType>(0), kIsNotModifier),
368 
369  EXPECT_EQ(g_call_records->len, 1u);
370  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
371  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
372  EXPECT_EQ(record->event->physical, kPhysicalKeyA);
373  EXPECT_EQ(record->event->logical, kLogicalKeyA);
374  EXPECT_STREQ(record->event->character, nullptr);
375  EXPECT_EQ(record->event->synthesized, false);
376 
378  g_ptr_array_clear(g_call_records);
379 
381  g_object_unref(responder);
382 }
383 
384 // Press or release Numpad 1 between presses/releases of NumLock.
385 //
386 // This tests interaction between lock keys and non-lock keys in cases that do
387 // not have events missed.
388 //
389 // This also tests the result of Numpad keys across NumLock taps, which is
390 // test-worthy because the keyval for the numpad key will change before and
391 // after the NumLock tap, which should not alter the resulting logical key.
392 TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) {
393  EXPECT_EQ(g_call_records, nullptr);
394  g_call_records = g_ptr_array_new_with_free_func(g_object_unref);
395  FlKeyResponder* responder = FL_KEY_RESPONDER(
397  int user_data = 123; // Arbitrary user data
398 
399  FlKeyEmbedderCallRecord* record;
400 
401  // Press Numpad 1 (stage 0)
403  responder,
404  fl_key_event_new_by_mock(101, kPress, GDK_KEY_KP_End, kKeyCodeNumpad1,
405  static_cast<GdkModifierType>(0), kIsNotModifier),
407 
408  EXPECT_EQ(g_call_records->len, 1u);
409  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
410  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
411  EXPECT_EQ(record->event->physical, kPhysicalNumpad1);
412  EXPECT_EQ(record->event->logical, kLogicalNumpad1);
413  EXPECT_STREQ(record->event->character, nullptr); // TODO(chrome-bot):
414  EXPECT_EQ(record->event->synthesized, false);
415 
417  g_ptr_array_clear(g_call_records);
418 
419  // Press NumLock (stage 0 -> 1)
421  responder,
422  fl_key_event_new_by_mock(102, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock,
423  static_cast<GdkModifierType>(0), kIsNotModifier),
425 
426  EXPECT_EQ(g_call_records->len, 1u);
427  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
428  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
429  EXPECT_EQ(record->event->physical, kPhysicalNumLock);
430  EXPECT_EQ(record->event->logical, kLogicalNumLock);
431  EXPECT_STREQ(record->event->character, nullptr);
432  EXPECT_EQ(record->event->synthesized, false);
433 
435  g_ptr_array_clear(g_call_records);
436 
437  // Release numpad 1 (stage 1)
439  responder,
440  fl_key_event_new_by_mock(104, kRelease, GDK_KEY_KP_1, kKeyCodeNumpad1,
441  GDK_MOD2_MASK, kIsNotModifier),
443 
444  EXPECT_EQ(g_call_records->len, 1u);
445  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
446  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
447  EXPECT_EQ(record->event->physical, kPhysicalNumpad1);
448  EXPECT_EQ(record->event->logical, kLogicalNumpad1);
449  EXPECT_STREQ(record->event->character, nullptr);
450  EXPECT_EQ(record->event->synthesized, false);
451 
453  g_ptr_array_clear(g_call_records);
454 
455  // Release NumLock (stage 1 -> 2)
457  responder,
458  fl_key_event_new_by_mock(103, kRelease, GDK_KEY_Num_Lock, kKeyCodeNumLock,
459  GDK_MOD2_MASK, kIsModifier),
461 
462  EXPECT_EQ(g_call_records->len, 1u);
463  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
464  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
465  EXPECT_EQ(record->event->physical, kPhysicalNumLock);
466  EXPECT_EQ(record->event->logical, kLogicalNumLock);
467  EXPECT_STREQ(record->event->character, nullptr);
468  EXPECT_EQ(record->event->synthesized, false);
469 
471  g_ptr_array_clear(g_call_records);
472 
473  // Press Numpad 1 (stage 2)
475  responder,
476  fl_key_event_new_by_mock(101, kPress, GDK_KEY_KP_End, kKeyCodeNumpad1,
477  GDK_MOD2_MASK, kIsNotModifier),
479 
480  EXPECT_EQ(g_call_records->len, 1u);
481  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
482  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
483  EXPECT_EQ(record->event->physical, kPhysicalNumpad1);
484  EXPECT_EQ(record->event->logical, kLogicalNumpad1);
485  EXPECT_STREQ(record->event->character, nullptr); // TODO(chrome-bot):
486  EXPECT_EQ(record->event->synthesized, false);
487 
489  g_ptr_array_clear(g_call_records);
490 
491  // Press NumLock (stage 2 -> 3)
493  responder,
494  fl_key_event_new_by_mock(102, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock,
495  GDK_MOD2_MASK, kIsNotModifier),
497 
498  EXPECT_EQ(g_call_records->len, 1u);
499  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
500  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
501  EXPECT_EQ(record->event->physical, kPhysicalNumLock);
502  EXPECT_EQ(record->event->logical, kLogicalNumLock);
503  EXPECT_STREQ(record->event->character, nullptr);
504  EXPECT_EQ(record->event->synthesized, false);
505 
507  g_ptr_array_clear(g_call_records);
508 
509  // Release numpad 1 (stage 3)
511  responder,
512  fl_key_event_new_by_mock(104, kRelease, GDK_KEY_KP_1, kKeyCodeNumpad1,
513  GDK_MOD2_MASK, kIsNotModifier),
515 
516  EXPECT_EQ(g_call_records->len, 1u);
517  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
518  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
519  EXPECT_EQ(record->event->physical, kPhysicalNumpad1);
520  EXPECT_EQ(record->event->logical, kLogicalNumpad1);
521  EXPECT_STREQ(record->event->character, nullptr);
522  EXPECT_EQ(record->event->synthesized, false);
523 
525  g_ptr_array_clear(g_call_records);
526 
527  // Release NumLock (stage 3 -> 0)
529  responder,
530  fl_key_event_new_by_mock(103, kRelease, GDK_KEY_Num_Lock, kKeyCodeNumLock,
531  GDK_MOD2_MASK, kIsModifier),
533 
534  EXPECT_EQ(g_call_records->len, 1u);
535  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
536  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
537  EXPECT_EQ(record->event->physical, kPhysicalNumLock);
538  EXPECT_EQ(record->event->logical, kLogicalNumLock);
539  EXPECT_STREQ(record->event->character, nullptr);
540  EXPECT_EQ(record->event->synthesized, false);
541 
543  g_ptr_array_clear(g_call_records);
544 
546  g_object_unref(responder);
547 }
548 
549 // Press or release digit 1 between presses/releases of Shift.
550 //
551 // GTK will change the virtual key during a key tap, and the embedder
552 // should regularize it.
553 TEST(FlKeyEmbedderResponderTest, ReleaseShiftKeyBetweenDigitKeyEvents) {
554  EXPECT_EQ(g_call_records, nullptr);
555  g_call_records = g_ptr_array_new_with_free_func(g_object_unref);
556  FlKeyResponder* responder = FL_KEY_RESPONDER(
558  int user_data = 123; // Arbitrary user data
559 
560  FlKeyEmbedderCallRecord* record;
561 
562  GdkModifierType state = static_cast<GdkModifierType>(0);
563 
564  // Press shift left
566  responder,
567  fl_key_event_new_by_mock(101, kPress, GDK_KEY_Shift_L, kKeyCodeShiftLeft,
568  state, kIsModifier),
570 
571  EXPECT_EQ(g_call_records->len, 1u);
572  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
573  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
574  EXPECT_EQ(record->event->physical, kPhysicalShiftLeft);
575  EXPECT_EQ(record->event->logical, kLogicalShiftLeft);
576  EXPECT_STREQ(record->event->character, nullptr);
577  EXPECT_EQ(record->event->synthesized, false);
578 
580  g_ptr_array_clear(g_call_records);
581 
582  state = GDK_SHIFT_MASK;
583 
584  // Press digit 1, which is '!' on a US keyboard
586  responder,
587  fl_key_event_new_by_mock(102, kPress, GDK_KEY_exclam, kKeyCodeDigit1,
588  state, kIsNotModifier),
590 
591  EXPECT_EQ(g_call_records->len, 1u);
592  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
593  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
594  EXPECT_EQ(record->event->physical, kPhysicalDigit1);
595  EXPECT_EQ(record->event->logical, kLogicalExclamation);
596  EXPECT_STREQ(record->event->character, "!");
597  EXPECT_EQ(record->event->synthesized, false);
598 
600  g_ptr_array_clear(g_call_records);
601 
602  // Release shift
604  responder,
605  fl_key_event_new_by_mock(103, kRelease, GDK_KEY_Shift_L,
606  kKeyCodeShiftLeft, state, kIsModifier),
608 
609  EXPECT_EQ(g_call_records->len, 1u);
610  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
611  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
612  EXPECT_EQ(record->event->physical, kPhysicalShiftLeft);
613  EXPECT_EQ(record->event->logical, kLogicalShiftLeft);
614  EXPECT_STREQ(record->event->character, nullptr);
615  EXPECT_EQ(record->event->synthesized, false);
616 
618  g_ptr_array_clear(g_call_records);
619 
620  state = static_cast<GdkModifierType>(0);
621 
622  // Release digit 1, which is "1" because shift has been released.
624  responder,
625  fl_key_event_new_by_mock(104, kRelease, GDK_KEY_1, kKeyCodeDigit1, state,
626  kIsNotModifier),
628 
629  EXPECT_EQ(g_call_records->len, 1u);
630  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
631  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
632  EXPECT_EQ(record->event->physical, kPhysicalDigit1);
633  EXPECT_EQ(record->event->logical, kLogicalExclamation); // Important
634  EXPECT_STREQ(record->event->character, nullptr);
635  EXPECT_EQ(record->event->synthesized, false);
636 
638  g_ptr_array_clear(g_call_records);
639 
641  g_object_unref(responder);
642 }
643 
644 // Press or release letter key between presses/releases of CapsLock.
645 //
646 // This tests interaction between lock keys and non-lock keys in cases that do
647 // not have events missed.
648 TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) {
649  EXPECT_EQ(g_call_records, nullptr);
650  g_call_records = g_ptr_array_new_with_free_func(g_object_unref);
651  FlKeyResponder* responder = FL_KEY_RESPONDER(
653  int user_data = 123; // Arbitrary user data
654 
655  FlKeyEmbedderCallRecord* record;
656 
657  // Press CapsLock (stage 0 -> 1)
659  responder,
660  fl_key_event_new_by_mock(101, kPress, GDK_KEY_Caps_Lock, kKeyCodeCapsLock,
661  static_cast<GdkModifierType>(0), kIsModifier),
663 
664  EXPECT_EQ(g_call_records->len, 1u);
665  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
666  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
667  EXPECT_EQ(record->event->physical, kPhysicalCapsLock);
668  EXPECT_EQ(record->event->logical, kLogicalCapsLock);
669  EXPECT_STREQ(record->event->character, nullptr);
670  EXPECT_EQ(record->event->synthesized, false);
671 
673  g_ptr_array_clear(g_call_records);
674 
675  // Press key A (stage 1)
677  responder,
678  fl_key_event_new_by_mock(102, kPress, GDK_KEY_A, kKeyCodeKeyA,
679  GDK_LOCK_MASK, kIsNotModifier),
681 
682  EXPECT_EQ(g_call_records->len, 1u);
683  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
684  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
685  EXPECT_EQ(record->event->physical, kPhysicalKeyA);
686  EXPECT_EQ(record->event->logical, kLogicalKeyA);
687  EXPECT_STREQ(record->event->character, "A");
688  EXPECT_EQ(record->event->synthesized, false);
689 
691  g_ptr_array_clear(g_call_records);
692 
693  // Release CapsLock (stage 1 -> 2)
695  responder,
696  fl_key_event_new_by_mock(103, kRelease, GDK_KEY_Caps_Lock,
697  kKeyCodeCapsLock, GDK_LOCK_MASK, kIsModifier),
699 
700  EXPECT_EQ(g_call_records->len, 1u);
701  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
702  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
703  EXPECT_EQ(record->event->physical, kPhysicalCapsLock);
704  EXPECT_EQ(record->event->logical, kLogicalCapsLock);
705  EXPECT_STREQ(record->event->character, nullptr);
706  EXPECT_EQ(record->event->synthesized, false);
707 
709  g_ptr_array_clear(g_call_records);
710 
711  // Release key A (stage 2)
713  responder,
714  fl_key_event_new_by_mock(104, kRelease, GDK_KEY_A, kKeyCodeKeyA,
715  GDK_LOCK_MASK, kIsNotModifier),
717 
718  EXPECT_EQ(g_call_records->len, 1u);
719  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
720  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
721  EXPECT_EQ(record->event->physical, kPhysicalKeyA);
722  EXPECT_EQ(record->event->logical, kLogicalKeyA);
723  EXPECT_STREQ(record->event->character, nullptr);
724  EXPECT_EQ(record->event->synthesized, false);
725 
727  g_ptr_array_clear(g_call_records);
728 
729  // Press CapsLock (stage 2 -> 3)
731  responder,
732  fl_key_event_new_by_mock(105, kPress, GDK_KEY_Caps_Lock, kKeyCodeCapsLock,
733  GDK_LOCK_MASK, kIsModifier),
735 
736  EXPECT_EQ(g_call_records->len, 1u);
737  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
738  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
739  EXPECT_EQ(record->event->physical, kPhysicalCapsLock);
740  EXPECT_EQ(record->event->logical, kLogicalCapsLock);
741  EXPECT_STREQ(record->event->character, nullptr);
742  EXPECT_EQ(record->event->synthesized, false);
743 
745  g_ptr_array_clear(g_call_records);
746 
747  // Press key A (stage 3)
749  responder,
750  fl_key_event_new_by_mock(106, kPress, GDK_KEY_A, kKeyCodeKeyA,
751  GDK_LOCK_MASK, kIsNotModifier),
753 
754  EXPECT_EQ(g_call_records->len, 1u);
755  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
756  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
757  EXPECT_EQ(record->event->physical, kPhysicalKeyA);
758  EXPECT_EQ(record->event->logical, kLogicalKeyA);
759  EXPECT_STREQ(record->event->character, "A");
760  EXPECT_EQ(record->event->synthesized, false);
761 
763  g_ptr_array_clear(g_call_records);
764 
765  // Release CapsLock (stage 3 -> 0)
767  responder,
768  fl_key_event_new_by_mock(107, kRelease, GDK_KEY_Caps_Lock,
769  kKeyCodeCapsLock, GDK_LOCK_MASK, kIsModifier),
771 
772  EXPECT_EQ(g_call_records->len, 1u);
773  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
774  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
775  EXPECT_EQ(record->event->physical, kPhysicalCapsLock);
776  EXPECT_EQ(record->event->logical, kLogicalCapsLock);
777  EXPECT_STREQ(record->event->character, nullptr);
778  EXPECT_EQ(record->event->synthesized, false);
779 
781  g_ptr_array_clear(g_call_records);
782 
783  // Release key A (stage 0)
785  responder,
786  fl_key_event_new_by_mock(108, kRelease, GDK_KEY_a, kKeyCodeKeyA,
787  static_cast<GdkModifierType>(0), kIsNotModifier),
789 
790  EXPECT_EQ(g_call_records->len, 1u);
791  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
792  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
793  EXPECT_EQ(record->event->physical, kPhysicalKeyA);
794  EXPECT_EQ(record->event->logical, kLogicalKeyA);
795  EXPECT_STREQ(record->event->character, nullptr);
796  EXPECT_EQ(record->event->synthesized, false);
797 
799  g_ptr_array_clear(g_call_records);
800 
802  g_object_unref(responder);
803 }
804 
805 // Press or release letter key between presses/releases of CapsLock, on
806 // a platform with reversed logic.
807 //
808 // This happens when using a Chrome remote desktop on MacOS.
809 TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) {
810  EXPECT_EQ(g_call_records, nullptr);
811  g_call_records = g_ptr_array_new_with_free_func(g_object_unref);
812  FlKeyResponder* responder = FL_KEY_RESPONDER(
814  int user_data = 123; // Arbitrary user data
815 
816  FlKeyEmbedderCallRecord* record;
817 
818  // Press key A (stage 0)
820  responder,
821  fl_key_event_new_by_mock(101, kPress, GDK_KEY_a, kKeyCodeKeyA,
822  static_cast<GdkModifierType>(0), kIsNotModifier),
824 
825  EXPECT_EQ(g_call_records->len, 1u);
826  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
827  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
828  EXPECT_EQ(record->event->physical, kPhysicalKeyA);
829  EXPECT_EQ(record->event->logical, kLogicalKeyA);
830  EXPECT_STREQ(record->event->character, "a");
831  EXPECT_EQ(record->event->synthesized, false);
832 
834  g_ptr_array_clear(g_call_records);
835 
836  // Press CapsLock (stage 0 -> 1)
838  responder,
839  fl_key_event_new_by_mock(102, kPress, GDK_KEY_Caps_Lock, kKeyCodeCapsLock,
840  GDK_LOCK_MASK, kIsModifier),
842 
843  EXPECT_EQ(g_call_records->len, 1u);
844  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
845  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
846  EXPECT_EQ(record->event->physical, kPhysicalCapsLock);
847  EXPECT_EQ(record->event->logical, kLogicalCapsLock);
848  EXPECT_STREQ(record->event->character, nullptr);
849  EXPECT_EQ(record->event->synthesized, false);
850 
852  g_ptr_array_clear(g_call_records);
853 
854  // Release CapsLock (stage 1 -> 2)
856  responder,
857  fl_key_event_new_by_mock(103, kRelease, GDK_KEY_Caps_Lock,
858  kKeyCodeCapsLock, GDK_LOCK_MASK, kIsModifier),
860 
861  EXPECT_EQ(g_call_records->len, 1u);
862  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
863  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
864  EXPECT_EQ(record->event->physical, kPhysicalCapsLock);
865  EXPECT_EQ(record->event->logical, kLogicalCapsLock);
866  EXPECT_STREQ(record->event->character, nullptr);
867  EXPECT_EQ(record->event->synthesized, false);
868 
870  g_ptr_array_clear(g_call_records);
871 
872  // Release key A (stage 2)
874  responder,
875  fl_key_event_new_by_mock(104, kRelease, GDK_KEY_A, kKeyCodeKeyA,
876  GDK_LOCK_MASK, kIsNotModifier),
878 
879  EXPECT_EQ(g_call_records->len, 1u);
880  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
881  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
882  EXPECT_EQ(record->event->physical, kPhysicalKeyA);
883  EXPECT_EQ(record->event->logical, kLogicalKeyA);
884  EXPECT_STREQ(record->event->character, nullptr);
885  EXPECT_EQ(record->event->synthesized, false);
886 
888  g_ptr_array_clear(g_call_records);
889 
890  // Press key A (stage 2)
892  responder,
893  fl_key_event_new_by_mock(105, kPress, GDK_KEY_A, kKeyCodeKeyA,
894  GDK_LOCK_MASK, kIsNotModifier),
896 
897  EXPECT_EQ(g_call_records->len, 1u);
898  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
899  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
900  EXPECT_EQ(record->event->physical, kPhysicalKeyA);
901  EXPECT_EQ(record->event->logical, kLogicalKeyA);
902  EXPECT_STREQ(record->event->character, "A");
903  EXPECT_EQ(record->event->synthesized, false);
904 
906  g_ptr_array_clear(g_call_records);
907 
908  // Press CapsLock (stage 2 -> 3)
910  responder,
911  fl_key_event_new_by_mock(106, kPress, GDK_KEY_Caps_Lock, kKeyCodeCapsLock,
912  static_cast<GdkModifierType>(0), kIsModifier),
914 
915  EXPECT_EQ(g_call_records->len, 1u);
916  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
917  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
918  EXPECT_EQ(record->event->physical, kPhysicalCapsLock);
919  EXPECT_EQ(record->event->logical, kLogicalCapsLock);
920  EXPECT_STREQ(record->event->character, nullptr);
921  EXPECT_EQ(record->event->synthesized, false);
922 
924  g_ptr_array_clear(g_call_records);
925 
926  // Release CapsLock (stage 3 -> 0)
928  responder,
929  fl_key_event_new_by_mock(107, kRelease, GDK_KEY_Caps_Lock,
930  kKeyCodeCapsLock, GDK_LOCK_MASK, kIsModifier),
932 
933  EXPECT_EQ(g_call_records->len, 1u);
934  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
935  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
936  EXPECT_EQ(record->event->physical, kPhysicalCapsLock);
937  EXPECT_EQ(record->event->logical, kLogicalCapsLock);
938  EXPECT_STREQ(record->event->character, nullptr);
939  EXPECT_EQ(record->event->synthesized, false);
940 
942  g_ptr_array_clear(g_call_records);
943 
944  // Release key A (stage 0)
946  responder,
947  fl_key_event_new_by_mock(108, kRelease, GDK_KEY_a, kKeyCodeKeyA,
948  static_cast<GdkModifierType>(0), kIsNotModifier),
950 
951  EXPECT_EQ(g_call_records->len, 1u);
952  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
953  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
954  EXPECT_EQ(record->event->physical, kPhysicalKeyA);
955  EXPECT_EQ(record->event->logical, kLogicalKeyA);
956  EXPECT_STREQ(record->event->character, nullptr);
957  EXPECT_EQ(record->event->synthesized, false);
958 
960  g_ptr_array_clear(g_call_records);
961 
963  g_object_unref(responder);
964 }
965 
966 TEST(FlKeyEmbedderResponderTest, TurnDuplicateDownEventsToRepeats) {
967  EXPECT_EQ(g_call_records, nullptr);
968  g_call_records = g_ptr_array_new_with_free_func(g_object_unref);
969  FlKeyResponder* responder = FL_KEY_RESPONDER(
971  int user_data = 123; // Arbitrary user data
972 
973  FlKeyEmbedderCallRecord* record;
974 
975  // Press KeyA
977  responder,
978  fl_key_event_new_by_mock(101, kPress, GDK_KEY_a, kKeyCodeKeyA,
979  static_cast<GdkModifierType>(0), kIsNotModifier),
981 
982  EXPECT_EQ(g_call_records->len, 1u);
983 
984  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
986  g_ptr_array_clear(g_call_records);
987 
988  // Another KeyA down events, which usually means a repeated event.
989  g_expected_handled = false;
991  responder,
992  fl_key_event_new_by_mock(102, kPress, GDK_KEY_a, kKeyCodeKeyA,
993  static_cast<GdkModifierType>(0), kIsNotModifier),
995 
996  EXPECT_EQ(g_call_records->len, 1u);
997 
998  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
999  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeRepeat);
1000  EXPECT_EQ(record->event->physical, kPhysicalKeyA);
1001  EXPECT_EQ(record->event->logical, kLogicalKeyA);
1002  EXPECT_STREQ(record->event->character, "a");
1003  EXPECT_EQ(record->event->synthesized, false);
1004  EXPECT_NE(record->callback, nullptr);
1005 
1007  g_ptr_array_clear(g_call_records);
1008 
1009  // Release KeyA
1011  responder,
1012  fl_key_event_new_by_mock(103, kRelease, GDK_KEY_q, kKeyCodeKeyA,
1013  static_cast<GdkModifierType>(0), kIsNotModifier),
1015 
1016  EXPECT_EQ(g_call_records->len, 1u);
1017  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
1019  g_ptr_array_clear(g_call_records);
1020 
1022  g_object_unref(responder);
1023 }
1024 
1025 TEST(FlKeyEmbedderResponderTest, IgnoreAbruptUpEvent) {
1026  FlKeyEmbedderCallRecord* record;
1027 
1028  EXPECT_EQ(g_call_records, nullptr);
1029  g_call_records = g_ptr_array_new_with_free_func(g_object_unref);
1030  FlKeyResponder* responder = FL_KEY_RESPONDER(
1031  fl_key_embedder_responder_new(record_calls, g_call_records));
1032  int user_data = 123; // Arbitrary user data
1033 
1034  // Release KeyA before it was even pressed.
1035  g_expected_handled = true; // The empty event is always handled.
1037  responder,
1038  fl_key_event_new_by_mock(103, kRelease, GDK_KEY_q, kKeyCodeKeyA,
1039  static_cast<GdkModifierType>(0), kIsNotModifier),
1041 
1042  EXPECT_EQ(g_call_records->len, 1u);
1043 
1044  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
1045  EXPECT_EQ(record->event->physical, 0ull);
1046  EXPECT_EQ(record->event->logical, 0ull);
1047  EXPECT_STREQ(record->event->character, nullptr);
1048  EXPECT_EQ(record->event->synthesized, false);
1049  EXPECT_EQ(record->callback, nullptr);
1050 
1052  g_object_unref(responder);
1053 }
1054 
1055 // Test if missed modifier keys can be detected and synthesized with state
1056 // information upon events that are for this modifier key.
1057 TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) {
1058  EXPECT_EQ(g_call_records, nullptr);
1059  g_call_records = g_ptr_array_new_with_free_func(g_object_unref);
1060  FlKeyResponder* responder = FL_KEY_RESPONDER(
1061  fl_key_embedder_responder_new(record_calls, g_call_records));
1062  int user_data = 123; // Arbitrary user data
1063 
1064  FlKeyEmbedderCallRecord* record;
1065 
1066  // Test 1: synthesize key down.
1067 
1068  // A key down of control left is missed.
1069  GdkModifierType state = GDK_CONTROL_MASK;
1070 
1071  // Send a ControlLeft up
1073  responder,
1074  fl_key_event_new_by_mock(101, kRelease, GDK_KEY_Control_L,
1075  kKeyCodeControlLeft, state, kIsModifier),
1077 
1078  EXPECT_EQ(g_call_records->len, 2u);
1079  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
1080  EXPECT_EQ(record->event->timestamp, 101000);
1081  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1082  EXPECT_EQ(record->event->physical, kPhysicalControlLeft);
1083  EXPECT_EQ(record->event->logical, kLogicalControlLeft);
1084  EXPECT_STREQ(record->event->character, nullptr);
1085  EXPECT_EQ(record->event->synthesized, true);
1086 
1087  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 1));
1088  EXPECT_EQ(record->event->timestamp, 101000);
1089  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1090  EXPECT_EQ(record->event->physical, kPhysicalControlLeft);
1091  EXPECT_EQ(record->event->logical, kLogicalControlLeft);
1092  EXPECT_STREQ(record->event->character, nullptr);
1093  EXPECT_EQ(record->event->synthesized, false);
1094 
1096  g_ptr_array_clear(g_call_records);
1097 
1098  // Test 2: synthesize key up.
1099 
1100  // Send a ControlLeft down.
1101  state = static_cast<GdkModifierType>(0);
1103  responder,
1104  fl_key_event_new_by_mock(102, kPress, GDK_KEY_Control_L,
1105  kKeyCodeControlLeft, state, kIsModifier),
1107  EXPECT_EQ(g_call_records->len, 1u);
1108  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
1110  g_ptr_array_clear(g_call_records);
1111 
1112  // A key up of control left is missed.
1113  state = static_cast<GdkModifierType>(0);
1114 
1115  // Send another ControlLeft down
1117  responder,
1118  fl_key_event_new_by_mock(103, kPress, GDK_KEY_Control_L,
1119  kKeyCodeControlLeft, state, kIsModifier),
1121 
1122  EXPECT_EQ(g_call_records->len, 2u);
1123  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
1124  EXPECT_EQ(record->event->timestamp, 103000);
1125  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1126  EXPECT_EQ(record->event->physical, kPhysicalControlLeft);
1127  EXPECT_EQ(record->event->logical, kLogicalControlLeft);
1128  EXPECT_STREQ(record->event->character, nullptr);
1129  EXPECT_EQ(record->event->synthesized, true);
1130 
1131  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 1));
1132  EXPECT_EQ(record->event->timestamp, 103000);
1133  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1134  EXPECT_EQ(record->event->physical, kPhysicalControlLeft);
1135  EXPECT_EQ(record->event->logical, kLogicalControlLeft);
1136  EXPECT_STREQ(record->event->character, nullptr);
1137  EXPECT_EQ(record->event->synthesized, false);
1138 
1140  g_ptr_array_clear(g_call_records);
1141 
1142  // Send a ControlLeft up to clear up state.
1143  state = GDK_CONTROL_MASK;
1145  responder,
1146  fl_key_event_new_by_mock(104, kRelease, GDK_KEY_Control_L,
1147  kKeyCodeControlLeft, state, kIsModifier),
1149  EXPECT_EQ(g_call_records->len, 1u);
1150  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
1152  g_ptr_array_clear(g_call_records);
1153 
1154  // Test 3: synthesize by right modifier.
1155 
1156  // A key down of control right is missed.
1157  state = GDK_CONTROL_MASK;
1158 
1159  // Send a ControlRight up.
1161  responder,
1162  fl_key_event_new_by_mock(105, kRelease, GDK_KEY_Control_R,
1163  kKeyCodeControlRight, state, kIsModifier),
1165 
1166  // A ControlLeft down is synthesized, with an empty event.
1167  // Reason: The ControlLeft down is synthesized to synchronize the state
1168  // showing Control as pressed. The ControlRight event is ignored because
1169  // the event is considered a duplicate up event.
1170  EXPECT_EQ(g_call_records->len, 1u);
1171  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
1172  EXPECT_EQ(record->event->timestamp, 105000);
1173  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1174  EXPECT_EQ(record->event->physical, kPhysicalControlLeft);
1175  EXPECT_EQ(record->event->logical, kLogicalControlLeft);
1176  EXPECT_STREQ(record->event->character, nullptr);
1177  EXPECT_EQ(record->event->synthesized, true);
1178 
1179  g_ptr_array_clear(g_call_records);
1180 
1182  g_object_unref(responder);
1183 }
1184 
1185 // Test if missed modifier keys can be detected and synthesized with state
1186 // information upon events that are not for this modifier key.
1187 TEST(FlKeyEmbedderResponderTest,
1188  SynthesizeForDesyncPressingStateOnNonSelfEvents) {
1189  EXPECT_EQ(g_call_records, nullptr);
1190  g_call_records = g_ptr_array_new_with_free_func(g_object_unref);
1191  FlKeyResponder* responder = FL_KEY_RESPONDER(
1192  fl_key_embedder_responder_new(record_calls, g_call_records));
1193  int user_data = 123; // Arbitrary user data
1194 
1195  FlKeyEmbedderCallRecord* record;
1196 
1197  // A key down of control left is missed.
1198  GdkModifierType state = GDK_CONTROL_MASK;
1199 
1200  // Send a normal event (KeyA down)
1202  responder,
1203  fl_key_event_new_by_mock(101, kPress, GDK_KEY_a, kKeyCodeKeyA, state,
1204  kIsNotModifier),
1206 
1207  EXPECT_EQ(g_call_records->len, 2u);
1208  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
1209  EXPECT_EQ(record->event->timestamp, 101000);
1210  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1211  EXPECT_EQ(record->event->physical, kPhysicalControlLeft);
1212  EXPECT_EQ(record->event->logical, kLogicalControlLeft);
1213  EXPECT_STREQ(record->event->character, nullptr);
1214  EXPECT_EQ(record->event->synthesized, true);
1215 
1216  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 1));
1217  EXPECT_EQ(record->event->timestamp, 101000);
1218  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1219  EXPECT_EQ(record->event->physical, kPhysicalKeyA);
1220  EXPECT_EQ(record->event->logical, kLogicalKeyA);
1221  EXPECT_STREQ(record->event->character, "a");
1222  EXPECT_EQ(record->event->synthesized, false);
1223 
1225  g_ptr_array_clear(g_call_records);
1226 
1227  // A key up of control left is missed.
1228  state = static_cast<GdkModifierType>(0);
1229 
1230  // Send a normal event (KeyA up)
1232  responder,
1233  fl_key_event_new_by_mock(102, kRelease, GDK_KEY_A, kKeyCodeKeyA, state,
1234  kIsNotModifier),
1236 
1237  EXPECT_EQ(g_call_records->len, 2u);
1238  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
1239  EXPECT_EQ(record->event->timestamp, 102000);
1240  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1241  EXPECT_EQ(record->event->physical, kPhysicalControlLeft);
1242  EXPECT_EQ(record->event->logical, kLogicalControlLeft);
1243  EXPECT_STREQ(record->event->character, nullptr);
1244  EXPECT_EQ(record->event->synthesized, true);
1245 
1246  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 1));
1247  EXPECT_EQ(record->event->timestamp, 102000);
1248  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1249  EXPECT_EQ(record->event->physical, kPhysicalKeyA);
1250  EXPECT_EQ(record->event->logical, kLogicalKeyA);
1251  EXPECT_STREQ(record->event->character, nullptr);
1252  EXPECT_EQ(record->event->synthesized, false);
1253 
1255  g_ptr_array_clear(g_call_records);
1256 
1257  // Test non-default key mapping.
1258 
1259  // Press a key with physical CapsLock and logical ControlLeft.
1260  state = static_cast<GdkModifierType>(0);
1261 
1263  responder,
1264  fl_key_event_new_by_mock(101, kPress, GDK_KEY_Control_L, kKeyCodeCapsLock,
1265  state, kIsModifier),
1267 
1268  EXPECT_EQ(g_call_records->len, 1u);
1269  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
1270  EXPECT_EQ(record->event->timestamp, 101000);
1271  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1272  EXPECT_EQ(record->event->physical, kPhysicalCapsLock);
1273  EXPECT_EQ(record->event->logical, kLogicalControlLeft);
1274  EXPECT_STREQ(record->event->character, nullptr);
1275  EXPECT_EQ(record->event->synthesized, false);
1276 
1278  g_ptr_array_clear(g_call_records);
1279 
1280  // The key up of the control left press is missed.
1281  state = static_cast<GdkModifierType>(0);
1282 
1283  // Send a normal event (KeyA down).
1285  responder,
1286  fl_key_event_new_by_mock(102, kPress, GDK_KEY_A, kKeyCodeKeyA, state,
1287  kIsNotModifier),
1289 
1290  // The synthesized event should have physical CapsLock and logical
1291  // ControlLeft.
1292  EXPECT_EQ(g_call_records->len, 2u);
1293  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
1294  EXPECT_EQ(record->event->timestamp, 102000);
1295  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1296  EXPECT_EQ(record->event->physical, kPhysicalCapsLock);
1297  EXPECT_EQ(record->event->logical, kLogicalControlLeft);
1298  EXPECT_STREQ(record->event->character, nullptr);
1299  EXPECT_EQ(record->event->synthesized, true);
1300 
1301  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 1));
1302  EXPECT_EQ(record->event->timestamp, 102000);
1303  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1304  EXPECT_EQ(record->event->physical, kPhysicalKeyA);
1305  EXPECT_EQ(record->event->logical, kLogicalKeyA);
1306  EXPECT_STREQ(record->event->character, "A");
1307  EXPECT_EQ(record->event->synthesized, false);
1308 
1310  g_ptr_array_clear(g_call_records);
1311 
1313  g_object_unref(responder);
1314 }
1315 
1316 // Test if missed modifier keys can be detected and synthesized with state
1317 // information upon events that do not have the standard key mapping.
1318 TEST(FlKeyEmbedderResponderTest,
1319  SynthesizeForDesyncPressingStateOnRemappedEvents) {
1320  EXPECT_EQ(g_call_records, nullptr);
1321  g_call_records = g_ptr_array_new_with_free_func(g_object_unref);
1322  FlKeyResponder* responder = FL_KEY_RESPONDER(
1323  fl_key_embedder_responder_new(record_calls, g_call_records));
1324  int user_data = 123; // Arbitrary user data
1325 
1326  FlKeyEmbedderCallRecord* record;
1327 
1328  // Press a key with physical CapsLock and logical ControlLeft.
1329  GdkModifierType state = static_cast<GdkModifierType>(0);
1330 
1332  responder,
1333  fl_key_event_new_by_mock(101, kPress, GDK_KEY_Control_L, kKeyCodeCapsLock,
1334  state, kIsModifier),
1336 
1337  EXPECT_EQ(g_call_records->len, 1u);
1338  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
1339  EXPECT_EQ(record->event->timestamp, 101000);
1340  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1341  EXPECT_EQ(record->event->physical, kPhysicalCapsLock);
1342  EXPECT_EQ(record->event->logical, kLogicalControlLeft);
1343  EXPECT_STREQ(record->event->character, nullptr);
1344  EXPECT_EQ(record->event->synthesized, false);
1345 
1347  g_ptr_array_clear(g_call_records);
1348 
1349  // The key up of the control left press is missed.
1350  state = static_cast<GdkModifierType>(0);
1351 
1352  // Send a normal event (KeyA down).
1354  responder,
1355  fl_key_event_new_by_mock(102, kPress, GDK_KEY_A, kKeyCodeKeyA, state,
1356  kIsNotModifier),
1358 
1359  // The synthesized event should have physical CapsLock and logical
1360  // ControlLeft.
1361  EXPECT_EQ(g_call_records->len, 2u);
1362  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
1363  EXPECT_EQ(record->event->timestamp, 102000);
1364  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1365  EXPECT_EQ(record->event->physical, kPhysicalCapsLock);
1366  EXPECT_EQ(record->event->logical, kLogicalControlLeft);
1367  EXPECT_STREQ(record->event->character, nullptr);
1368  EXPECT_EQ(record->event->synthesized, true);
1369 
1370  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 1));
1371  EXPECT_EQ(record->event->timestamp, 102000);
1372  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1373  EXPECT_EQ(record->event->physical, kPhysicalKeyA);
1374  EXPECT_EQ(record->event->logical, kLogicalKeyA);
1375  EXPECT_STREQ(record->event->character, "A");
1376  EXPECT_EQ(record->event->synthesized, false);
1377 
1379  g_ptr_array_clear(g_call_records);
1380 
1382  g_object_unref(responder);
1383 }
1384 
1385 // Test if missed lock keys can be detected and synthesized with state
1386 // information upon events that are not for this modifier key.
1387 TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) {
1388  EXPECT_EQ(g_call_records, nullptr);
1389  g_call_records = g_ptr_array_new_with_free_func(g_object_unref);
1390  FlKeyResponder* responder = FL_KEY_RESPONDER(
1391  fl_key_embedder_responder_new(record_calls, g_call_records));
1392  int user_data = 123; // Arbitrary user data
1393 
1394  FlKeyEmbedderCallRecord* record;
1395 
1396  // The NumLock is desynchronized by being enabled.
1397  GdkModifierType state = GDK_MOD2_MASK;
1398 
1399  // Send a normal event
1401  responder,
1402  fl_key_event_new_by_mock(101, kPress, GDK_KEY_a, kKeyCodeKeyA, state,
1403  kIsNotModifier),
1405 
1406  EXPECT_EQ(g_call_records->len, 2u);
1407  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
1408  EXPECT_EQ(record->event->timestamp, 101000);
1409  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1410  EXPECT_EQ(record->event->physical, kPhysicalNumLock);
1411  EXPECT_EQ(record->event->logical, kLogicalNumLock);
1412  EXPECT_STREQ(record->event->character, nullptr);
1413  EXPECT_EQ(record->event->synthesized, true);
1414 
1415  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 1));
1416  EXPECT_EQ(record->event->timestamp, 101000);
1417  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1418  EXPECT_EQ(record->event->physical, kPhysicalKeyA);
1419  EXPECT_EQ(record->event->logical, kLogicalKeyA);
1420  EXPECT_STREQ(record->event->character, "a");
1421  EXPECT_EQ(record->event->synthesized, false);
1422 
1424  g_ptr_array_clear(g_call_records);
1425 
1426  // The NumLock is desynchronized by being disabled.
1427  state = static_cast<GdkModifierType>(0);
1428 
1429  // Release key A
1431  responder,
1432  fl_key_event_new_by_mock(102, kRelease, GDK_KEY_A, kKeyCodeKeyA, state,
1433  kIsNotModifier),
1435 
1436  EXPECT_EQ(g_call_records->len, 4u);
1437  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
1438  EXPECT_EQ(record->event->timestamp, 102000);
1439  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1440  EXPECT_EQ(record->event->physical, kPhysicalNumLock);
1441  EXPECT_EQ(record->event->logical, kLogicalNumLock);
1442  EXPECT_STREQ(record->event->character, nullptr);
1443  EXPECT_EQ(record->event->synthesized, true);
1444 
1445  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 1));
1446  EXPECT_EQ(record->event->timestamp, 102000);
1447  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1448  EXPECT_EQ(record->event->physical, kPhysicalNumLock);
1449  EXPECT_EQ(record->event->logical, kLogicalNumLock);
1450  EXPECT_STREQ(record->event->character, nullptr);
1451  EXPECT_EQ(record->event->synthesized, true);
1452 
1453  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 2));
1454  EXPECT_EQ(record->event->timestamp, 102000);
1455  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1456  EXPECT_EQ(record->event->physical, kPhysicalNumLock);
1457  EXPECT_EQ(record->event->logical, kLogicalNumLock);
1458  EXPECT_STREQ(record->event->character, nullptr);
1459  EXPECT_EQ(record->event->synthesized, true);
1460 
1461  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 3));
1462  EXPECT_EQ(record->event->timestamp, 102000);
1463  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1464  EXPECT_EQ(record->event->physical, kPhysicalKeyA);
1465  EXPECT_EQ(record->event->logical, kLogicalKeyA);
1466  EXPECT_STREQ(record->event->character, nullptr);
1467  EXPECT_EQ(record->event->synthesized, false);
1468 
1470  g_ptr_array_clear(g_call_records);
1471 
1472  // Release NumLock. Since the previous event should have synthesized NumLock
1473  // to be released, this should result in only an empty event.
1474  g_expected_handled = true;
1476  responder,
1477  fl_key_event_new_by_mock(103, kRelease, GDK_KEY_Num_Lock, kKeyCodeNumLock,
1478  state, kIsModifier),
1480 
1481  EXPECT_EQ(g_call_records->len, 1u);
1482  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
1483  EXPECT_EQ(record->event->physical, 0ull);
1484  EXPECT_EQ(record->event->logical, 0ull);
1485  EXPECT_STREQ(record->event->character, nullptr);
1486  EXPECT_EQ(record->event->synthesized, false);
1487  EXPECT_EQ(record->callback, nullptr);
1488 
1490  g_object_unref(responder);
1491 }
1492 
1493 // Test if missed lock keys can be detected and synthesized with state
1494 // information upon events that are for this modifier key.
1495 TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) {
1496  EXPECT_EQ(g_call_records, nullptr);
1497  g_call_records = g_ptr_array_new_with_free_func(g_object_unref);
1498  FlKeyResponder* responder = FL_KEY_RESPONDER(
1499  fl_key_embedder_responder_new(record_calls, g_call_records));
1500  int user_data = 123; // Arbitrary user data
1501 
1502  FlKeyEmbedderCallRecord* record;
1503 
1504  // The NumLock is desynchronized by being enabled.
1505  GdkModifierType state = GDK_MOD2_MASK;
1506 
1507  // NumLock down
1509  responder,
1510  fl_key_event_new_by_mock(101, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock,
1511  state, kIsModifier),
1513 
1514  EXPECT_EQ(g_call_records->len, 3u);
1515  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
1516  EXPECT_EQ(record->event->timestamp, 101000);
1517  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1518  EXPECT_EQ(record->event->physical, kPhysicalNumLock);
1519  EXPECT_EQ(record->event->logical, kLogicalNumLock);
1520  EXPECT_STREQ(record->event->character, nullptr);
1521  EXPECT_EQ(record->event->synthesized, true);
1522 
1523  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 1));
1524  EXPECT_EQ(record->event->timestamp, 101000);
1525  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1526  EXPECT_EQ(record->event->physical, kPhysicalNumLock);
1527  EXPECT_EQ(record->event->logical, kLogicalNumLock);
1528  EXPECT_STREQ(record->event->character, nullptr);
1529  EXPECT_EQ(record->event->synthesized, true);
1530 
1531  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 2));
1532  EXPECT_EQ(record->event->timestamp, 101000);
1533  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1534  EXPECT_EQ(record->event->physical, kPhysicalNumLock);
1535  EXPECT_EQ(record->event->logical, kLogicalNumLock);
1536  EXPECT_STREQ(record->event->character, nullptr);
1537  EXPECT_EQ(record->event->synthesized, false);
1538 
1540  g_ptr_array_clear(g_call_records);
1541 
1542  // The NumLock is desynchronized by being enabled in a press event.
1543  state = GDK_MOD2_MASK;
1544 
1545  // NumLock up
1547  responder,
1548  fl_key_event_new_by_mock(102, kPress, GDK_KEY_Num_Lock, kKeyCodeNumLock,
1549  state, kIsModifier),
1551 
1552  EXPECT_EQ(g_call_records->len, 4u);
1553  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
1554  EXPECT_EQ(record->event->timestamp, 102000);
1555  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1556  EXPECT_EQ(record->event->physical, kPhysicalNumLock);
1557  EXPECT_EQ(record->event->logical, kLogicalNumLock);
1558  EXPECT_STREQ(record->event->character, nullptr);
1559  EXPECT_EQ(record->event->synthesized, true);
1560 
1561  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 1));
1562  EXPECT_EQ(record->event->timestamp, 102000);
1563  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1564  EXPECT_EQ(record->event->physical, kPhysicalNumLock);
1565  EXPECT_EQ(record->event->logical, kLogicalNumLock);
1566  EXPECT_STREQ(record->event->character, nullptr);
1567  EXPECT_EQ(record->event->synthesized, true);
1568 
1569  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 2));
1570  EXPECT_EQ(record->event->timestamp, 102000);
1571  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1572  EXPECT_EQ(record->event->physical, kPhysicalNumLock);
1573  EXPECT_EQ(record->event->logical, kLogicalNumLock);
1574  EXPECT_STREQ(record->event->character, nullptr);
1575  EXPECT_EQ(record->event->synthesized, true);
1576 
1577  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 3));
1578  EXPECT_EQ(record->event->timestamp, 102000);
1579  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1580  EXPECT_EQ(record->event->physical, kPhysicalNumLock);
1581  EXPECT_EQ(record->event->logical, kLogicalNumLock);
1582  EXPECT_STREQ(record->event->character, nullptr);
1583  EXPECT_EQ(record->event->synthesized, false);
1584 
1586  g_ptr_array_clear(g_call_records);
1587 
1589  g_object_unref(responder);
1590 }
1591 
1592 // Ensures that even if the primary event is ignored (due to duplicate
1593 // key up or down events), key synthesization is still performed.
1594 TEST(FlKeyEmbedderResponderTest, SynthesizationOccursOnIgnoredEvents) {
1595  EXPECT_EQ(g_call_records, nullptr);
1596  g_call_records = g_ptr_array_new_with_free_func(g_object_unref);
1597  FlKeyResponder* responder = FL_KEY_RESPONDER(
1598  fl_key_embedder_responder_new(record_calls, g_call_records));
1599  int user_data = 123; // Arbitrary user data
1600 
1601  FlKeyEmbedderCallRecord* record;
1602 
1603  // The NumLock is desynchronized by being enabled, and Control is pressed.
1604  GdkModifierType state =
1605  static_cast<GdkModifierType>(GDK_MOD2_MASK | GDK_CONTROL_MASK);
1606 
1607  // Send a KeyA up event, which will be ignored.
1608  g_expected_handled = true; // The ignored event is always handled.
1610  responder,
1611  fl_key_event_new_by_mock(101, kRelease, GDK_KEY_a, kKeyCodeKeyA, state,
1612  kIsNotModifier),
1614 
1615  EXPECT_EQ(g_call_records->len, 2u);
1616  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
1617  EXPECT_EQ(record->event->timestamp, 101000);
1618  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1619  EXPECT_EQ(record->event->physical, kPhysicalNumLock);
1620  EXPECT_EQ(record->event->logical, kLogicalNumLock);
1621  EXPECT_STREQ(record->event->character, nullptr);
1622  EXPECT_EQ(record->event->synthesized, true);
1623 
1624  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 1));
1625  EXPECT_EQ(record->event->timestamp, 101000);
1626  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1627  EXPECT_EQ(record->event->physical, kPhysicalControlLeft);
1628  EXPECT_EQ(record->event->logical, kLogicalControlLeft);
1629  EXPECT_STREQ(record->event->character, nullptr);
1630  EXPECT_EQ(record->event->synthesized, true);
1631 
1632  g_ptr_array_clear(g_call_records);
1633 
1635  g_object_unref(responder);
1636 }
1637 
1638 // This test case occurs when the following two cases collide:
1639 //
1640 // 1. When holding shift, AltRight key gives logical GDK_KEY_Meta_R with the
1641 // state bitmask still MOD3 (Alt).
1642 // 2. When holding AltRight, ShiftLeft key gives logical GDK_KEY_ISO_Next_Group
1643 // with the state bitmask RESERVED_14.
1644 //
1645 // The resulting event sequence is not perfectly ideal: it had to synthesize
1646 // AltLeft down because the physical AltRight key corresponds to logical
1647 // MetaRight at the moment.
1648 TEST(FlKeyEmbedderResponderTest, HandlesShiftAltVersusGroupNext) {
1649  EXPECT_EQ(g_call_records, nullptr);
1650  g_call_records = g_ptr_array_new_with_free_func(g_object_unref);
1651  FlKeyResponder* responder = FL_KEY_RESPONDER(
1652  fl_key_embedder_responder_new(record_calls, g_call_records));
1653 
1654  g_expected_handled = true;
1655  guint32 now_time = 1;
1656  // A convenient shorthand to simulate events.
1657  auto send_key_event = [responder, &now_time](bool is_press, guint keyval,
1658  guint16 keycode,
1659  GdkModifierType state) {
1660  now_time += 1;
1661  int user_data = 123; // Arbitrary user data
1663  responder,
1664  fl_key_event_new_by_mock(now_time, is_press, keyval, keycode, state,
1665  kIsModifier),
1667  };
1668 
1669  FlKeyEmbedderCallRecord* record;
1670 
1671  send_key_event(kPress, GDK_KEY_Shift_L, kKeyCodeShiftLeft,
1672  GDK_MODIFIER_RESERVED_25_MASK);
1673  EXPECT_EQ(g_call_records->len, 1u);
1674  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
1675  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1676  EXPECT_EQ(record->event->physical, kPhysicalShiftLeft);
1677  EXPECT_EQ(record->event->logical, kLogicalShiftLeft);
1678  EXPECT_EQ(record->event->synthesized, false);
1679 
1680  send_key_event(kPress, GDK_KEY_Meta_R, kKeyCodeAltRight,
1681  static_cast<GdkModifierType>(GDK_SHIFT_MASK |
1682  GDK_MODIFIER_RESERVED_25_MASK));
1683  EXPECT_EQ(g_call_records->len, 2u);
1684  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 1));
1685  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1686  EXPECT_EQ(record->event->physical, kPhysicalAltRight);
1687  EXPECT_EQ(record->event->logical, kLogicalMetaRight);
1688  EXPECT_EQ(record->event->synthesized, false);
1689 
1690  send_key_event(kRelease, GDK_KEY_ISO_Next_Group, kKeyCodeShiftLeft,
1691  static_cast<GdkModifierType>(GDK_SHIFT_MASK | GDK_MOD1_MASK |
1692  GDK_MODIFIER_RESERVED_25_MASK));
1693  EXPECT_EQ(g_call_records->len, 5u);
1694  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 2));
1695  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1696  EXPECT_EQ(record->event->physical, kPhysicalAltLeft);
1697  EXPECT_EQ(record->event->logical, kLogicalAltLeft);
1698  EXPECT_EQ(record->event->synthesized, true);
1699 
1700  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 3));
1701  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1702  EXPECT_EQ(record->event->physical, kPhysicalAltRight);
1703  EXPECT_EQ(record->event->logical, kLogicalMetaRight);
1704  EXPECT_EQ(record->event->synthesized, true);
1705 
1706  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 4));
1707  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1708  EXPECT_EQ(record->event->physical, kPhysicalShiftLeft);
1709  EXPECT_EQ(record->event->logical, kLogicalShiftLeft);
1710  EXPECT_EQ(record->event->synthesized, false);
1711 
1712  send_key_event(kPress, GDK_KEY_ISO_Next_Group, kKeyCodeShiftLeft,
1713  static_cast<GdkModifierType>(GDK_MOD1_MASK |
1714  GDK_MODIFIER_RESERVED_25_MASK));
1715  EXPECT_EQ(g_call_records->len, 6u);
1716  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 5));
1717  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1718  EXPECT_EQ(record->event->physical, kPhysicalShiftLeft);
1719  EXPECT_EQ(record->event->logical, kLogicalGroupNext);
1720  EXPECT_EQ(record->event->synthesized, false);
1721 
1722  send_key_event(kRelease, GDK_KEY_ISO_Level3_Shift, kKeyCodeAltRight,
1723  static_cast<GdkModifierType>(GDK_MOD1_MASK |
1724  GDK_MODIFIER_RESERVED_13_MASK |
1725  GDK_MODIFIER_RESERVED_25_MASK));
1726  EXPECT_EQ(g_call_records->len, 7u);
1727  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 6));
1728  EXPECT_EQ(record->event->physical, 0u);
1729  EXPECT_EQ(record->event->logical, 0u);
1730 
1731  send_key_event(kRelease, GDK_KEY_Shift_L, kKeyCodeShiftLeft,
1732  static_cast<GdkModifierType>(GDK_MODIFIER_RESERVED_13_MASK |
1733  GDK_MODIFIER_RESERVED_25_MASK));
1734  EXPECT_EQ(g_call_records->len, 9u);
1735  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 7));
1736  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1737  EXPECT_EQ(record->event->physical, kPhysicalAltLeft);
1738  EXPECT_EQ(record->event->logical, kLogicalAltLeft);
1739  EXPECT_EQ(record->event->synthesized, true);
1740 
1741  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 8));
1742  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1743  EXPECT_EQ(record->event->physical, kPhysicalShiftLeft);
1744  EXPECT_EQ(record->event->logical, kLogicalGroupNext);
1745  EXPECT_EQ(record->event->synthesized, false);
1746 
1748  g_object_unref(responder);
1749 }
1750 
1751 // Shift + AltLeft results in GDK event whose keyval is MetaLeft but whose
1752 // keycode is either AltLeft or Shift keycode (depending on which one was
1753 // released last). The physical key is usually deduced from the keycode, but in
1754 // this case (Shift + AltLeft) a correction is needed otherwise the physical
1755 // key won't be the MetaLeft one.
1756 // Regression test for https://github.com/flutter/flutter/issues/96082
1757 TEST(FlKeyEmbedderResponderTest, HandlesShiftAltLeftIsMetaLeft) {
1758  EXPECT_EQ(g_call_records, nullptr);
1759  g_call_records = g_ptr_array_new_with_free_func(g_object_unref);
1760  FlKeyResponder* responder = FL_KEY_RESPONDER(
1761  fl_key_embedder_responder_new(record_calls, g_call_records));
1762 
1763  g_expected_handled = true;
1764  guint32 now_time = 1;
1765  // A convenient shorthand to simulate events.
1766  auto send_key_event = [responder, &now_time](bool is_press, guint keyval,
1767  guint16 keycode,
1768  GdkModifierType state) {
1769  now_time += 1;
1770  int user_data = 123; // Arbitrary user data
1772  responder,
1773  fl_key_event_new_by_mock(now_time, is_press, keyval, keycode, state,
1774  kIsModifier),
1776  };
1777 
1778  FlKeyEmbedderCallRecord* record;
1779 
1780  // ShiftLeft + AltLeft
1781  send_key_event(kPress, GDK_KEY_Shift_L, kKeyCodeShiftLeft,
1782  GDK_MODIFIER_RESERVED_25_MASK);
1783  EXPECT_EQ(g_call_records->len, 1u);
1784  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
1785  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1786  EXPECT_EQ(record->event->physical, kPhysicalShiftLeft);
1787  EXPECT_EQ(record->event->logical, kLogicalShiftLeft);
1788  EXPECT_EQ(record->event->synthesized, false);
1789 
1790  send_key_event(kPress, GDK_KEY_Meta_L, kKeyCodeAltLeft,
1791  static_cast<GdkModifierType>(GDK_SHIFT_MASK |
1792  GDK_MODIFIER_RESERVED_25_MASK));
1793  EXPECT_EQ(g_call_records->len, 2u);
1794  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 1));
1795  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1796  EXPECT_EQ(record->event->physical, kPhysicalMetaLeft);
1797  EXPECT_EQ(record->event->logical, kLogicalMetaLeft);
1798  EXPECT_EQ(record->event->synthesized, false);
1799 
1800  send_key_event(kRelease, GDK_KEY_Meta_L, kKeyCodeAltLeft,
1801  static_cast<GdkModifierType>(GDK_MODIFIER_RESERVED_13_MASK |
1802  GDK_MODIFIER_RESERVED_25_MASK));
1803  send_key_event(kRelease, GDK_KEY_Shift_L, kKeyCodeShiftLeft,
1804  GDK_MODIFIER_RESERVED_25_MASK);
1805  g_ptr_array_clear(g_call_records);
1806 
1807  // ShiftRight + AltLeft
1808  send_key_event(kPress, GDK_KEY_Shift_R, kKeyCodeShiftRight,
1809  GDK_MODIFIER_RESERVED_25_MASK);
1810  EXPECT_EQ(g_call_records->len, 1u);
1811  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 0));
1812  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1813  EXPECT_EQ(record->event->physical, kPhysicalShiftRight);
1814  EXPECT_EQ(record->event->logical, kLogicalShiftRight);
1815  EXPECT_EQ(record->event->synthesized, false);
1816 
1817  send_key_event(kPress, GDK_KEY_Meta_L, kKeyCodeAltLeft,
1818  static_cast<GdkModifierType>(GDK_SHIFT_MASK |
1819  GDK_MODIFIER_RESERVED_25_MASK));
1820  EXPECT_EQ(g_call_records->len, 2u);
1821  record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(g_call_records, 1));
1822  EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1823  EXPECT_EQ(record->event->physical, kPhysicalMetaLeft);
1824  EXPECT_EQ(record->event->logical, kLogicalMetaLeft);
1825  EXPECT_EQ(record->event->synthesized, false);
1826 
1828  g_object_unref(responder);
1829 }
event
FlKeyEvent * event
Definition: fl_key_channel_responder.cc:118
fl_key_embedder_responder.h
clear_g_call_records
static void clear_g_call_records()
Definition: fl_key_embedder_responder_test.cc:162
user_data
FlKeyEvent uint64_t FlKeyResponderAsyncCallback gpointer user_data
Definition: fl_key_channel_responder.cc:121
fl_key_embedder_call_record_class_init
static void fl_key_embedder_call_record_class_init(FlKeyEmbedderCallRecordClass *klass)
Definition: fl_key_embedder_responder_test.cc:74
_FlKeyEvent
Definition: fl_key_event.h:22
state
AtkStateType state
Definition: fl_accessible_node.cc:10
_FlKeyEmbedderCallRecord::event
FlutterKeyEvent * event
Definition: fl_key_embedder_responder_test.cc:50
record_calls
static void record_calls(const FlutterKeyEvent *event, FlutterKeyEventCallback callback, void *callback_user_data, void *send_key_event_user_data)
Definition: fl_key_embedder_responder_test.cc:150
fl_key_embedder_responder_new
FlKeyEmbedderResponder * fl_key_embedder_responder_new(EmbedderSendKeyEvent send_key_event, void *send_key_event_user_data)
Definition: fl_key_embedder_responder.cc:263
fl_key_event_new_by_mock
static FlKeyEvent * fl_key_event_new_by_mock(guint32 time_in_milliseconds, bool is_press, guint keyval, guint16 keycode, GdkModifierType state, gboolean is_modifier)
Definition: fl_key_embedder_responder_test.cc:115
fl_key_responder_handle_event
void fl_key_responder_handle_event(FlKeyResponder *self, FlKeyEvent *event, FlKeyResponderAsyncCallback callback, gpointer user_data, uint64_t specified_logical_key)
Definition: fl_key_responder.cc:11
_FlKeyEmbedderCallRecord::callback
FlutterKeyEventCallback callback
Definition: fl_key_embedder_responder_test.cc:51
_FlKeyEmbedderCallRecord::parent_instance
GObject parent_instance
Definition: fl_key_embedder_responder_test.cc:48
fl_engine_private.h
_FlKeyEvent::is_press
bool is_press
Definition: fl_key_event.h:26
TRUE
return TRUE
Definition: fl_pixel_buffer_texture_test.cc:53
_FlKeyEmbedderCallRecord
Definition: fl_key_embedder_responder_test.cc:47
fl_key_embedder_call_record_dispose
static void fl_key_embedder_call_record_dispose(GObject *object)
Definition: fl_key_embedder_responder_test.cc:62
G_DEFINE_TYPE
G_DEFINE_TYPE(FlKeyEmbedderCallRecord, fl_key_embedder_call_record, G_TYPE_OBJECT) static void fl_key_embedder_call_record_init(FlKeyEmbedderCallRecord *self)
Definition: fl_key_embedder_responder_test.cc:55
FL
FL
Definition: fl_binary_messenger.cc:27
fl_key_embedder_call_record_new
static FlKeyEmbedderCallRecord * fl_key_embedder_call_record_new(const FlutterKeyEvent *event, FlutterKeyEventCallback callback, gpointer user_data)
Definition: fl_key_embedder_responder_test.cc:79
fl_binary_messenger_private.h
_FlKeyEmbedderCallRecord::user_data
gpointer user_data
Definition: fl_key_embedder_responder_test.cc:52
g_expected_handled
static gboolean g_expected_handled
Definition: fl_key_embedder_responder_test.cc:130
invoke_record_callback_and_verify
static void invoke_record_callback_and_verify(FlKeyEmbedderCallRecord *record, bool expected_handled, void *expected_user_data)
Definition: fl_key_embedder_responder_test.cc:137
g_ptr_array_clear
static void g_ptr_array_clear(GPtrArray *array)
Definition: fl_key_embedder_responder_test.cc:37
g_expected_user_data
static gpointer g_expected_user_data
Definition: fl_key_embedder_responder_test.cc:131
verify_response_handled
static void verify_response_handled(bool handled, gpointer user_data)
Definition: fl_key_embedder_responder_test.cc:133
G_DECLARE_FINAL_TYPE
G_DECLARE_FINAL_TYPE(FlKeyEmbedderCallRecord, fl_key_embedder_call_record, FL, KEY_EMBEDDER_CALL_RECORD, GObject)
send_key_event
static void send_key_event(FlTextInputPlugin *plugin, gint keyval, gint state=0)
Definition: fl_text_input_plugin_test.cc:181
callback
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
Definition: fl_key_channel_responder.cc:120
TEST
TEST(FlKeyEmbedderResponderTest, SendKeyEvent)
Definition: fl_key_embedder_responder_test.cc:168
expected_handled
static gboolean expected_handled
Definition: fl_key_channel_responder_test.cc:14