| Flutter Linux Embedder |

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