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