Flutter Engine
 
Loading...
Searching...
No Matches
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
13
14namespace {
15constexpr gboolean kRelease = FALSE;
16constexpr gboolean kPress = TRUE;
17
18constexpr guint16 kKeyCodeDigit1 = 0x0au;
19constexpr guint16 kKeyCodeKeyA = 0x26u;
20constexpr guint16 kKeyCodeShiftLeft = 0x32u;
21constexpr guint16 kKeyCodeShiftRight = 0x3Eu;
22constexpr guint16 kKeyCodeAltLeft = 0x40u;
23constexpr guint16 kKeyCodeAltRight = 0x6Cu;
24constexpr guint16 kKeyCodeNumpad1 = 0x57u;
25constexpr guint16 kKeyCodeNumLock = 0x4Du;
26constexpr guint16 kKeyCodeCapsLock = 0x42u;
27constexpr guint16 kKeyCodeControlLeft = 0x25u;
28constexpr guint16 kKeyCodeControlRight = 0x69u;
29
30using namespace ::flutter::testing::keycodes;
31} // namespace
32
33static void clear_records(GPtrArray* array) {
34 g_ptr_array_remove_range(array, 0, array->len);
35}
36
37G_DECLARE_FINAL_TYPE(FlKeyEmbedderCallRecord,
38 fl_key_embedder_call_record,
39 FL,
40 KEY_EMBEDDER_CALL_RECORD,
41 GObject);
42
50
51G_DEFINE_TYPE(FlKeyEmbedderCallRecord,
52 fl_key_embedder_call_record,
53 G_TYPE_OBJECT)
54
55static void fl_key_embedder_call_record_init(FlKeyEmbedderCallRecord* self) {}
56
57// Dispose method for FlKeyEmbedderCallRecord.
58static void fl_key_embedder_call_record_dispose(GObject* object) {
59 g_return_if_fail(FL_IS_KEY_EMBEDDER_CALL_RECORD(object));
60
61 FlKeyEmbedderCallRecord* self = FL_KEY_EMBEDDER_CALL_RECORD(object);
62 if (self->event != nullptr) {
63 g_free(const_cast<char*>(self->event->character));
64 g_free(self->event);
65 }
66 G_OBJECT_CLASS(fl_key_embedder_call_record_parent_class)->dispose(object);
67}
68
69// Class Initialization method for FlKeyEmbedderCallRecord class.
71 FlKeyEmbedderCallRecordClass* klass) {
72 G_OBJECT_CLASS(klass)->dispose = fl_key_embedder_call_record_dispose;
73}
74
75static FlKeyEmbedderCallRecord* fl_key_embedder_call_record_new(
76 const FlutterKeyEvent* event,
78 gpointer user_data) {
79 g_return_val_if_fail(event != nullptr, nullptr);
80
81 FlKeyEmbedderCallRecord* self = FL_KEY_EMBEDDER_CALL_RECORD(
82 g_object_new(fl_key_embedder_call_record_get_type(), nullptr));
83
84 FlutterKeyEvent* clone_event = g_new(FlutterKeyEvent, 1);
85 *clone_event = *event;
86 if (event->character != nullptr) {
87 size_t character_length = strlen(event->character);
88 char* clone_character = g_new(char, character_length + 1);
89 strncpy(clone_character, event->character, character_length + 1);
90 clone_event->character = clone_character;
91 }
92 self->event = clone_event;
93 self->callback = callback;
94 self->user_data = user_data;
95
96 return self;
97}
98
99static void invoke_record_callback(FlKeyEmbedderCallRecord* record,
100 bool expected_handled) {
101 g_return_if_fail(record->callback != nullptr);
102 record->callback(expected_handled, record->user_data);
103}
104
105// Basic key presses
106TEST(FlKeyEmbedderResponderTest, SendKeyEvent) {
107 g_autoptr(FlDartProject) project = fl_dart_project_new();
108 g_autoptr(FlEngine) engine = fl_engine_new(project);
109 EXPECT_TRUE(fl_engine_start(engine, nullptr));
110
111 g_autoptr(FlKeyEmbedderResponder) responder =
113
114 g_autoptr(GPtrArray) call_records =
115 g_ptr_array_new_with_free_func(g_object_unref);
117 SendKeyEvent,
118 ([&call_records](auto engine, const FlutterKeyEvent* event,
120 g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
121 event, callback, user_data));
122 return kSuccess;
123 }));
124
125 // On a QWERTY keyboard, press key Q (physically key A), and release.
126 // Key down
127 g_autoptr(FlKeyEvent) event1 =
128 fl_key_event_new(12345, kPress, kKeyCodeKeyA, GDK_KEY_a,
129 static_cast<GdkModifierType>(0), 0);
130 g_autoptr(GMainLoop) loop1 = g_main_loop_new(nullptr, 0);
132 responder, event1, 0, nullptr,
133 [](GObject* object, GAsyncResult* result, gpointer user_data) {
134 gboolean handled;
136 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
137 EXPECT_EQ(handled, TRUE);
138
139 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
140 },
141 loop1);
142
143 EXPECT_EQ(call_records->len, 1u);
144 FlKeyEmbedderCallRecord* record =
145 FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
146 EXPECT_EQ(record->event->struct_size, sizeof(FlutterKeyEvent));
147 EXPECT_EQ(record->event->timestamp, 12345000);
148 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
149 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
150 EXPECT_EQ(record->event->logical, kLogicalKeyA);
151 EXPECT_STREQ(record->event->character, "a");
152 EXPECT_EQ(record->event->synthesized, false);
153
155 g_main_loop_run(loop1);
156 clear_records(call_records);
157
158 // Key up
159 g_autoptr(FlKeyEvent) event2 =
160 fl_key_event_new(12346, kRelease, kKeyCodeKeyA, GDK_KEY_a,
161 static_cast<GdkModifierType>(0), 0);
162 g_autoptr(GMainLoop) loop2 = g_main_loop_new(nullptr, 0);
164 responder, event2, 0, nullptr,
165 [](GObject* object, GAsyncResult* result, gpointer user_data) {
166 gboolean handled;
168 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
169 EXPECT_EQ(handled, FALSE);
170
171 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
172 },
173 loop2);
174
175 EXPECT_EQ(call_records->len, 1u);
176 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
177 EXPECT_EQ(record->event->struct_size, sizeof(FlutterKeyEvent));
178 EXPECT_EQ(record->event->timestamp, 12346000);
179 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
180 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
181 EXPECT_EQ(record->event->logical, kLogicalKeyA);
182 EXPECT_STREQ(record->event->character, nullptr);
183 EXPECT_EQ(record->event->synthesized, false);
184
185 invoke_record_callback(record, FALSE);
186 g_main_loop_run(loop2);
187 clear_records(call_records);
188
189 // On an AZERTY keyboard, press key Q (physically key A), and release.
190 // Key down
191 g_autoptr(FlKeyEvent) event3 =
192 fl_key_event_new(12347, kPress, kKeyCodeKeyA, GDK_KEY_q,
193 static_cast<GdkModifierType>(0), 0);
194 g_autoptr(GMainLoop) loop3 = g_main_loop_new(nullptr, 0);
196 responder, event3, 0, nullptr,
197 [](GObject* object, GAsyncResult* result, gpointer user_data) {
198 gboolean handled;
200 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
201 EXPECT_EQ(handled, TRUE);
202
203 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
204 },
205 loop3);
206
207 EXPECT_EQ(call_records->len, 1u);
208 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
209 EXPECT_EQ(record->event->struct_size, sizeof(FlutterKeyEvent));
210 EXPECT_EQ(record->event->timestamp, 12347000);
211 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
212 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
213 EXPECT_EQ(record->event->logical, kLogicalKeyQ);
214 EXPECT_STREQ(record->event->character, "q");
215 EXPECT_EQ(record->event->synthesized, false);
216
218 g_main_loop_run(loop3);
219 clear_records(call_records);
220
221 // Key up
222 g_autoptr(FlKeyEvent) event4 =
223 fl_key_event_new(12348, kRelease, kKeyCodeKeyA, GDK_KEY_q,
224 static_cast<GdkModifierType>(0), 0);
225 g_autoptr(GMainLoop) loop4 = g_main_loop_new(nullptr, 0);
227 responder, event4, 0, nullptr,
228 [](GObject* object, GAsyncResult* result, gpointer user_data) {
229 gboolean handled;
231 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
232 EXPECT_EQ(handled, FALSE);
233
234 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
235 },
236 loop4);
237
238 EXPECT_EQ(call_records->len, 1u);
239 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
240 EXPECT_EQ(record->event->struct_size, sizeof(FlutterKeyEvent));
241 EXPECT_EQ(record->event->timestamp, 12348000);
242 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
243 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
244 EXPECT_EQ(record->event->logical, kLogicalKeyQ);
245 EXPECT_STREQ(record->event->character, nullptr);
246 EXPECT_EQ(record->event->synthesized, false);
247
248 invoke_record_callback(record, FALSE);
249 g_main_loop_run(loop4);
250}
251
252// Basic key presses, but uses the specified logical key if it is not 0.
253TEST(FlKeyEmbedderResponderTest, UsesSpecifiedLogicalKey) {
254 g_autoptr(FlDartProject) project = fl_dart_project_new();
255 g_autoptr(FlEngine) engine = fl_engine_new(project);
256 EXPECT_TRUE(fl_engine_start(engine, nullptr));
257
258 g_autoptr(FlKeyEmbedderResponder) responder =
260
261 g_autoptr(GPtrArray) call_records =
262 g_ptr_array_new_with_free_func(g_object_unref);
264 SendKeyEvent,
265 ([&call_records](auto engine, const FlutterKeyEvent* event,
267 g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
268 event, callback, user_data));
269 return kSuccess;
270 }));
271
272 // On an AZERTY keyboard, press physical key 1, and release.
273 // Key down
274 g_autoptr(FlKeyEvent) event =
275 fl_key_event_new(12345, kPress, kKeyCodeDigit1, GDK_KEY_ampersand,
276 static_cast<GdkModifierType>(0), 0);
277 g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
279 responder, event, kLogicalDigit1, nullptr,
280 [](GObject* object, GAsyncResult* result, gpointer user_data) {
281 gboolean handled;
283 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
284 EXPECT_EQ(handled, TRUE);
285
286 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
287 },
288 loop);
289
290 EXPECT_EQ(call_records->len, 1u);
291 FlKeyEmbedderCallRecord* record =
292 FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
293 EXPECT_EQ(record->event->struct_size, sizeof(FlutterKeyEvent));
294 EXPECT_EQ(record->event->timestamp, 12345000);
295 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
296 EXPECT_EQ(record->event->physical, kPhysicalDigit1);
297 EXPECT_EQ(record->event->logical, kLogicalDigit1);
298 EXPECT_STREQ(record->event->character, "&");
299 EXPECT_EQ(record->event->synthesized, false);
300
302 g_main_loop_run(loop);
303}
304
305// Press Shift, key A, then release Shift, key A.
306TEST(FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap) {
307 g_autoptr(FlDartProject) project = fl_dart_project_new();
308 g_autoptr(FlEngine) engine = fl_engine_new(project);
309 EXPECT_TRUE(fl_engine_start(engine, nullptr));
310
311 g_autoptr(FlKeyEmbedderResponder) responder =
313
314 g_autoptr(GPtrArray) call_records =
315 g_ptr_array_new_with_free_func(g_object_unref);
317 SendKeyEvent,
318 ([&call_records](auto engine, const FlutterKeyEvent* event,
320 g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
321 event, callback, user_data));
322 return kSuccess;
323 }));
324
325 // Press shift right
326 g_autoptr(FlKeyEvent) event1 =
327 fl_key_event_new(101, kPress, kKeyCodeShiftRight, GDK_KEY_Shift_R,
328 static_cast<GdkModifierType>(0), 0);
329 g_autoptr(GMainLoop) loop1 = g_main_loop_new(nullptr, 0);
331 responder, event1, 0, nullptr,
332 [](GObject* object, GAsyncResult* result, gpointer user_data) {
333 gboolean handled;
335 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
336 EXPECT_EQ(handled, TRUE);
337
338 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
339 },
340 loop1);
341
342 EXPECT_EQ(call_records->len, 1u);
343 FlKeyEmbedderCallRecord* record =
344 FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
345 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
346 EXPECT_EQ(record->event->physical, kPhysicalShiftRight);
347 EXPECT_EQ(record->event->logical, kLogicalShiftRight);
348 EXPECT_STREQ(record->event->character, nullptr);
349 EXPECT_EQ(record->event->synthesized, false);
350
352 g_main_loop_run(loop1);
353 clear_records(call_records);
354
355 // Press key A
356 g_autoptr(FlKeyEvent) event2 =
357 fl_key_event_new(102, kPress, kKeyCodeKeyA, GDK_KEY_A, GDK_SHIFT_MASK, 0);
358 g_autoptr(GMainLoop) loop2 = g_main_loop_new(nullptr, 0);
360 responder, event2, 0, nullptr,
361 [](GObject* object, GAsyncResult* result, gpointer user_data) {
362 gboolean handled;
364 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
365 EXPECT_EQ(handled, TRUE);
366
367 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
368 },
369 loop2);
370
371 EXPECT_EQ(call_records->len, 1u);
372 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
373 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
374 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
375 EXPECT_EQ(record->event->logical, kLogicalKeyA);
376 EXPECT_STREQ(record->event->character, "A");
377 EXPECT_EQ(record->event->synthesized, false);
378
380 g_main_loop_run(loop2);
381 clear_records(call_records);
382
383 // Release shift right
384 g_autoptr(FlKeyEvent) event3 = fl_key_event_new(
385 103, kRelease, kKeyCodeShiftRight, GDK_KEY_Shift_R, GDK_SHIFT_MASK, 0);
386 g_autoptr(GMainLoop) loop3 = g_main_loop_new(nullptr, 0);
388 responder, event3, 0, nullptr,
389 [](GObject* object, GAsyncResult* result, gpointer user_data) {
390 gboolean handled;
392 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
393 EXPECT_EQ(handled, TRUE);
394
395 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
396 },
397 loop3);
398
399 EXPECT_EQ(call_records->len, 1u);
400 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
401 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
402 EXPECT_EQ(record->event->physical, kPhysicalShiftRight);
403 EXPECT_EQ(record->event->logical, kLogicalShiftRight);
404 EXPECT_STREQ(record->event->character, nullptr);
405 EXPECT_EQ(record->event->synthesized, false);
406
408 g_main_loop_run(loop3);
409 clear_records(call_records);
410
411 // Release key A
412 g_autoptr(FlKeyEvent) event4 =
413 fl_key_event_new(104, kRelease, kKeyCodeKeyA, GDK_KEY_A,
414 static_cast<GdkModifierType>(0), 0);
415 g_autoptr(GMainLoop) loop4 = g_main_loop_new(nullptr, 0);
417 responder, event4, 0, nullptr,
418 [](GObject* object, GAsyncResult* result, gpointer user_data) {
419 gboolean handled;
421 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
422 EXPECT_EQ(handled, TRUE);
423
424 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
425 },
426 loop4);
427
428 EXPECT_EQ(call_records->len, 1u);
429 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
430 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
431 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
432 EXPECT_EQ(record->event->logical, kLogicalKeyA);
433 EXPECT_STREQ(record->event->character, nullptr);
434 EXPECT_EQ(record->event->synthesized, false);
435
437 g_main_loop_run(loop4);
438}
439
440// Press or release Numpad 1 between presses/releases of NumLock.
441//
442// This tests interaction between lock keys and non-lock keys in cases that do
443// not have events missed.
444//
445// This also tests the result of Numpad keys across NumLock taps, which is
446// test-worthy because the keyval for the numpad key will change before and
447// after the NumLock tap, which should not alter the resulting logical key.
448TEST(FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents) {
449 g_autoptr(FlDartProject) project = fl_dart_project_new();
450 g_autoptr(FlEngine) engine = fl_engine_new(project);
451 EXPECT_TRUE(fl_engine_start(engine, nullptr));
452
453 g_autoptr(FlKeyEmbedderResponder) responder =
455
456 g_autoptr(GPtrArray) call_records =
457 g_ptr_array_new_with_free_func(g_object_unref);
459 SendKeyEvent,
460 ([&call_records](auto engine, const FlutterKeyEvent* event,
462 g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
463 event, callback, user_data));
464 return kSuccess;
465 }));
466
467 // Press Numpad 1 (stage 0)
468 g_autoptr(FlKeyEvent) event1 =
469 fl_key_event_new(101, kPress, kKeyCodeNumpad1, GDK_KEY_KP_End,
470 static_cast<GdkModifierType>(0), 0);
471 g_autoptr(GMainLoop) loop1 = g_main_loop_new(nullptr, 0);
473 responder, event1, 0, nullptr,
474 [](GObject* object, GAsyncResult* result, gpointer user_data) {
475 gboolean handled;
477 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
478 EXPECT_EQ(handled, TRUE);
479
480 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
481 },
482 loop1);
483
484 EXPECT_EQ(call_records->len, 1u);
485 FlKeyEmbedderCallRecord* record =
486 FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
487 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
488 EXPECT_EQ(record->event->physical, kPhysicalNumpad1);
489 EXPECT_EQ(record->event->logical, kLogicalNumpad1);
490 EXPECT_STREQ(record->event->character, nullptr); // TODO(chrome-bot):
491 EXPECT_EQ(record->event->synthesized, false);
492
494 g_main_loop_run(loop1);
495 clear_records(call_records);
496
497 // Press NumLock (stage 0 -> 1)
498 g_autoptr(FlKeyEvent) event2 =
499 fl_key_event_new(102, kPress, kKeyCodeNumLock, GDK_KEY_Num_Lock,
500 static_cast<GdkModifierType>(0), 0);
501 g_autoptr(GMainLoop) loop2 = g_main_loop_new(nullptr, 0);
503 responder, event2, 0, nullptr,
504 [](GObject* object, GAsyncResult* result, gpointer user_data) {
505 gboolean handled;
507 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
508 EXPECT_EQ(handled, TRUE);
509
510 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
511 },
512 loop2);
513
514 EXPECT_EQ(call_records->len, 1u);
515 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
516 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
517 EXPECT_EQ(record->event->physical, kPhysicalNumLock);
518 EXPECT_EQ(record->event->logical, kLogicalNumLock);
519 EXPECT_STREQ(record->event->character, nullptr);
520 EXPECT_EQ(record->event->synthesized, false);
521
523 g_main_loop_run(loop2);
524 clear_records(call_records);
525
526 // Release numpad 1 (stage 1)
527 g_autoptr(FlKeyEvent) event3 = fl_key_event_new(
528 104, kRelease, kKeyCodeNumpad1, GDK_KEY_KP_1, GDK_MOD2_MASK, 0);
529 g_autoptr(GMainLoop) loop3 = g_main_loop_new(nullptr, 0);
531 responder, event3, 0, nullptr,
532 [](GObject* object, GAsyncResult* result, gpointer user_data) {
533 gboolean handled;
535 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
536 EXPECT_EQ(handled, TRUE);
537
538 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
539 },
540 loop3);
541
542 EXPECT_EQ(call_records->len, 1u);
543 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
544 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
545 EXPECT_EQ(record->event->physical, kPhysicalNumpad1);
546 EXPECT_EQ(record->event->logical, kLogicalNumpad1);
547 EXPECT_STREQ(record->event->character, nullptr);
548 EXPECT_EQ(record->event->synthesized, false);
549
551 g_main_loop_run(loop3);
552 clear_records(call_records);
553
554 // Release NumLock (stage 1 -> 2)
555 g_autoptr(FlKeyEvent) event4 = fl_key_event_new(
556 103, kRelease, kKeyCodeNumLock, GDK_KEY_Num_Lock, GDK_MOD2_MASK, 0);
557 g_autoptr(GMainLoop) loop4 = g_main_loop_new(nullptr, 0);
559 responder, event4, 0, nullptr,
560 [](GObject* object, GAsyncResult* result, gpointer user_data) {
561 gboolean handled;
563 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
564 EXPECT_EQ(handled, TRUE);
565
566 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
567 },
568 loop4);
569
570 EXPECT_EQ(call_records->len, 1u);
571 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
572 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
573 EXPECT_EQ(record->event->physical, kPhysicalNumLock);
574 EXPECT_EQ(record->event->logical, kLogicalNumLock);
575 EXPECT_STREQ(record->event->character, nullptr);
576 EXPECT_EQ(record->event->synthesized, false);
577
579 g_main_loop_run(loop4);
580 clear_records(call_records);
581
582 // Press Numpad 1 (stage 2)
583 g_autoptr(FlKeyEvent) event5 = fl_key_event_new(
584 101, kPress, kKeyCodeNumpad1, GDK_KEY_KP_End, GDK_MOD2_MASK, 0);
585 g_autoptr(GMainLoop) loop5 = g_main_loop_new(nullptr, 0);
587 responder, event5, 0, nullptr,
588 [](GObject* object, GAsyncResult* result, gpointer user_data) {
589 gboolean handled;
591 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
592 EXPECT_EQ(handled, TRUE);
593
594 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
595 },
596 loop5);
597
598 EXPECT_EQ(call_records->len, 1u);
599 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
600 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
601 EXPECT_EQ(record->event->physical, kPhysicalNumpad1);
602 EXPECT_EQ(record->event->logical, kLogicalNumpad1);
603 EXPECT_STREQ(record->event->character, nullptr); // TODO(chrome-bot):
604 EXPECT_EQ(record->event->synthesized, false);
605
607 g_main_loop_run(loop5);
608 clear_records(call_records);
609
610 // Press NumLock (stage 2 -> 3)
611 g_autoptr(FlKeyEvent) event6 = fl_key_event_new(
612 102, kPress, kKeyCodeNumLock, GDK_KEY_Num_Lock, GDK_MOD2_MASK, 0);
613 g_autoptr(GMainLoop) loop6 = g_main_loop_new(nullptr, 0);
615 responder, event6, 0, nullptr,
616 [](GObject* object, GAsyncResult* result, gpointer user_data) {
617 gboolean handled;
619 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
620 EXPECT_EQ(handled, TRUE);
621
622 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
623 },
624 loop6);
625
626 EXPECT_EQ(call_records->len, 1u);
627 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
628 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
629 EXPECT_EQ(record->event->physical, kPhysicalNumLock);
630 EXPECT_EQ(record->event->logical, kLogicalNumLock);
631 EXPECT_STREQ(record->event->character, nullptr);
632 EXPECT_EQ(record->event->synthesized, false);
633
635 g_main_loop_run(loop6);
636 clear_records(call_records);
637
638 // Release numpad 1 (stage 3)
639 g_autoptr(FlKeyEvent) event7 = fl_key_event_new(
640 104, kRelease, kKeyCodeNumpad1, GDK_KEY_KP_1, GDK_MOD2_MASK, 0);
641 g_autoptr(GMainLoop) loop7 = g_main_loop_new(nullptr, 0);
643 responder, event7, 0, nullptr,
644 [](GObject* object, GAsyncResult* result, gpointer user_data) {
645 gboolean handled;
647 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
648 EXPECT_EQ(handled, TRUE);
649
650 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
651 },
652 loop7);
653
654 EXPECT_EQ(call_records->len, 1u);
655 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
656 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
657 EXPECT_EQ(record->event->physical, kPhysicalNumpad1);
658 EXPECT_EQ(record->event->logical, kLogicalNumpad1);
659 EXPECT_STREQ(record->event->character, nullptr);
660 EXPECT_EQ(record->event->synthesized, false);
661
663 g_main_loop_run(loop7);
664 clear_records(call_records);
665
666 // Release NumLock (stage 3 -> 0)
667 g_autoptr(FlKeyEvent) event8 = fl_key_event_new(
668 103, kRelease, kKeyCodeNumLock, GDK_KEY_Num_Lock, GDK_MOD2_MASK, 0);
669 g_autoptr(GMainLoop) loop8 = g_main_loop_new(nullptr, 0);
671 responder, event8, 0, nullptr,
672 [](GObject* object, GAsyncResult* result, gpointer user_data) {
673 gboolean handled;
675 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
676 EXPECT_EQ(handled, TRUE);
677
678 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
679 },
680 loop8);
681
682 EXPECT_EQ(call_records->len, 1u);
683 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
684 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
685 EXPECT_EQ(record->event->physical, kPhysicalNumLock);
686 EXPECT_EQ(record->event->logical, kLogicalNumLock);
687 EXPECT_STREQ(record->event->character, nullptr);
688 EXPECT_EQ(record->event->synthesized, false);
689
691 g_main_loop_run(loop8);
692}
693
694// Press or release digit 1 between presses/releases of Shift.
695//
696// GTK will change the virtual key during a key tap, and the embedder
697// should regularize it.
698TEST(FlKeyEmbedderResponderTest, ReleaseShiftKeyBetweenDigitKeyEvents) {
699 g_autoptr(FlDartProject) project = fl_dart_project_new();
700 g_autoptr(FlEngine) engine = fl_engine_new(project);
701 EXPECT_TRUE(fl_engine_start(engine, nullptr));
702
703 g_autoptr(FlKeyEmbedderResponder) responder =
705
706 g_autoptr(GPtrArray) call_records =
707 g_ptr_array_new_with_free_func(g_object_unref);
709 SendKeyEvent,
710 ([&call_records](auto engine, const FlutterKeyEvent* event,
712 g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
713 event, callback, user_data));
714 return kSuccess;
715 }));
716
717 GdkModifierType state = static_cast<GdkModifierType>(0);
718
719 // Press shift left
720 g_autoptr(FlKeyEvent) event1 = fl_key_event_new(
721 101, kPress, kKeyCodeShiftLeft, GDK_KEY_Shift_L, state, 0);
722 g_autoptr(GMainLoop) loop1 = g_main_loop_new(nullptr, 0);
724 responder, event1, 0, nullptr,
725 [](GObject* object, GAsyncResult* result, gpointer user_data) {
726 gboolean handled;
728 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
729 EXPECT_EQ(handled, TRUE);
730
731 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
732 },
733 loop1);
734
735 EXPECT_EQ(call_records->len, 1u);
736 FlKeyEmbedderCallRecord* record =
737 FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
738 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
739 EXPECT_EQ(record->event->physical, kPhysicalShiftLeft);
740 EXPECT_EQ(record->event->logical, kLogicalShiftLeft);
741 EXPECT_STREQ(record->event->character, nullptr);
742 EXPECT_EQ(record->event->synthesized, false);
743
745 g_main_loop_run(loop1);
746 clear_records(call_records);
747
748 state = GDK_SHIFT_MASK;
749
750 // Press digit 1, which is '!' on a US keyboard
751 g_autoptr(FlKeyEvent) event2 =
752 fl_key_event_new(102, kPress, kKeyCodeDigit1, GDK_KEY_exclam, state, 0);
753 g_autoptr(GMainLoop) loop2 = g_main_loop_new(nullptr, 0);
755 responder, event2, 0, nullptr,
756 [](GObject* object, GAsyncResult* result, gpointer user_data) {
757 gboolean handled;
759 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
760 EXPECT_EQ(handled, TRUE);
761
762 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
763 },
764 loop2);
765
766 EXPECT_EQ(call_records->len, 1u);
767 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
768 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
769 EXPECT_EQ(record->event->physical, kPhysicalDigit1);
770 EXPECT_EQ(record->event->logical, kLogicalExclamation);
771 EXPECT_STREQ(record->event->character, "!");
772 EXPECT_EQ(record->event->synthesized, false);
773
775 g_main_loop_run(loop2);
776 clear_records(call_records);
777
778 // Release shift
779 g_autoptr(FlKeyEvent) event3 = fl_key_event_new(
780 103, kRelease, kKeyCodeShiftLeft, GDK_KEY_Shift_L, state, 0);
781 g_autoptr(GMainLoop) loop3 = g_main_loop_new(nullptr, 0);
783 responder, event3, 0, nullptr,
784 [](GObject* object, GAsyncResult* result, gpointer user_data) {
785 gboolean handled;
787 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
788 EXPECT_EQ(handled, TRUE);
789
790 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
791 },
792 loop3);
793
794 EXPECT_EQ(call_records->len, 1u);
795 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
796 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
797 EXPECT_EQ(record->event->physical, kPhysicalShiftLeft);
798 EXPECT_EQ(record->event->logical, kLogicalShiftLeft);
799 EXPECT_STREQ(record->event->character, nullptr);
800 EXPECT_EQ(record->event->synthesized, false);
801
803 g_main_loop_run(loop3);
804 clear_records(call_records);
805
806 state = static_cast<GdkModifierType>(0);
807
808 // Release digit 1, which is "1" because shift has been released.
809 g_autoptr(FlKeyEvent) event4 =
810 fl_key_event_new(104, kRelease, kKeyCodeDigit1, GDK_KEY_1, state, 0);
811 g_autoptr(GMainLoop) loop4 = g_main_loop_new(nullptr, 0);
813 responder, event4, 0, nullptr,
814 [](GObject* object, GAsyncResult* result, gpointer user_data) {
815 gboolean handled;
817 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
818 EXPECT_EQ(handled, TRUE);
819
820 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
821 },
822 loop4);
823
824 EXPECT_EQ(call_records->len, 1u);
825 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
826 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
827 EXPECT_EQ(record->event->physical, kPhysicalDigit1);
828 EXPECT_EQ(record->event->logical, kLogicalExclamation); // Important
829 EXPECT_STREQ(record->event->character, nullptr);
830 EXPECT_EQ(record->event->synthesized, false);
831
833 g_main_loop_run(loop4);
834}
835
836// Press or release letter key between presses/releases of CapsLock.
837//
838// This tests interaction between lock keys and non-lock keys in cases that do
839// not have events missed.
840TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents) {
841 g_autoptr(FlDartProject) project = fl_dart_project_new();
842 g_autoptr(FlEngine) engine = fl_engine_new(project);
843 EXPECT_TRUE(fl_engine_start(engine, nullptr));
844
845 g_autoptr(FlKeyEmbedderResponder) responder =
847
848 g_autoptr(GPtrArray) call_records =
849 g_ptr_array_new_with_free_func(g_object_unref);
851 SendKeyEvent,
852 ([&call_records](auto engine, const FlutterKeyEvent* event,
854 g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
855 event, callback, user_data));
856 return kSuccess;
857 }));
858
859 // Press CapsLock (stage 0 -> 1)
860 g_autoptr(FlKeyEvent) event1 =
861 fl_key_event_new(101, kPress, kKeyCodeCapsLock, GDK_KEY_Caps_Lock,
862 static_cast<GdkModifierType>(0), 0);
863 g_autoptr(GMainLoop) loop1 = g_main_loop_new(nullptr, 0);
865 responder, event1, 0, nullptr,
866 [](GObject* object, GAsyncResult* result, gpointer user_data) {
867 gboolean handled;
869 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
870 EXPECT_EQ(handled, TRUE);
871
872 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
873 },
874 loop1);
875
876 EXPECT_EQ(call_records->len, 1u);
877 FlKeyEmbedderCallRecord* record =
878 FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
879 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
880 EXPECT_EQ(record->event->physical, kPhysicalCapsLock);
881 EXPECT_EQ(record->event->logical, kLogicalCapsLock);
882 EXPECT_STREQ(record->event->character, nullptr);
883 EXPECT_EQ(record->event->synthesized, false);
884
886 g_main_loop_run(loop1);
887 clear_records(call_records);
888
889 // Press key A (stage 1)
890 g_autoptr(FlKeyEvent) event2 =
891 fl_key_event_new(102, kPress, kKeyCodeKeyA, GDK_KEY_A, GDK_LOCK_MASK, 0);
892 g_autoptr(GMainLoop) loop2 = g_main_loop_new(nullptr, 0);
894 responder, event2, 0, nullptr,
895 [](GObject* object, GAsyncResult* result, gpointer user_data) {
896 gboolean handled;
898 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
899 EXPECT_EQ(handled, TRUE);
900
901 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
902 },
903 loop2);
904
905 EXPECT_EQ(call_records->len, 1u);
906 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
907 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
908 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
909 EXPECT_EQ(record->event->logical, kLogicalKeyA);
910 EXPECT_STREQ(record->event->character, "A");
911 EXPECT_EQ(record->event->synthesized, false);
912
914 g_main_loop_run(loop2);
915 clear_records(call_records);
916
917 // Release CapsLock (stage 1 -> 2)
918 g_autoptr(FlKeyEvent) event3 = fl_key_event_new(
919 103, kRelease, kKeyCodeCapsLock, GDK_KEY_Caps_Lock, GDK_LOCK_MASK, 0);
920 g_autoptr(GMainLoop) loop3 = g_main_loop_new(nullptr, 0);
922 responder, event3, 0, nullptr,
923 [](GObject* object, GAsyncResult* result, gpointer user_data) {
924 gboolean handled;
926 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
927 EXPECT_EQ(handled, TRUE);
928
929 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
930 },
931 loop3);
932
933 EXPECT_EQ(call_records->len, 1u);
934 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(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_main_loop_run(loop3);
943 clear_records(call_records);
944
945 // Release key A (stage 2)
946 g_autoptr(FlKeyEvent) event4 = fl_key_event_new(104, kRelease, kKeyCodeKeyA,
947 GDK_KEY_A, GDK_LOCK_MASK, 0);
948 g_autoptr(GMainLoop) loop4 = g_main_loop_new(nullptr, 0);
950 responder, event4, 0, nullptr,
951 [](GObject* object, GAsyncResult* result, gpointer user_data) {
952 gboolean handled;
954 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
955 EXPECT_EQ(handled, TRUE);
956
957 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
958 },
959 loop4);
960
961 EXPECT_EQ(call_records->len, 1u);
962 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
963 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
964 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
965 EXPECT_EQ(record->event->logical, kLogicalKeyA);
966 EXPECT_STREQ(record->event->character, nullptr);
967 EXPECT_EQ(record->event->synthesized, false);
968
970 g_main_loop_run(loop4);
971 clear_records(call_records);
972
973 // Press CapsLock (stage 2 -> 3)
974 g_autoptr(FlKeyEvent) event5 = fl_key_event_new(
975 105, kPress, kKeyCodeCapsLock, GDK_KEY_Caps_Lock, GDK_LOCK_MASK, 0);
976 g_autoptr(GMainLoop) loop5 = g_main_loop_new(nullptr, 0);
978 responder, event5, 0, nullptr,
979 [](GObject* object, GAsyncResult* result, gpointer user_data) {
980 gboolean handled;
982 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
983 EXPECT_EQ(handled, TRUE);
984
985 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
986 },
987 loop5);
988
989 EXPECT_EQ(call_records->len, 1u);
990 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
991 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
992 EXPECT_EQ(record->event->physical, kPhysicalCapsLock);
993 EXPECT_EQ(record->event->logical, kLogicalCapsLock);
994 EXPECT_STREQ(record->event->character, nullptr);
995 EXPECT_EQ(record->event->synthesized, false);
996
998 g_main_loop_run(loop5);
999 clear_records(call_records);
1000
1001 // Press key A (stage 3)
1002 g_autoptr(FlKeyEvent) event6 =
1003 fl_key_event_new(106, kPress, kKeyCodeKeyA, GDK_KEY_A, GDK_LOCK_MASK, 0);
1004 g_autoptr(GMainLoop) loop6 = g_main_loop_new(nullptr, 0);
1006 responder, event6, 0, nullptr,
1007 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1008 gboolean handled;
1010 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1011 EXPECT_EQ(handled, TRUE);
1012
1013 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1014 },
1015 loop6);
1016
1017 EXPECT_EQ(call_records->len, 1u);
1018 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1019 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1020 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
1021 EXPECT_EQ(record->event->logical, kLogicalKeyA);
1022 EXPECT_STREQ(record->event->character, "A");
1023 EXPECT_EQ(record->event->synthesized, false);
1024
1026 g_main_loop_run(loop6);
1027 clear_records(call_records);
1028
1029 // Release CapsLock (stage 3 -> 0)
1030 g_autoptr(FlKeyEvent) event7 = fl_key_event_new(
1031 107, kRelease, kKeyCodeCapsLock, GDK_KEY_Caps_Lock, GDK_LOCK_MASK, 0);
1032 g_autoptr(GMainLoop) loop7 = g_main_loop_new(nullptr, 0);
1034 responder, event7, 0, nullptr,
1035 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1036 gboolean handled;
1038 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1039 EXPECT_EQ(handled, TRUE);
1040
1041 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1042 },
1043 loop7);
1044
1045 EXPECT_EQ(call_records->len, 1u);
1046 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1047 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1048 EXPECT_EQ(record->event->physical, kPhysicalCapsLock);
1049 EXPECT_EQ(record->event->logical, kLogicalCapsLock);
1050 EXPECT_STREQ(record->event->character, nullptr);
1051 EXPECT_EQ(record->event->synthesized, false);
1052
1054 g_main_loop_run(loop7);
1055 clear_records(call_records);
1056
1057 // Release key A (stage 0)
1058 g_autoptr(FlKeyEvent) event8 =
1059 fl_key_event_new(108, kRelease, kKeyCodeKeyA, GDK_KEY_a,
1060 static_cast<GdkModifierType>(0), 0);
1061 g_autoptr(GMainLoop) loop8 = g_main_loop_new(nullptr, 0);
1063 responder, event8, 0, nullptr,
1064 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1065 gboolean handled;
1067 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1068 EXPECT_EQ(handled, TRUE);
1069
1070 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1071 },
1072 loop8);
1073
1074 EXPECT_EQ(call_records->len, 1u);
1075 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1076 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1077 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
1078 EXPECT_EQ(record->event->logical, kLogicalKeyA);
1079 EXPECT_STREQ(record->event->character, nullptr);
1080 EXPECT_EQ(record->event->synthesized, false);
1081
1083 g_main_loop_run(loop8);
1084}
1085
1086// Press or release letter key between presses/releases of CapsLock, on
1087// a platform with reversed logic.
1088//
1089// This happens when using a Chrome remote desktop on MacOS.
1090TEST(FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed) {
1091 g_autoptr(FlDartProject) project = fl_dart_project_new();
1092 g_autoptr(FlEngine) engine = fl_engine_new(project);
1093 EXPECT_TRUE(fl_engine_start(engine, nullptr));
1094
1095 g_autoptr(FlKeyEmbedderResponder) responder =
1097
1098 g_autoptr(GPtrArray) call_records =
1099 g_ptr_array_new_with_free_func(g_object_unref);
1101 SendKeyEvent,
1102 ([&call_records](auto engine, const FlutterKeyEvent* event,
1104 g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
1105 event, callback, user_data));
1106 return kSuccess;
1107 }));
1108
1109 // Press key A (stage 0)
1110 g_autoptr(FlKeyEvent) event1 = fl_key_event_new(
1111 101, kPress, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0);
1112 g_autoptr(GMainLoop) loop1 = g_main_loop_new(nullptr, 0);
1114 responder, event1, 0, nullptr,
1115 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1116 gboolean handled;
1118 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1119 EXPECT_EQ(handled, TRUE);
1120
1121 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1122 },
1123 loop1);
1124
1125 EXPECT_EQ(call_records->len, 1u);
1126 FlKeyEmbedderCallRecord* record =
1127 FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1128 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1129 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
1130 EXPECT_EQ(record->event->logical, kLogicalKeyA);
1131 EXPECT_STREQ(record->event->character, "a");
1132 EXPECT_EQ(record->event->synthesized, false);
1133
1135 g_main_loop_run(loop1);
1136 clear_records(call_records);
1137
1138 // Press CapsLock (stage 0 -> 1)
1139 g_autoptr(FlKeyEvent) event2 = fl_key_event_new(
1140 102, kPress, kKeyCodeCapsLock, GDK_KEY_Caps_Lock, GDK_LOCK_MASK, 0);
1141 g_autoptr(GMainLoop) loop2 = g_main_loop_new(nullptr, 0);
1143 responder, event2, 0, nullptr,
1144 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1145 gboolean handled;
1147 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1148 EXPECT_EQ(handled, TRUE);
1149
1150 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1151 },
1152 loop2);
1153
1154 EXPECT_EQ(call_records->len, 1u);
1155 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1156 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1157 EXPECT_EQ(record->event->physical, kPhysicalCapsLock);
1158 EXPECT_EQ(record->event->logical, kLogicalCapsLock);
1159 EXPECT_STREQ(record->event->character, nullptr);
1160 EXPECT_EQ(record->event->synthesized, false);
1161
1163 g_main_loop_run(loop2);
1164 clear_records(call_records);
1165
1166 // Release CapsLock (stage 1 -> 2)
1167 g_autoptr(FlKeyEvent) event3 = fl_key_event_new(
1168 103, kRelease, kKeyCodeCapsLock, GDK_KEY_Caps_Lock, GDK_LOCK_MASK, 0);
1169 g_autoptr(GMainLoop) loop3 = g_main_loop_new(nullptr, 0);
1171 responder, event3, 0, nullptr,
1172 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1173 gboolean handled;
1175 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1176 EXPECT_EQ(handled, TRUE);
1177
1178 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1179 },
1180 loop3);
1181
1182 EXPECT_EQ(call_records->len, 1u);
1183 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1184 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1185 EXPECT_EQ(record->event->physical, kPhysicalCapsLock);
1186 EXPECT_EQ(record->event->logical, kLogicalCapsLock);
1187 EXPECT_STREQ(record->event->character, nullptr);
1188 EXPECT_EQ(record->event->synthesized, false);
1189
1191 g_main_loop_run(loop3);
1192 clear_records(call_records);
1193
1194 // Release key A (stage 2)
1195 g_autoptr(FlKeyEvent) event4 = fl_key_event_new(104, kRelease, kKeyCodeKeyA,
1196 GDK_KEY_A, GDK_LOCK_MASK, 0);
1197 g_autoptr(GMainLoop) loop4 = g_main_loop_new(nullptr, 0);
1199 responder, event4, 0, nullptr,
1200 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1201 gboolean handled;
1203 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1204 EXPECT_EQ(handled, TRUE);
1205
1206 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1207 },
1208 loop4);
1209
1210 EXPECT_EQ(call_records->len, 1u);
1211 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1212 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1213 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
1214 EXPECT_EQ(record->event->logical, kLogicalKeyA);
1215 EXPECT_STREQ(record->event->character, nullptr);
1216 EXPECT_EQ(record->event->synthesized, false);
1217
1219 g_main_loop_run(loop4);
1220 clear_records(call_records);
1221
1222 // Press key A (stage 2)
1223 g_autoptr(FlKeyEvent) event5 =
1224 fl_key_event_new(105, kPress, kKeyCodeKeyA, GDK_KEY_A, GDK_LOCK_MASK, 0);
1225 g_autoptr(GMainLoop) loop5 = g_main_loop_new(nullptr, 0);
1227 responder, event5, 0, nullptr,
1228 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1229 gboolean handled;
1231 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1232 EXPECT_EQ(handled, TRUE);
1233
1234 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1235 },
1236 loop5);
1237
1238 EXPECT_EQ(call_records->len, 1u);
1239 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1240 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1241 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
1242 EXPECT_EQ(record->event->logical, kLogicalKeyA);
1243 EXPECT_STREQ(record->event->character, "A");
1244 EXPECT_EQ(record->event->synthesized, false);
1245
1247 g_main_loop_run(loop5);
1248 clear_records(call_records);
1249
1250 // Press CapsLock (stage 2 -> 3)
1251 g_autoptr(FlKeyEvent) event6 =
1252 fl_key_event_new(106, kPress, kKeyCodeCapsLock, GDK_KEY_Caps_Lock,
1253 static_cast<GdkModifierType>(0), 0);
1254 g_autoptr(GMainLoop) loop6 = g_main_loop_new(nullptr, 0);
1256 responder, event6, 0, nullptr,
1257 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1258 gboolean handled;
1260 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1261 EXPECT_EQ(handled, TRUE);
1262
1263 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1264 },
1265 loop6);
1266
1267 EXPECT_EQ(call_records->len, 1u);
1268 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1269 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1270 EXPECT_EQ(record->event->physical, kPhysicalCapsLock);
1271 EXPECT_EQ(record->event->logical, kLogicalCapsLock);
1272 EXPECT_STREQ(record->event->character, nullptr);
1273 EXPECT_EQ(record->event->synthesized, false);
1274
1276 g_main_loop_run(loop6);
1277 clear_records(call_records);
1278
1279 // Release CapsLock (stage 3 -> 0)
1280 g_autoptr(FlKeyEvent) event7 = fl_key_event_new(
1281 107, kRelease, kKeyCodeCapsLock, GDK_KEY_Caps_Lock, GDK_LOCK_MASK, 0);
1282 g_autoptr(GMainLoop) loop7 = g_main_loop_new(nullptr, 0);
1284 responder, event7, 0, nullptr,
1285 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1286 gboolean handled;
1288 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1289 EXPECT_EQ(handled, TRUE);
1290
1291 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1292 },
1293 loop7);
1294
1295 EXPECT_EQ(call_records->len, 1u);
1296 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1297 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1298 EXPECT_EQ(record->event->physical, kPhysicalCapsLock);
1299 EXPECT_EQ(record->event->logical, kLogicalCapsLock);
1300 EXPECT_STREQ(record->event->character, nullptr);
1301 EXPECT_EQ(record->event->synthesized, false);
1302
1304 g_main_loop_run(loop7);
1305 clear_records(call_records);
1306
1307 // Release key A (stage 0)
1308 g_autoptr(FlKeyEvent) event8 =
1309 fl_key_event_new(108, kRelease, kKeyCodeKeyA, GDK_KEY_a,
1310 static_cast<GdkModifierType>(0), 0);
1311 g_autoptr(GMainLoop) loop8 = g_main_loop_new(nullptr, 0);
1313 responder, event8, 0, nullptr,
1314 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1315 gboolean handled;
1317 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1318 EXPECT_EQ(handled, TRUE);
1319
1320 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1321 },
1322 loop8);
1323
1324 EXPECT_EQ(call_records->len, 1u);
1325 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1326 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1327 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
1328 EXPECT_EQ(record->event->logical, kLogicalKeyA);
1329 EXPECT_STREQ(record->event->character, nullptr);
1330 EXPECT_EQ(record->event->synthesized, false);
1331
1333 g_main_loop_run(loop8);
1334}
1335
1336TEST(FlKeyEmbedderResponderTest, TurnDuplicateDownEventsToRepeats) {
1337 g_autoptr(FlDartProject) project = fl_dart_project_new();
1338 g_autoptr(FlEngine) engine = fl_engine_new(project);
1339 EXPECT_TRUE(fl_engine_start(engine, nullptr));
1340
1341 g_autoptr(FlKeyEmbedderResponder) responder =
1343
1344 g_autoptr(GPtrArray) call_records =
1345 g_ptr_array_new_with_free_func(g_object_unref);
1347 SendKeyEvent,
1348 ([&call_records](auto engine, const FlutterKeyEvent* event,
1350 g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
1351 event, callback, user_data));
1352 return kSuccess;
1353 }));
1354
1355 // Press KeyA
1356 g_autoptr(FlKeyEvent) event1 = fl_key_event_new(
1357 101, kPress, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0);
1358 g_autoptr(GMainLoop) loop1 = g_main_loop_new(nullptr, 0);
1360 responder, event1, 0, nullptr,
1361 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1362 gboolean handled;
1364 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1365 EXPECT_EQ(handled, TRUE);
1366
1367 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1368 },
1369 loop1);
1370
1371 EXPECT_EQ(call_records->len, 1u);
1372
1373 FlKeyEmbedderCallRecord* record =
1374 FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1376 g_main_loop_run(loop1);
1377 clear_records(call_records);
1378
1379 // Another KeyA down events, which usually means a repeated event.
1380 g_autoptr(FlKeyEvent) event2 = fl_key_event_new(
1381 102, kPress, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0);
1382 g_autoptr(GMainLoop) loop2 = g_main_loop_new(nullptr, 0);
1384 responder, event2, 0, nullptr,
1385 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1386 gboolean handled;
1388 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1389 EXPECT_EQ(handled, TRUE);
1390
1391 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1392 },
1393 loop2);
1394
1395 EXPECT_EQ(call_records->len, 1u);
1396
1397 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1398 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeRepeat);
1399 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
1400 EXPECT_EQ(record->event->logical, kLogicalKeyA);
1401 EXPECT_STREQ(record->event->character, "a");
1402 EXPECT_EQ(record->event->synthesized, false);
1403 EXPECT_NE(record->callback, nullptr);
1404
1406 g_main_loop_run(loop2);
1407 clear_records(call_records);
1408
1409 // Release KeyA
1410 g_autoptr(FlKeyEvent) event3 =
1411 fl_key_event_new(103, kRelease, kKeyCodeKeyA, GDK_KEY_q,
1412 static_cast<GdkModifierType>(0), 0);
1413 g_autoptr(GMainLoop) loop3 = g_main_loop_new(nullptr, 0);
1415 responder, event3, 0, nullptr,
1416 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1417 gboolean handled;
1419 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1420 EXPECT_EQ(handled, TRUE);
1421
1422 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1423 },
1424 loop3);
1425
1426 EXPECT_EQ(call_records->len, 1u);
1427 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1429 g_main_loop_run(loop3);
1430}
1431
1432TEST(FlKeyEmbedderResponderTest, IgnoreAbruptUpEvent) {
1433 g_autoptr(FlDartProject) project = fl_dart_project_new();
1434 g_autoptr(FlEngine) engine = fl_engine_new(project);
1435 EXPECT_TRUE(fl_engine_start(engine, nullptr));
1436
1437 g_autoptr(FlKeyEmbedderResponder) responder =
1439
1440 g_autoptr(GPtrArray) call_records =
1441 g_ptr_array_new_with_free_func(g_object_unref);
1443 SendKeyEvent,
1444 ([&call_records](auto engine, const FlutterKeyEvent* event,
1446 g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
1447 event, callback, user_data));
1448 return kSuccess;
1449 }));
1450
1451 // Release KeyA before it was even pressed.
1452 g_autoptr(FlKeyEvent) event =
1453 fl_key_event_new(103, kRelease, kKeyCodeKeyA, GDK_KEY_q,
1454 static_cast<GdkModifierType>(0), 0);
1455 g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
1457 responder, event, 0, nullptr,
1458 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1459 gboolean handled;
1461 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1462 EXPECT_EQ(handled, TRUE);
1463
1464 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1465 },
1466 loop);
1467
1468 EXPECT_EQ(call_records->len, 1u);
1469
1470 FlKeyEmbedderCallRecord* record =
1471 FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1472 EXPECT_EQ(record->event->physical, 0ull);
1473 EXPECT_EQ(record->event->logical, 0ull);
1474 EXPECT_STREQ(record->event->character, nullptr);
1475 EXPECT_EQ(record->event->synthesized, false);
1476
1478 g_main_loop_run(loop);
1479}
1480
1481// Test if missed modifier keys can be detected and synthesized with state
1482// information upon events that are for this modifier key.
1483TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents) {
1484 g_autoptr(FlDartProject) project = fl_dart_project_new();
1485 g_autoptr(FlEngine) engine = fl_engine_new(project);
1486 EXPECT_TRUE(fl_engine_start(engine, nullptr));
1487
1488 g_autoptr(FlKeyEmbedderResponder) responder =
1490
1491 g_autoptr(GPtrArray) call_records =
1492 g_ptr_array_new_with_free_func(g_object_unref);
1494 SendKeyEvent,
1495 ([&call_records](auto engine, const FlutterKeyEvent* event,
1497 g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
1498 event, callback, user_data));
1499 return kSuccess;
1500 }));
1501
1502 // Test 1: synthesize key down.
1503
1504 // A key down of control left is missed.
1505 GdkModifierType state = GDK_CONTROL_MASK;
1506
1507 // Send a ControlLeft up
1508 g_autoptr(FlKeyEvent) event1 = fl_key_event_new(
1509 101, kRelease, kKeyCodeControlLeft, GDK_KEY_Control_L, state, 0);
1510 g_autoptr(GMainLoop) loop1 = g_main_loop_new(nullptr, 0);
1512 responder, event1, 0, nullptr,
1513 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1514 gboolean handled;
1516 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1517 EXPECT_EQ(handled, TRUE);
1518
1519 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1520 },
1521 loop1);
1522
1523 EXPECT_EQ(call_records->len, 2u);
1524 FlKeyEmbedderCallRecord* record =
1525 FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1526 EXPECT_EQ(record->event->timestamp, 101000);
1527 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1528 EXPECT_EQ(record->event->physical, kPhysicalControlLeft);
1529 EXPECT_EQ(record->event->logical, kLogicalControlLeft);
1530 EXPECT_STREQ(record->event->character, nullptr);
1531 EXPECT_EQ(record->event->synthesized, true);
1532
1533 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 1));
1534 EXPECT_EQ(record->event->timestamp, 101000);
1535 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1536 EXPECT_EQ(record->event->physical, kPhysicalControlLeft);
1537 EXPECT_EQ(record->event->logical, kLogicalControlLeft);
1538 EXPECT_STREQ(record->event->character, nullptr);
1539 EXPECT_EQ(record->event->synthesized, false);
1540
1542 g_main_loop_run(loop1);
1543 clear_records(call_records);
1544
1545 // Test 2: synthesize key up.
1546
1547 // Send a ControlLeft down.
1548 state = static_cast<GdkModifierType>(0);
1549 g_autoptr(FlKeyEvent) event2 = fl_key_event_new(
1550 102, kPress, kKeyCodeControlLeft, GDK_KEY_Control_L, state, 0);
1551 g_autoptr(GMainLoop) loop2 = g_main_loop_new(nullptr, 0);
1553 responder, event2, 0, nullptr,
1554 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1555 gboolean handled;
1557 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1558 EXPECT_EQ(handled, TRUE);
1559
1560 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1561 },
1562 loop2);
1563 EXPECT_EQ(call_records->len, 1u);
1564 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1566 g_main_loop_run(loop2);
1567 clear_records(call_records);
1568
1569 // A key up of control left is missed.
1570 state = static_cast<GdkModifierType>(0);
1571
1572 // Send another ControlLeft down
1573 g_autoptr(FlKeyEvent) event3 = fl_key_event_new(
1574 103, kPress, kKeyCodeControlLeft, GDK_KEY_Control_L, state, 0);
1575 g_autoptr(GMainLoop) loop3 = g_main_loop_new(nullptr, 0);
1577 responder, event3, 0, nullptr,
1578 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1579 gboolean handled;
1581 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1582 EXPECT_EQ(handled, TRUE);
1583
1584 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1585 },
1586 loop3);
1587
1588 EXPECT_EQ(call_records->len, 2u);
1589 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1590 EXPECT_EQ(record->event->timestamp, 103000);
1591 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1592 EXPECT_EQ(record->event->physical, kPhysicalControlLeft);
1593 EXPECT_EQ(record->event->logical, kLogicalControlLeft);
1594 EXPECT_STREQ(record->event->character, nullptr);
1595 EXPECT_EQ(record->event->synthesized, true);
1596
1597 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 1));
1598 EXPECT_EQ(record->event->timestamp, 103000);
1599 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1600 EXPECT_EQ(record->event->physical, kPhysicalControlLeft);
1601 EXPECT_EQ(record->event->logical, kLogicalControlLeft);
1602 EXPECT_STREQ(record->event->character, nullptr);
1603 EXPECT_EQ(record->event->synthesized, false);
1604
1606 g_main_loop_run(loop3);
1607 clear_records(call_records);
1608
1609 // Send a ControlLeft up to clear up state.
1610 state = GDK_CONTROL_MASK;
1611 g_autoptr(FlKeyEvent) event4 = fl_key_event_new(
1612 104, kRelease, kKeyCodeControlLeft, GDK_KEY_Control_L, state, 0);
1613 g_autoptr(GMainLoop) loop4 = g_main_loop_new(nullptr, 0);
1615 responder, event4, 0, nullptr,
1616 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1617 gboolean handled;
1619 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1620 EXPECT_EQ(handled, TRUE);
1621
1622 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1623 },
1624 loop4);
1625 EXPECT_EQ(call_records->len, 1u);
1626 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1628 g_main_loop_run(loop4);
1629 clear_records(call_records);
1630
1631 // Test 3: synthesize by right modifier.
1632
1633 // A key down of control right is missed.
1634 state = GDK_CONTROL_MASK;
1635
1636 // Send a ControlRight up.
1637 g_autoptr(FlKeyEvent) event5 = fl_key_event_new(
1638 105, kRelease, kKeyCodeControlRight, GDK_KEY_Control_R, state, 0);
1639 g_autoptr(GMainLoop) loop5 = g_main_loop_new(nullptr, 0);
1641 responder, event5, 0, nullptr,
1642 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1643 gboolean handled;
1645 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1646 EXPECT_EQ(handled, TRUE);
1647
1648 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1649 },
1650 loop5);
1651
1652 // A ControlLeft down is synthesized, with an empty event.
1653 // Reason: The ControlLeft down is synthesized to synchronize the state
1654 // showing Control as pressed. The ControlRight event is ignored because
1655 // the event is considered a duplicate up event.
1656 EXPECT_EQ(call_records->len, 1u);
1657 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1658 EXPECT_EQ(record->event->timestamp, 105000);
1659 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1660 EXPECT_EQ(record->event->physical, kPhysicalControlLeft);
1661 EXPECT_EQ(record->event->logical, kLogicalControlLeft);
1662 EXPECT_STREQ(record->event->character, nullptr);
1663 EXPECT_EQ(record->event->synthesized, true);
1664
1666 g_main_loop_run(loop5);
1667}
1668
1669// Test if missed modifier keys can be detected and synthesized with state
1670// information upon events that are not for this modifier key.
1671TEST(FlKeyEmbedderResponderTest,
1672 SynthesizeForDesyncPressingStateOnNonSelfEvents) {
1673 g_autoptr(FlDartProject) project = fl_dart_project_new();
1674 g_autoptr(FlEngine) engine = fl_engine_new(project);
1675 EXPECT_TRUE(fl_engine_start(engine, nullptr));
1676
1677 g_autoptr(FlKeyEmbedderResponder) responder =
1679
1680 g_autoptr(GPtrArray) call_records =
1681 g_ptr_array_new_with_free_func(g_object_unref);
1683 SendKeyEvent,
1684 ([&call_records](auto engine, const FlutterKeyEvent* event,
1686 g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
1687 event, callback, user_data));
1688 return kSuccess;
1689 }));
1690
1691 // A key down of control left is missed.
1692 GdkModifierType state = GDK_CONTROL_MASK;
1693
1694 // Send a normal event (KeyA down)
1695 g_autoptr(FlKeyEvent) event1 =
1696 fl_key_event_new(101, kPress, kKeyCodeKeyA, GDK_KEY_a, state, 0);
1697 g_autoptr(GMainLoop) loop1 = g_main_loop_new(nullptr, 0);
1699 responder, event1, 0, nullptr,
1700 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1701 gboolean handled;
1703 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1704 EXPECT_EQ(handled, TRUE);
1705
1706 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1707 },
1708 loop1);
1709
1710 EXPECT_EQ(call_records->len, 2u);
1711 FlKeyEmbedderCallRecord* record =
1712 FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1713 EXPECT_EQ(record->event->timestamp, 101000);
1714 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1715 EXPECT_EQ(record->event->physical, kPhysicalControlLeft);
1716 EXPECT_EQ(record->event->logical, kLogicalControlLeft);
1717 EXPECT_STREQ(record->event->character, nullptr);
1718 EXPECT_EQ(record->event->synthesized, true);
1719
1720 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 1));
1721 EXPECT_EQ(record->event->timestamp, 101000);
1722 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1723 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
1724 EXPECT_EQ(record->event->logical, kLogicalKeyA);
1725 EXPECT_STREQ(record->event->character, "a");
1726 EXPECT_EQ(record->event->synthesized, false);
1727
1729 g_main_loop_run(loop1);
1730 clear_records(call_records);
1731
1732 // A key up of control left is missed.
1733 state = static_cast<GdkModifierType>(0);
1734
1735 // Send a normal event (KeyA up)
1736 g_autoptr(FlKeyEvent) event2 =
1737 fl_key_event_new(102, kRelease, kKeyCodeKeyA, GDK_KEY_A, state, 0);
1738 g_autoptr(GMainLoop) loop2 = g_main_loop_new(nullptr, 0);
1740 responder, event2, 0, nullptr,
1741 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1742 gboolean handled;
1744 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1745 EXPECT_EQ(handled, TRUE);
1746
1747 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1748 },
1749 loop2);
1750
1751 EXPECT_EQ(call_records->len, 2u);
1752 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1753 EXPECT_EQ(record->event->timestamp, 102000);
1754 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1755 EXPECT_EQ(record->event->physical, kPhysicalControlLeft);
1756 EXPECT_EQ(record->event->logical, kLogicalControlLeft);
1757 EXPECT_STREQ(record->event->character, nullptr);
1758 EXPECT_EQ(record->event->synthesized, true);
1759
1760 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 1));
1761 EXPECT_EQ(record->event->timestamp, 102000);
1762 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1763 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
1764 EXPECT_EQ(record->event->logical, kLogicalKeyA);
1765 EXPECT_STREQ(record->event->character, nullptr);
1766 EXPECT_EQ(record->event->synthesized, false);
1767
1769 g_main_loop_run(loop2);
1770 clear_records(call_records);
1771
1772 // Test non-default key mapping.
1773
1774 // Press a key with physical CapsLock and logical ControlLeft.
1775 state = static_cast<GdkModifierType>(0);
1776
1777 g_autoptr(FlKeyEvent) event3 = fl_key_event_new(101, kPress, kKeyCodeCapsLock,
1778 GDK_KEY_Control_L, state, 0);
1779 g_autoptr(GMainLoop) loop3 = g_main_loop_new(nullptr, 0);
1781 responder, event3, 0, nullptr,
1782 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1783 gboolean handled;
1785 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1786 EXPECT_EQ(handled, TRUE);
1787
1788 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1789 },
1790 loop3);
1791
1792 EXPECT_EQ(call_records->len, 1u);
1793 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1794 EXPECT_EQ(record->event->timestamp, 101000);
1795 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1796 EXPECT_EQ(record->event->physical, kPhysicalCapsLock);
1797 EXPECT_EQ(record->event->logical, kLogicalControlLeft);
1798 EXPECT_STREQ(record->event->character, nullptr);
1799 EXPECT_EQ(record->event->synthesized, false);
1800
1802 g_main_loop_run(loop3);
1803 clear_records(call_records);
1804
1805 // The key up of the control left press is missed.
1806 state = static_cast<GdkModifierType>(0);
1807
1808 // Send a normal event (KeyA down).
1809 g_autoptr(FlKeyEvent) event4 =
1810 fl_key_event_new(102, kPress, kKeyCodeKeyA, GDK_KEY_A, state, 0);
1811 g_autoptr(GMainLoop) loop4 = g_main_loop_new(nullptr, 0);
1813 responder, event4, 0, nullptr,
1814 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1815 gboolean handled;
1817 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1818 EXPECT_EQ(handled, TRUE);
1819
1820 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1821 },
1822 loop4);
1823
1824 // The synthesized event should have physical CapsLock and logical
1825 // ControlLeft.
1826 EXPECT_EQ(call_records->len, 2u);
1827 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1828 EXPECT_EQ(record->event->timestamp, 102000);
1829 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1830 EXPECT_EQ(record->event->physical, kPhysicalCapsLock);
1831 EXPECT_EQ(record->event->logical, kLogicalControlLeft);
1832 EXPECT_STREQ(record->event->character, nullptr);
1833 EXPECT_EQ(record->event->synthesized, true);
1834
1835 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 1));
1836 EXPECT_EQ(record->event->timestamp, 102000);
1837 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1838 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
1839 EXPECT_EQ(record->event->logical, kLogicalKeyA);
1840 EXPECT_STREQ(record->event->character, "A");
1841 EXPECT_EQ(record->event->synthesized, false);
1842
1844 g_main_loop_run(loop4);
1845}
1846
1847// Test if missed modifier keys can be detected and synthesized with state
1848// information upon events that do not have the standard key mapping.
1849TEST(FlKeyEmbedderResponderTest,
1850 SynthesizeForDesyncPressingStateOnRemappedEvents) {
1851 g_autoptr(FlDartProject) project = fl_dart_project_new();
1852 g_autoptr(FlEngine) engine = fl_engine_new(project);
1853 EXPECT_TRUE(fl_engine_start(engine, nullptr));
1854
1855 g_autoptr(FlKeyEmbedderResponder) responder =
1857
1858 g_autoptr(GPtrArray) call_records =
1859 g_ptr_array_new_with_free_func(g_object_unref);
1861 SendKeyEvent,
1862 ([&call_records](auto engine, const FlutterKeyEvent* event,
1864 g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
1865 event, callback, user_data));
1866 return kSuccess;
1867 }));
1868
1869 // Press a key with physical CapsLock and logical ControlLeft.
1870 GdkModifierType state = static_cast<GdkModifierType>(0);
1871
1872 g_autoptr(FlKeyEvent) event1 = fl_key_event_new(101, kPress, kKeyCodeCapsLock,
1873 GDK_KEY_Control_L, state, 0);
1874 g_autoptr(GMainLoop) loop1 = g_main_loop_new(nullptr, 0);
1876 responder, event1, 0, nullptr,
1877 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1878 gboolean handled;
1880 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1881 EXPECT_EQ(handled, TRUE);
1882
1883 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1884 },
1885 loop1);
1886
1887 EXPECT_EQ(call_records->len, 1u);
1888 FlKeyEmbedderCallRecord* record =
1889 FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1890 EXPECT_EQ(record->event->timestamp, 101000);
1891 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1892 EXPECT_EQ(record->event->physical, kPhysicalCapsLock);
1893 EXPECT_EQ(record->event->logical, kLogicalControlLeft);
1894 EXPECT_STREQ(record->event->character, nullptr);
1895 EXPECT_EQ(record->event->synthesized, false);
1896
1898 g_main_loop_run(loop1);
1899 clear_records(call_records);
1900
1901 // The key up of the control left press is missed.
1902 state = static_cast<GdkModifierType>(0);
1903
1904 // Send a normal event (KeyA down).
1905 g_autoptr(FlKeyEvent) event2 =
1906 fl_key_event_new(102, kPress, kKeyCodeKeyA, GDK_KEY_A, state, 0);
1907 g_autoptr(GMainLoop) loop2 = g_main_loop_new(nullptr, 0);
1909 responder, event2, 0, nullptr,
1910 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1911 gboolean handled;
1913 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1914 EXPECT_EQ(handled, TRUE);
1915
1916 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1917 },
1918 loop2);
1919
1920 // The synthesized event should have physical CapsLock and logical
1921 // ControlLeft.
1922 EXPECT_EQ(call_records->len, 2u);
1923 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1924 EXPECT_EQ(record->event->timestamp, 102000);
1925 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1926 EXPECT_EQ(record->event->physical, kPhysicalCapsLock);
1927 EXPECT_EQ(record->event->logical, kLogicalControlLeft);
1928 EXPECT_STREQ(record->event->character, nullptr);
1929 EXPECT_EQ(record->event->synthesized, true);
1930
1931 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 1));
1932 EXPECT_EQ(record->event->timestamp, 102000);
1933 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1934 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
1935 EXPECT_EQ(record->event->logical, kLogicalKeyA);
1936 EXPECT_STREQ(record->event->character, "A");
1937 EXPECT_EQ(record->event->synthesized, false);
1938
1940 g_main_loop_run(loop2);
1941}
1942
1943// Test if missed lock keys can be detected and synthesized with state
1944// information upon events that are not for this modifier key.
1945TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents) {
1946 g_autoptr(FlDartProject) project = fl_dart_project_new();
1947 g_autoptr(FlEngine) engine = fl_engine_new(project);
1948 EXPECT_TRUE(fl_engine_start(engine, nullptr));
1949
1950 g_autoptr(FlKeyEmbedderResponder) responder =
1952
1953 g_autoptr(GPtrArray) call_records =
1954 g_ptr_array_new_with_free_func(g_object_unref);
1956 SendKeyEvent,
1957 ([&call_records](auto engine, const FlutterKeyEvent* event,
1959 g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
1960 event, callback, user_data));
1961 return kSuccess;
1962 }));
1963
1964 // The NumLock is desynchronized by being enabled.
1965 GdkModifierType state = GDK_MOD2_MASK;
1966
1967 // Send a normal event
1968 g_autoptr(FlKeyEvent) event1 =
1969 fl_key_event_new(101, kPress, kKeyCodeKeyA, GDK_KEY_a, state, 0);
1970 g_autoptr(GMainLoop) loop1 = g_main_loop_new(nullptr, 0);
1972 responder, event1, 0, nullptr,
1973 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1974 gboolean handled;
1976 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1977 EXPECT_EQ(handled, TRUE);
1978
1979 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1980 },
1981 loop1);
1982
1983 EXPECT_EQ(call_records->len, 2u);
1984 FlKeyEmbedderCallRecord* record =
1985 FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1986 EXPECT_EQ(record->event->timestamp, 101000);
1987 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1988 EXPECT_EQ(record->event->physical, kPhysicalNumLock);
1989 EXPECT_EQ(record->event->logical, kLogicalNumLock);
1990 EXPECT_STREQ(record->event->character, nullptr);
1991 EXPECT_EQ(record->event->synthesized, true);
1992
1993 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 1));
1994 EXPECT_EQ(record->event->timestamp, 101000);
1995 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1996 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
1997 EXPECT_EQ(record->event->logical, kLogicalKeyA);
1998 EXPECT_STREQ(record->event->character, "a");
1999 EXPECT_EQ(record->event->synthesized, false);
2000
2002 g_main_loop_run(loop1);
2003 clear_records(call_records);
2004
2005 // The NumLock is desynchronized by being disabled.
2006 state = static_cast<GdkModifierType>(0);
2007
2008 // Release key A
2009 g_autoptr(FlKeyEvent) event2 =
2010 fl_key_event_new(102, kRelease, kKeyCodeKeyA, GDK_KEY_A, state, 0);
2011 g_autoptr(GMainLoop) loop2 = g_main_loop_new(nullptr, 0);
2013 responder, event2, 0, nullptr,
2014 [](GObject* object, GAsyncResult* result, gpointer user_data) {
2015 gboolean handled;
2017 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
2018 EXPECT_EQ(handled, TRUE);
2019
2020 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
2021 },
2022 loop2);
2023
2024 EXPECT_EQ(call_records->len, 4u);
2025 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
2026 EXPECT_EQ(record->event->timestamp, 102000);
2027 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
2028 EXPECT_EQ(record->event->physical, kPhysicalNumLock);
2029 EXPECT_EQ(record->event->logical, kLogicalNumLock);
2030 EXPECT_STREQ(record->event->character, nullptr);
2031 EXPECT_EQ(record->event->synthesized, true);
2032
2033 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 1));
2034 EXPECT_EQ(record->event->timestamp, 102000);
2035 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
2036 EXPECT_EQ(record->event->physical, kPhysicalNumLock);
2037 EXPECT_EQ(record->event->logical, kLogicalNumLock);
2038 EXPECT_STREQ(record->event->character, nullptr);
2039 EXPECT_EQ(record->event->synthesized, true);
2040
2041 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 2));
2042 EXPECT_EQ(record->event->timestamp, 102000);
2043 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
2044 EXPECT_EQ(record->event->physical, kPhysicalNumLock);
2045 EXPECT_EQ(record->event->logical, kLogicalNumLock);
2046 EXPECT_STREQ(record->event->character, nullptr);
2047 EXPECT_EQ(record->event->synthesized, true);
2048
2049 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 3));
2050 EXPECT_EQ(record->event->timestamp, 102000);
2051 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
2052 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
2053 EXPECT_EQ(record->event->logical, kLogicalKeyA);
2054 EXPECT_STREQ(record->event->character, nullptr);
2055 EXPECT_EQ(record->event->synthesized, false);
2056
2058 g_main_loop_run(loop2);
2059 clear_records(call_records);
2060
2061 // Release NumLock. Since the previous event should have synthesized NumLock
2062 // to be released, this should result in only an empty event.
2063 g_autoptr(FlKeyEvent) event3 = fl_key_event_new(
2064 103, kRelease, kKeyCodeNumLock, GDK_KEY_Num_Lock, state, 0);
2065 g_autoptr(GMainLoop) loop3 = g_main_loop_new(nullptr, 0);
2067 responder, event3, 0, nullptr,
2068 [](GObject* object, GAsyncResult* result, gpointer user_data) {
2069 gboolean handled;
2071 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
2072 EXPECT_EQ(handled, TRUE);
2073
2074 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
2075 },
2076 loop3);
2077
2078 EXPECT_EQ(call_records->len, 1u);
2079 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
2080 EXPECT_EQ(record->event->physical, 0ull);
2081 EXPECT_EQ(record->event->logical, 0ull);
2082 EXPECT_STREQ(record->event->character, nullptr);
2083 EXPECT_EQ(record->event->synthesized, false);
2084
2086 g_main_loop_run(loop3);
2087}
2088
2089// Test if missed lock keys can be detected and synthesized with state
2090// information upon events that are for this modifier key.
2091TEST(FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents) {
2092 g_autoptr(FlDartProject) project = fl_dart_project_new();
2093 g_autoptr(FlEngine) engine = fl_engine_new(project);
2094 EXPECT_TRUE(fl_engine_start(engine, nullptr));
2095
2096 g_autoptr(FlKeyEmbedderResponder) responder =
2098
2099 g_autoptr(GPtrArray) call_records =
2100 g_ptr_array_new_with_free_func(g_object_unref);
2102 SendKeyEvent,
2103 ([&call_records](auto engine, const FlutterKeyEvent* event,
2105 g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
2106 event, callback, user_data));
2107 return kSuccess;
2108 }));
2109
2110 // The NumLock is desynchronized by being enabled.
2111 GdkModifierType state = GDK_MOD2_MASK;
2112
2113 // NumLock down
2114 g_autoptr(FlKeyEvent) event1 = fl_key_event_new(101, kPress, kKeyCodeNumLock,
2115 GDK_KEY_Num_Lock, state, 0);
2116 g_autoptr(GMainLoop) loop1 = g_main_loop_new(nullptr, 0);
2118 responder, event1, 0, nullptr,
2119 [](GObject* object, GAsyncResult* result, gpointer user_data) {
2120 gboolean handled;
2122 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
2123 EXPECT_EQ(handled, TRUE);
2124
2125 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
2126 },
2127 loop1);
2128
2129 EXPECT_EQ(call_records->len, 3u);
2130 FlKeyEmbedderCallRecord* record =
2131 FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
2132 EXPECT_EQ(record->event->timestamp, 101000);
2133 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
2134 EXPECT_EQ(record->event->physical, kPhysicalNumLock);
2135 EXPECT_EQ(record->event->logical, kLogicalNumLock);
2136 EXPECT_STREQ(record->event->character, nullptr);
2137 EXPECT_EQ(record->event->synthesized, true);
2138
2139 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 1));
2140 EXPECT_EQ(record->event->timestamp, 101000);
2141 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
2142 EXPECT_EQ(record->event->physical, kPhysicalNumLock);
2143 EXPECT_EQ(record->event->logical, kLogicalNumLock);
2144 EXPECT_STREQ(record->event->character, nullptr);
2145 EXPECT_EQ(record->event->synthesized, true);
2146
2147 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 2));
2148 EXPECT_EQ(record->event->timestamp, 101000);
2149 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
2150 EXPECT_EQ(record->event->physical, kPhysicalNumLock);
2151 EXPECT_EQ(record->event->logical, kLogicalNumLock);
2152 EXPECT_STREQ(record->event->character, nullptr);
2153 EXPECT_EQ(record->event->synthesized, false);
2154
2156 g_main_loop_run(loop1);
2157 clear_records(call_records);
2158
2159 // The NumLock is desynchronized by being enabled in a press event.
2160 state = GDK_MOD2_MASK;
2161
2162 // NumLock up
2163 g_autoptr(FlKeyEvent) event2 = fl_key_event_new(102, kPress, kKeyCodeNumLock,
2164 GDK_KEY_Num_Lock, state, 0);
2165 g_autoptr(GMainLoop) loop2 = g_main_loop_new(nullptr, 0);
2167 responder, event2, 0, nullptr,
2168 [](GObject* object, GAsyncResult* result, gpointer user_data) {
2169 gboolean handled;
2171 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
2172 EXPECT_EQ(handled, TRUE);
2173
2174 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
2175 },
2176 loop2);
2177
2178 EXPECT_EQ(call_records->len, 4u);
2179 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
2180 EXPECT_EQ(record->event->timestamp, 102000);
2181 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
2182 EXPECT_EQ(record->event->physical, kPhysicalNumLock);
2183 EXPECT_EQ(record->event->logical, kLogicalNumLock);
2184 EXPECT_STREQ(record->event->character, nullptr);
2185 EXPECT_EQ(record->event->synthesized, true);
2186
2187 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 1));
2188 EXPECT_EQ(record->event->timestamp, 102000);
2189 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
2190 EXPECT_EQ(record->event->physical, kPhysicalNumLock);
2191 EXPECT_EQ(record->event->logical, kLogicalNumLock);
2192 EXPECT_STREQ(record->event->character, nullptr);
2193 EXPECT_EQ(record->event->synthesized, true);
2194
2195 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 2));
2196 EXPECT_EQ(record->event->timestamp, 102000);
2197 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
2198 EXPECT_EQ(record->event->physical, kPhysicalNumLock);
2199 EXPECT_EQ(record->event->logical, kLogicalNumLock);
2200 EXPECT_STREQ(record->event->character, nullptr);
2201 EXPECT_EQ(record->event->synthesized, true);
2202
2203 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 3));
2204 EXPECT_EQ(record->event->timestamp, 102000);
2205 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
2206 EXPECT_EQ(record->event->physical, kPhysicalNumLock);
2207 EXPECT_EQ(record->event->logical, kLogicalNumLock);
2208 EXPECT_STREQ(record->event->character, nullptr);
2209 EXPECT_EQ(record->event->synthesized, false);
2210
2212 g_main_loop_run(loop2);
2213}
2214
2215// Ensures that even if the primary event is ignored (due to duplicate
2216// key up or down events), key synthesization is still performed.
2217TEST(FlKeyEmbedderResponderTest, SynthesizationOccursOnIgnoredEvents) {
2218 g_autoptr(FlDartProject) project = fl_dart_project_new();
2219 g_autoptr(FlEngine) engine = fl_engine_new(project);
2220 EXPECT_TRUE(fl_engine_start(engine, nullptr));
2221
2222 g_autoptr(FlKeyEmbedderResponder) responder =
2224
2225 g_autoptr(GPtrArray) call_records =
2226 g_ptr_array_new_with_free_func(g_object_unref);
2228 SendKeyEvent,
2229 ([&call_records](auto engine, const FlutterKeyEvent* event,
2231 g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
2232 event, callback, user_data));
2233 return kSuccess;
2234 }));
2235
2236 // The NumLock is desynchronized by being enabled, and Control is pressed.
2237 GdkModifierType state =
2238 static_cast<GdkModifierType>(GDK_MOD2_MASK | GDK_CONTROL_MASK);
2239
2240 // Send a KeyA up event, which will be ignored.
2241 g_autoptr(FlKeyEvent) event =
2242 fl_key_event_new(101, kRelease, kKeyCodeKeyA, GDK_KEY_a, state, 0);
2243 g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
2245 responder, event, 0, nullptr,
2246 [](GObject* object, GAsyncResult* result, gpointer user_data) {
2247 gboolean handled;
2249 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
2250 EXPECT_EQ(handled, TRUE);
2251
2252 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
2253 },
2254 loop);
2255 g_main_loop_run(loop);
2256
2257 EXPECT_EQ(call_records->len, 2u);
2258 FlKeyEmbedderCallRecord* record =
2259 FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
2260 EXPECT_EQ(record->event->timestamp, 101000);
2261 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
2262 EXPECT_EQ(record->event->physical, kPhysicalNumLock);
2263 EXPECT_EQ(record->event->logical, kLogicalNumLock);
2264 EXPECT_STREQ(record->event->character, nullptr);
2265 EXPECT_EQ(record->event->synthesized, true);
2266
2267 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 1));
2268 EXPECT_EQ(record->event->timestamp, 101000);
2269 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
2270 EXPECT_EQ(record->event->physical, kPhysicalControlLeft);
2271 EXPECT_EQ(record->event->logical, kLogicalControlLeft);
2272 EXPECT_STREQ(record->event->character, nullptr);
2273 EXPECT_EQ(record->event->synthesized, true);
2274}
2275
2276// This test case occurs when the following two cases collide:
2277//
2278// 1. When holding shift, AltRight key gives logical GDK_KEY_Meta_R with the
2279// state bitmask still MOD3 (Alt).
2280// 2. When holding AltRight, ShiftLeft key gives logical GDK_KEY_ISO_Next_Group
2281// with the state bitmask RESERVED_14.
2282//
2283// The resulting event sequence is not perfectly ideal: it had to synthesize
2284// AltLeft down because the physical AltRight key corresponds to logical
2285// MetaRight at the moment.
2286TEST(FlKeyEmbedderResponderTest, HandlesShiftAltVersusGroupNext) {
2287 g_autoptr(FlDartProject) project = fl_dart_project_new();
2288 g_autoptr(FlEngine) engine = fl_engine_new(project);
2289 EXPECT_TRUE(fl_engine_start(engine, nullptr));
2290
2291 g_autoptr(FlKeyEmbedderResponder) responder =
2293
2294 g_autoptr(GPtrArray) call_records =
2295 g_ptr_array_new_with_free_func(g_object_unref);
2297 SendKeyEvent,
2298 ([&call_records](auto engine, const FlutterKeyEvent* event,
2300 g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
2301 event, callback, user_data));
2302 callback(true, user_data);
2303 return kSuccess;
2304 }));
2305
2306 guint32 now_time = 1;
2307 // A convenient shorthand to simulate events.
2308 auto send_key_event = [responder, &now_time](bool is_press, guint keyval,
2309 guint16 keycode,
2310 GdkModifierType state) {
2311 now_time += 1;
2312 g_autoptr(FlKeyEvent) event =
2313 fl_key_event_new(now_time, is_press, keycode, keyval, state, 0);
2314 g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
2316 responder, event, 0, nullptr,
2317 [](GObject* object, GAsyncResult* result, gpointer user_data) {
2318 gboolean handled;
2320 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
2321 EXPECT_EQ(handled, TRUE);
2322
2323 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
2324 },
2325 loop);
2326 g_main_loop_run(loop);
2327 };
2328
2329 send_key_event(kPress, GDK_KEY_Shift_L, kKeyCodeShiftLeft,
2330 GDK_MODIFIER_RESERVED_25_MASK);
2331 EXPECT_EQ(call_records->len, 1u);
2332 FlKeyEmbedderCallRecord* record =
2333 FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
2334 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
2335 EXPECT_EQ(record->event->physical, kPhysicalShiftLeft);
2336 EXPECT_EQ(record->event->logical, kLogicalShiftLeft);
2337 EXPECT_EQ(record->event->synthesized, false);
2338
2339 send_key_event(kPress, GDK_KEY_Meta_R, kKeyCodeAltRight,
2340 static_cast<GdkModifierType>(GDK_SHIFT_MASK |
2341 GDK_MODIFIER_RESERVED_25_MASK));
2342 EXPECT_EQ(call_records->len, 2u);
2343 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 1));
2344 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
2345 EXPECT_EQ(record->event->physical, kPhysicalAltRight);
2346 EXPECT_EQ(record->event->logical, kLogicalMetaRight);
2347 EXPECT_EQ(record->event->synthesized, false);
2348
2349 send_key_event(kRelease, GDK_KEY_ISO_Next_Group, kKeyCodeShiftLeft,
2350 static_cast<GdkModifierType>(GDK_SHIFT_MASK | GDK_MOD1_MASK |
2351 GDK_MODIFIER_RESERVED_25_MASK));
2352 EXPECT_EQ(call_records->len, 5u);
2353 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 2));
2354 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
2355 EXPECT_EQ(record->event->physical, kPhysicalAltLeft);
2356 EXPECT_EQ(record->event->logical, kLogicalAltLeft);
2357 EXPECT_EQ(record->event->synthesized, true);
2358
2359 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 3));
2360 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
2361 EXPECT_EQ(record->event->physical, kPhysicalAltRight);
2362 EXPECT_EQ(record->event->logical, kLogicalMetaRight);
2363 EXPECT_EQ(record->event->synthesized, true);
2364
2365 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 4));
2366 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
2367 EXPECT_EQ(record->event->physical, kPhysicalShiftLeft);
2368 EXPECT_EQ(record->event->logical, kLogicalShiftLeft);
2369 EXPECT_EQ(record->event->synthesized, false);
2370
2371 send_key_event(kPress, GDK_KEY_ISO_Next_Group, kKeyCodeShiftLeft,
2372 static_cast<GdkModifierType>(GDK_MOD1_MASK |
2373 GDK_MODIFIER_RESERVED_25_MASK));
2374 EXPECT_EQ(call_records->len, 6u);
2375 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 5));
2376 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
2377 EXPECT_EQ(record->event->physical, kPhysicalShiftLeft);
2378 EXPECT_EQ(record->event->logical, kLogicalGroupNext);
2379 EXPECT_EQ(record->event->synthesized, false);
2380
2381 send_key_event(kRelease, GDK_KEY_ISO_Level3_Shift, kKeyCodeAltRight,
2382 static_cast<GdkModifierType>(GDK_MOD1_MASK |
2383 GDK_MODIFIER_RESERVED_13_MASK |
2384 GDK_MODIFIER_RESERVED_25_MASK));
2385 EXPECT_EQ(call_records->len, 7u);
2386 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 6));
2387 EXPECT_EQ(record->event->physical, 0u);
2388 EXPECT_EQ(record->event->logical, 0u);
2389
2390 send_key_event(kRelease, GDK_KEY_Shift_L, kKeyCodeShiftLeft,
2391 static_cast<GdkModifierType>(GDK_MODIFIER_RESERVED_13_MASK |
2392 GDK_MODIFIER_RESERVED_25_MASK));
2393 EXPECT_EQ(call_records->len, 9u);
2394 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 7));
2395 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
2396 EXPECT_EQ(record->event->physical, kPhysicalAltLeft);
2397 EXPECT_EQ(record->event->logical, kLogicalAltLeft);
2398 EXPECT_EQ(record->event->synthesized, true);
2399
2400 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 8));
2401 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
2402 EXPECT_EQ(record->event->physical, kPhysicalShiftLeft);
2403 EXPECT_EQ(record->event->logical, kLogicalGroupNext);
2404 EXPECT_EQ(record->event->synthesized, false);
2405}
2406
2407// Shift + AltLeft results in GDK event whose keyval is MetaLeft but whose
2408// keycode is either AltLeft or Shift keycode (depending on which one was
2409// released last). The physical key is usually deduced from the keycode, but in
2410// this case (Shift + AltLeft) a correction is needed otherwise the physical
2411// key won't be the MetaLeft one.
2412// Regression test for https://github.com/flutter/flutter/issues/96082
2413TEST(FlKeyEmbedderResponderTest, HandlesShiftAltLeftIsMetaLeft) {
2414 g_autoptr(FlDartProject) project = fl_dart_project_new();
2415 g_autoptr(FlEngine) engine = fl_engine_new(project);
2416 EXPECT_TRUE(fl_engine_start(engine, nullptr));
2417
2418 g_autoptr(FlKeyEmbedderResponder) responder =
2420
2421 g_autoptr(GPtrArray) call_records =
2422 g_ptr_array_new_with_free_func(g_object_unref);
2424 SendKeyEvent,
2425 ([&call_records](auto engine, const FlutterKeyEvent* event,
2427 g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
2428 event, callback, user_data));
2429 callback(true, user_data);
2430 return kSuccess;
2431 }));
2432
2433 guint32 now_time = 1;
2434 // A convenient shorthand to simulate events.
2435 auto send_key_event = [responder, &now_time](bool is_press, guint keyval,
2436 guint16 keycode,
2437 GdkModifierType state) {
2438 now_time += 1;
2439 g_autoptr(FlKeyEvent) event =
2440 fl_key_event_new(now_time, is_press, keycode, keyval, state, 0);
2441 g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
2443 responder, event, 0, nullptr,
2444 [](GObject* object, GAsyncResult* result, gpointer user_data) {
2445 gboolean handled;
2447 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
2448 EXPECT_EQ(handled, TRUE);
2449
2450 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
2451 },
2452 loop);
2453 g_main_loop_run(loop);
2454 };
2455
2456 // ShiftLeft + AltLeft
2457 send_key_event(kPress, GDK_KEY_Shift_L, kKeyCodeShiftLeft,
2458 GDK_MODIFIER_RESERVED_25_MASK);
2459 EXPECT_EQ(call_records->len, 1u);
2460 FlKeyEmbedderCallRecord* record =
2461 FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
2462 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
2463 EXPECT_EQ(record->event->physical, kPhysicalShiftLeft);
2464 EXPECT_EQ(record->event->logical, kLogicalShiftLeft);
2465 EXPECT_EQ(record->event->synthesized, false);
2466
2467 send_key_event(kPress, GDK_KEY_Meta_L, kKeyCodeAltLeft,
2468 static_cast<GdkModifierType>(GDK_SHIFT_MASK |
2469 GDK_MODIFIER_RESERVED_25_MASK));
2470 EXPECT_EQ(call_records->len, 2u);
2471 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 1));
2472 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
2473 EXPECT_EQ(record->event->physical, kPhysicalMetaLeft);
2474 EXPECT_EQ(record->event->logical, kLogicalMetaLeft);
2475 EXPECT_EQ(record->event->synthesized, false);
2476
2477 send_key_event(kRelease, GDK_KEY_Meta_L, kKeyCodeAltLeft,
2478 static_cast<GdkModifierType>(GDK_MODIFIER_RESERVED_13_MASK |
2479 GDK_MODIFIER_RESERVED_25_MASK));
2480 send_key_event(kRelease, GDK_KEY_Shift_L, kKeyCodeShiftLeft,
2481 GDK_MODIFIER_RESERVED_25_MASK);
2482 clear_records(call_records);
2483
2484 // ShiftRight + AltLeft
2485 send_key_event(kPress, GDK_KEY_Shift_R, kKeyCodeShiftRight,
2486 GDK_MODIFIER_RESERVED_25_MASK);
2487 EXPECT_EQ(call_records->len, 1u);
2488 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
2489 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
2490 EXPECT_EQ(record->event->physical, kPhysicalShiftRight);
2491 EXPECT_EQ(record->event->logical, kLogicalShiftRight);
2492 EXPECT_EQ(record->event->synthesized, false);
2493
2494 send_key_event(kPress, GDK_KEY_Meta_L, kKeyCodeAltLeft,
2495 static_cast<GdkModifierType>(GDK_SHIFT_MASK |
2496 GDK_MODIFIER_RESERVED_25_MASK));
2497 EXPECT_EQ(call_records->len, 2u);
2498 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 1));
2499 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
2500 EXPECT_EQ(record->event->physical, kPhysicalMetaLeft);
2501 EXPECT_EQ(record->event->logical, kLogicalMetaLeft);
2502 EXPECT_EQ(record->event->synthesized, false);
2503}
@ kSuccess
Definition embedder.h:73
void(* FlutterKeyEventCallback)(bool, void *)
Definition embedder.h:1427
@ kFlutterKeyEventTypeDown
Definition embedder.h:1348
@ kFlutterKeyEventTypeUp
Definition embedder.h:1347
@ kFlutterKeyEventTypeRepeat
Definition embedder.h:1349
FlutterEngine engine
Definition main.cc:84
g_autoptr(GMutexLocker) locker
return TRUE
G_MODULE_EXPORT FlDartProject * fl_dart_project_new()
G_MODULE_EXPORT FlEngine * fl_engine_new(FlDartProject *project)
Definition fl_engine.cc:697
FlutterEngineProcTable * fl_engine_get_embedder_api(FlEngine *self)
Definition fl_engine.cc:868
gboolean fl_engine_start(FlEngine *self, GError **error)
Definition fl_engine.cc:726
FlKeyEmbedderResponder * fl_key_embedder_responder_new(FlEngine *engine)
void fl_key_embedder_responder_handle_event(FlKeyEmbedderResponder *self, FlKeyEvent *event, uint64_t specified_logical_key, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
gboolean fl_key_embedder_responder_handle_event_finish(FlKeyEmbedderResponder *self, GAsyncResult *result, gboolean *handled, GError **error)
G_DEFINE_TYPE(FlKeyEmbedderCallRecord, fl_key_embedder_call_record, G_TYPE_OBJECT) static void fl_key_embedder_call_record_init(FlKeyEmbedderCallRecord *self)
TEST(FlKeyEmbedderResponderTest, SendKeyEvent)
static void invoke_record_callback(FlKeyEmbedderCallRecord *record, bool expected_handled)
static void clear_records(GPtrArray *array)
static void fl_key_embedder_call_record_dispose(GObject *object)
static void fl_key_embedder_call_record_class_init(FlKeyEmbedderCallRecordClass *klass)
G_DECLARE_FINAL_TYPE(FlKeyEmbedderCallRecord, fl_key_embedder_call_record, FL, KEY_EMBEDDER_CALL_RECORD, GObject)
static FlKeyEmbedderCallRecord * fl_key_embedder_call_record_new(const FlutterKeyEvent *event, FlutterKeyEventCallback callback, gpointer user_data)
FlKeyEvent * fl_key_event_new(guint32 time, gboolean is_press, guint16 keycode, guint keyval, GdkModifierType state, guint8 group)
constexpr guint16 kKeyCodeKeyA
static void send_key_event(FlTextInputHandler *handler, gint keyval, gint state=0)
FlutterDesktopBinaryReply callback
constexpr int kKeyCodeShiftLeft
constexpr int kKeyCodeControlLeft
#define MOCK_ENGINE_PROC(proc, mock_impl)
FlutterEngineSendKeyEventFnPtr SendKeyEvent
Definition embedder.h:3717
const char * character
Definition embedder.h:1409