| Flutter Linux Embedder |

Classes | Functions
fl_key_embedder_responder_test.cc File Reference
`#include "flutter/shell/platform/linux/fl_key_embedder_responder.h"`
`#include "gtest/gtest.h"`
`#include "flutter/shell/platform/embedder/test_utils/key_codes.g.h"`
`#include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h"`
`#include "flutter/shell/platform/linux/public/flutter_linux/fl_engine.h"`
`#include "flutter/shell/platform/linux/testing/fl_test.h"`

Go to the source code of this file.

## Classes
struct | _FlKeyEmbedderCallRecord

## Functions
static void | clear_records (GPtrArray *array)
| G_DECLARE_FINAL_TYPE (FlKeyEmbedderCallRecord, fl_key_embedder_call_record, FL, KEY_EMBEDDER_CALL_RECORD, GObject)
| G_DEFINE_TYPE (FlKeyEmbedderCallRecord, fl_key_embedder_call_record, G_TYPE_OBJECT) static void fl_key_embedder_call_record_init(FlKeyEmbedderCallRecord *self)
static void | fl_key_embedder_call_record_dispose (GObject *object)
static void | fl_key_embedder_call_record_class_init (FlKeyEmbedderCallRecordClass *klass)
static FlKeyEmbedderCallRecord * | fl_key_embedder_call_record_new (const FlutterKeyEvent *event, FlutterKeyEventCallback callback, gpointer user_data)
static void | invoke_record_callback (FlKeyEmbedderCallRecord *record, bool expected_handled)
| TEST (FlKeyEmbedderResponderTest, SendKeyEvent)
| TEST (FlKeyEmbedderResponderTest, UsesSpecifiedLogicalKey)
| TEST (FlKeyEmbedderResponderTest, PressShiftDuringLetterKeyTap)
| TEST (FlKeyEmbedderResponderTest, TapNumPadKeysBetweenNumLockEvents)
| TEST (FlKeyEmbedderResponderTest, ReleaseShiftKeyBetweenDigitKeyEvents)
| TEST (FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEvents)
| TEST (FlKeyEmbedderResponderTest, TapLetterKeysBetweenCapsLockEventsReversed)
| TEST (FlKeyEmbedderResponderTest, TurnDuplicateDownEventsToRepeats)
| TEST (FlKeyEmbedderResponderTest, IgnoreAbruptUpEvent)
| TEST (FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnSelfEvents)
| TEST (FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnNonSelfEvents)
| TEST (FlKeyEmbedderResponderTest, SynthesizeForDesyncPressingStateOnRemappedEvents)
| TEST (FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnNonSelfEvents)
| TEST (FlKeyEmbedderResponderTest, SynthesizeForDesyncLockModeOnSelfEvents)
| TEST (FlKeyEmbedderResponderTest, SynthesizationOccursOnIgnoredEvents)
| TEST (FlKeyEmbedderResponderTest, HandlesShiftAltVersusGroupNext)
| TEST (FlKeyEmbedderResponderTest, HandlesShiftAltLeftIsMetaLeft)

## Function Documentation

## ◆ clear_records()

static void clear_records | ( | GPtrArray * | array | ) |
| static

Definition at line 33 of file fl_key_embedder_responder_test.cc.

33 {
34 g_ptr_array_remove_range(array, 0, array->len);
35 }

Referenced by TEST().

## ◆ fl_key_embedder_call_record_class_init()

static void fl_key_embedder_call_record_class_init | ( | FlKeyEmbedderCallRecordClass * | klass | ) |
| static

Definition at line 70 of file fl_key_embedder_responder_test.cc.

71 {
72 G_OBJECT_CLASS(klass)->dispose = fl_key_embedder_call_record_dispose;
73 }
fl_key_embedder_call_record_dispose
static void fl_key_embedder_call_record_dispose(GObject *object)
Definition: fl_key_embedder_responder_test.cc:58

References fl_key_embedder_call_record_dispose().

## ◆ fl_key_embedder_call_record_dispose()

static void fl_key_embedder_call_record_dispose | ( | GObject * | object | ) |
| static

Definition at line 58 of file fl_key_embedder_responder_test.cc.

58 {
59 g_return_if_fail(FL_IS_KEY_EMBEDDER_CALL_RECORD(object));
60
61 FlKeyEmbedderCallRecord* self = FL_KEY_EMBEDDER_CALL_RECORD(object);
62 if (self->event != nullptr) {
63 g_free(const_cast<char*>(self->event->character));
64 g_free(self->event);
65 }
66 G_OBJECT_CLASS(fl_key_embedder_call_record_parent_class)->dispose(object);
67 }

Referenced by fl_key_embedder_call_record_class_init().

## ◆ fl_key_embedder_call_record_new()

static FlKeyEmbedderCallRecord* fl_key_embedder_call_record_new | ( | const FlutterKeyEvent * | event,
|  | FlutterKeyEventCallback | callback,
|  | gpointer | user_data
| ) |  |
| static

Definition at line 75 of file fl_key_embedder_responder_test.cc.

78 {
79 g_return_val_if_fail(event != nullptr, nullptr);
80
81 FlKeyEmbedderCallRecord* self = FL_KEY_EMBEDDER_CALL_RECORD(
82 g_object_new(fl_key_embedder_call_record_get_type(), nullptr));
83
84 FlutterKeyEvent* clone_event = g_new(FlutterKeyEvent, 1);
85 *clone_event = *event;
86 if (event->character != nullptr) {
87 size_t character_length = strlen(event->character);
88 char* clone_character = g_new(char, character_length + 1);
89 strncpy(clone_character, event->character, character_length + 1);
90 clone_event->character = clone_character;
91 }
92 self->event = clone_event;
93 self->callback = callback;
94 self->user_data = user_data;
95
96 return self;
97 }
user_data
G_BEGIN_DECLS G_MODULE_EXPORT FlValue gpointer user_data
Definition: fl_event_channel.h:90

References user_data.

Referenced by TEST().

## ◆ G_DECLARE_FINAL_TYPE()

G_DECLARE_FINAL_TYPE | ( | FlKeyEmbedderCallRecord | ,
|  | fl_key_embedder_call_record | ,
|  | FL | ,
|  | KEY_EMBEDDER_CALL_RECORD | ,
|  | GObject |
| ) |  |

## ◆ G_DEFINE_TYPE()

G_DEFINE_TYPE | ( | FlKeyEmbedderCallRecord | ,
|  | fl_key_embedder_call_record | ,
|  | G_TYPE_OBJECT |
| ) |  |

Definition at line 51 of file fl_key_embedder_responder_test.cc.

55 {}

## ◆ invoke_record_callback()

static void invoke_record_callback | ( | FlKeyEmbedderCallRecord * | record,
|  | bool | expected_handled
| ) |  |
| static

Definition at line 99 of file fl_key_embedder_responder_test.cc.

100 {
101 g_return_if_fail(record->callback != nullptr);
102 record->callback(expected_handled, record->user_data);
103 }

Referenced by TEST().

## ◆ TEST() [1/17]

TEST | ( | FlKeyEmbedderResponderTest | ,
|  | HandlesShiftAltLeftIsMetaLeft |
| ) |  |

Definition at line 2413 of file fl_key_embedder_responder_test.cc.

2413 {
2414 g_autoptr(FlDartProject) project = fl_dart_project_new();
2415 g_autoptr(FlEngine) engine = fl_engine_new(project);
2416 EXPECT_TRUE(fl_engine_start(engine, nullptr));
2417
2418 g_autoptr(FlKeyEmbedderResponder) responder =
2419 fl_key_embedder_responder_new(engine);
2420
2421 g_autoptr(GPtrArray) call_records =
2422 g_ptr_array_new_with_free_func(g_object_unref);
2423 fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
2424 SendKeyEvent,
2425 ([&call_records](auto engine, const FlutterKeyEvent* event,
2426 FlutterKeyEventCallback callback, void* user_data) {
2427 g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
2428 event, callback, user_data));
2429 callback(true, user_data);
2430 return kSuccess;
2431 }));
2432
2433 guint32 now_time = 1;
2434 // A convenient shorthand to simulate events.
2435 auto send_key_event = [responder, &now_time](bool is_press, guint keyval,
2436 guint16 keycode,
2437 GdkModifierType state) {
2438 now_time += 1;
2439 g_autoptr(FlKeyEvent) event =
2440 fl_key_event_new(now_time, is_press, keycode, keyval, state, 0);
2441 g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
2442 fl_key_embedder_responder_handle_event(
2443 responder, event, 0, nullptr,
2444 [](GObject* object, GAsyncResult* result, gpointer user_data) {
2445 gboolean handled;
2446 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
2447 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
2448 EXPECT_EQ(handled, TRUE);
2449
2450 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
2451 },
2452 loop);
2453 g_main_loop_run(loop);
2454 };
2455
2456 // ShiftLeft + AltLeft
2457 send_key_event(kPress, GDK_KEY_Shift_L, kKeyCodeShiftLeft,
2458 GDK_MODIFIER_RESERVED_25_MASK);
2459 EXPECT_EQ(call_records->len, 1u);
2460 FlKeyEmbedderCallRecord* record =
2461 FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
2462 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
2463 EXPECT_EQ(record->event->physical, kPhysicalShiftLeft);
2464 EXPECT_EQ(record->event->logical, kLogicalShiftLeft);
2465 EXPECT_EQ(record->event->synthesized, false);
2466
2467 send_key_event(kPress, GDK_KEY_Meta_L, kKeyCodeAltLeft,
2468 static_cast<GdkModifierType>(GDK_SHIFT_MASK |
2469 GDK_MODIFIER_RESERVED_25_MASK));
2470 EXPECT_EQ(call_records->len, 2u);
2471 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 1));
2472 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
2473 EXPECT_EQ(record->event->physical, kPhysicalMetaLeft);
2474 EXPECT_EQ(record->event->logical, kLogicalMetaLeft);
2475 EXPECT_EQ(record->event->synthesized, false);
2476
2477 send_key_event(kRelease, GDK_KEY_Meta_L, kKeyCodeAltLeft,
2478 static_cast<GdkModifierType>(GDK_MODIFIER_RESERVED_13_MASK |
2479 GDK_MODIFIER_RESERVED_25_MASK));
2480 send_key_event(kRelease, GDK_KEY_Shift_L, kKeyCodeShiftLeft,
2481 GDK_MODIFIER_RESERVED_25_MASK);
2482 clear_records(call_records);
2483
2484 // ShiftRight + AltLeft
2485 send_key_event(kPress, GDK_KEY_Shift_R, kKeyCodeShiftRight,
2486 GDK_MODIFIER_RESERVED_25_MASK);
2487 EXPECT_EQ(call_records->len, 1u);
2488 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
2489 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
2490 EXPECT_EQ(record->event->physical, kPhysicalShiftRight);
2491 EXPECT_EQ(record->event->logical, kLogicalShiftRight);
2492 EXPECT_EQ(record->event->synthesized, false);
2493
2494 send_key_event(kPress, GDK_KEY_Meta_L, kKeyCodeAltLeft,
2495 static_cast<GdkModifierType>(GDK_SHIFT_MASK |
2496 GDK_MODIFIER_RESERVED_25_MASK));
2497 EXPECT_EQ(call_records->len, 2u);
2498 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 1));
2499 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
2500 EXPECT_EQ(record->event->physical, kPhysicalMetaLeft);
2501 EXPECT_EQ(record->event->logical, kLogicalMetaLeft);
2502 EXPECT_EQ(record->event->synthesized, false);
2503 }
g_autoptr
g_autoptr(GMutexLocker) locker
TRUE
return TRUE
Definition: fl_compositor_software.cc:68
fl_dart_project_new
G_MODULE_EXPORT FlDartProject * fl_dart_project_new()
Definition: fl_dart_project.cc:52
fl_engine_get_embedder_api
FlutterEngineProcTable * fl_engine_get_embedder_api(FlEngine *self)
Definition: fl_engine.cc:864
fl_engine_start
gboolean fl_engine_start(FlEngine *self, GError **error)
Definition: fl_engine.cc:726
fl_engine_new
G_MODULE_EXPORT FlEngine * fl_engine_new(FlDartProject *project)
Definition: fl_engine.cc:697
fl_key_embedder_responder_handle_event
void fl_key_embedder_responder_handle_event(FlKeyEmbedderResponder *self, FlKeyEvent *event, uint64_t specified_logical_key, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
Definition: fl_key_embedder_responder.cc:737
fl_key_embedder_responder_handle_event_finish
gboolean fl_key_embedder_responder_handle_event_finish(FlKeyEmbedderResponder *self, GAsyncResult *result, gboolean *handled, GError **error)
Definition: fl_key_embedder_responder.cc:757
fl_key_embedder_responder_new
FlKeyEmbedderResponder * fl_key_embedder_responder_new(FlEngine *engine)
Definition: fl_key_embedder_responder.cc:181
clear_records
static void clear_records(GPtrArray *array)
Definition: fl_key_embedder_responder_test.cc:33
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:75
fl_key_event_new
FlKeyEvent * fl_key_event_new(guint32 time, gboolean is_press, guint16 keycode, guint keyval, GdkModifierType state, guint8 group)
Definition: fl_key_event.cc:34
send_key_event
static void send_key_event(FlTextInputHandler *handler, gint keyval, gint state=0)
Definition: fl_text_input_handler_test.cc:143

References clear_records(), fl_dart_project_new(), fl_engine_get_embedder_api(), fl_engine_new(), fl_engine_start(), fl_key_embedder_call_record_new(), fl_key_embedder_responder_handle_event(), fl_key_embedder_responder_handle_event_finish(), fl_key_embedder_responder_new(), fl_key_event_new(), g_autoptr(), send_key_event(), TRUE, and user_data.

## ◆ TEST() [2/17]

TEST | ( | FlKeyEmbedderResponderTest | ,
|  | HandlesShiftAltVersusGroupNext |
| ) |  |

Definition at line 2286 of file fl_key_embedder_responder_test.cc.

2286 {
2287 g_autoptr(FlDartProject) project = fl_dart_project_new();
2288 g_autoptr(FlEngine) engine = fl_engine_new(project);
2289 EXPECT_TRUE(fl_engine_start(engine, nullptr));
2290
2291 g_autoptr(FlKeyEmbedderResponder) responder =
2292 fl_key_embedder_responder_new(engine);
2293
2294 g_autoptr(GPtrArray) call_records =
2295 g_ptr_array_new_with_free_func(g_object_unref);
2296 fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
2297 SendKeyEvent,
2298 ([&call_records](auto engine, const FlutterKeyEvent* event,
2299 FlutterKeyEventCallback callback, void* user_data) {
2300 g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
2301 event, callback, user_data));
2302 callback(true, user_data);
2303 return kSuccess;
2304 }));
2305
2306 guint32 now_time = 1;
2307 // A convenient shorthand to simulate events.
2308 auto send_key_event = [responder, &now_time](bool is_press, guint keyval,
2309 guint16 keycode,
2310 GdkModifierType state) {
2311 now_time += 1;
2312 g_autoptr(FlKeyEvent) event =
2313 fl_key_event_new(now_time, is_press, keycode, keyval, state, 0);
2314 g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
2315 fl_key_embedder_responder_handle_event(
2316 responder, event, 0, nullptr,
2317 [](GObject* object, GAsyncResult* result, gpointer user_data) {
2318 gboolean handled;
2319 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
2320 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
2321 EXPECT_EQ(handled, TRUE);
2322
2323 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
2324 },
2325 loop);
2326 g_main_loop_run(loop);
2327 };
2328
2329 send_key_event(kPress, GDK_KEY_Shift_L, kKeyCodeShiftLeft,
2330 GDK_MODIFIER_RESERVED_25_MASK);
2331 EXPECT_EQ(call_records->len, 1u);
2332 FlKeyEmbedderCallRecord* record =
2333 FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
2334 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
2335 EXPECT_EQ(record->event->physical, kPhysicalShiftLeft);
2336 EXPECT_EQ(record->event->logical, kLogicalShiftLeft);
2337 EXPECT_EQ(record->event->synthesized, false);
2338
2339 send_key_event(kPress, GDK_KEY_Meta_R, kKeyCodeAltRight,
2340 static_cast<GdkModifierType>(GDK_SHIFT_MASK |
2341 GDK_MODIFIER_RESERVED_25_MASK));
2342 EXPECT_EQ(call_records->len, 2u);
2343 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 1));
2344 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
2345 EXPECT_EQ(record->event->physical, kPhysicalAltRight);
2346 EXPECT_EQ(record->event->logical, kLogicalMetaRight);
2347 EXPECT_EQ(record->event->synthesized, false);
2348
2349 send_key_event(kRelease, GDK_KEY_ISO_Next_Group, kKeyCodeShiftLeft,
2350 static_cast<GdkModifierType>(GDK_SHIFT_MASK | GDK_MOD1_MASK |
2351 GDK_MODIFIER_RESERVED_25_MASK));
2352 EXPECT_EQ(call_records->len, 5u);
2353 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 2));
2354 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
2355 EXPECT_EQ(record->event->physical, kPhysicalAltLeft);
2356 EXPECT_EQ(record->event->logical, kLogicalAltLeft);
2357 EXPECT_EQ(record->event->synthesized, true);
2358
2359 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 3));
2360 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
2361 EXPECT_EQ(record->event->physical, kPhysicalAltRight);
2362 EXPECT_EQ(record->event->logical, kLogicalMetaRight);
2363 EXPECT_EQ(record->event->synthesized, true);
2364
2365 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 4));
2366 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
2367 EXPECT_EQ(record->event->physical, kPhysicalShiftLeft);
2368 EXPECT_EQ(record->event->logical, kLogicalShiftLeft);
2369 EXPECT_EQ(record->event->synthesized, false);
2370
2371 send_key_event(kPress, GDK_KEY_ISO_Next_Group, kKeyCodeShiftLeft,
2372 static_cast<GdkModifierType>(GDK_MOD1_MASK |
2373 GDK_MODIFIER_RESERVED_25_MASK));
2374 EXPECT_EQ(call_records->len, 6u);
2375 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 5));
2376 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
2377 EXPECT_EQ(record->event->physical, kPhysicalShiftLeft);
2378 EXPECT_EQ(record->event->logical, kLogicalGroupNext);
2379 EXPECT_EQ(record->event->synthesized, false);
2380
2381 send_key_event(kRelease, GDK_KEY_ISO_Level3_Shift, kKeyCodeAltRight,
2382 static_cast<GdkModifierType>(GDK_MOD1_MASK |
2383 GDK_MODIFIER_RESERVED_13_MASK |
2384 GDK_MODIFIER_RESERVED_25_MASK));
2385 EXPECT_EQ(call_records->len, 7u);
2386 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 6));
2387 EXPECT_EQ(record->event->physical, 0u);
2388 EXPECT_EQ(record->event->logical, 0u);
2389
2390 send_key_event(kRelease, GDK_KEY_Shift_L, kKeyCodeShiftLeft,
2391 static_cast<GdkModifierType>(GDK_MODIFIER_RESERVED_13_MASK |
2392 GDK_MODIFIER_RESERVED_25_MASK));
2393 EXPECT_EQ(call_records->len, 9u);
2394 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 7));
2395 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
2396 EXPECT_EQ(record->event->physical, kPhysicalAltLeft);
2397 EXPECT_EQ(record->event->logical, kLogicalAltLeft);
2398 EXPECT_EQ(record->event->synthesized, true);
2399
2400 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 8));
2401 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
2402 EXPECT_EQ(record->event->physical, kPhysicalShiftLeft);
2403 EXPECT_EQ(record->event->logical, kLogicalGroupNext);
2404 EXPECT_EQ(record->event->synthesized, false);
2405 }

References fl_dart_project_new(), fl_engine_get_embedder_api(), fl_engine_new(), fl_engine_start(), fl_key_embedder_call_record_new(), fl_key_embedder_responder_handle_event(), fl_key_embedder_responder_handle_event_finish(), fl_key_embedder_responder_new(), fl_key_event_new(), g_autoptr(), send_key_event(), TRUE, and user_data.

## ◆ TEST() [3/17]

TEST | ( | FlKeyEmbedderResponderTest | ,
|  | IgnoreAbruptUpEvent |
| ) |  |

Definition at line 1432 of file fl_key_embedder_responder_test.cc.

1432 {
1433 g_autoptr(FlDartProject) project = fl_dart_project_new();
1434 g_autoptr(FlEngine) engine = fl_engine_new(project);
1435 EXPECT_TRUE(fl_engine_start(engine, nullptr));
1436
1437 g_autoptr(FlKeyEmbedderResponder) responder =
1438 fl_key_embedder_responder_new(engine);
1439
1440 g_autoptr(GPtrArray) call_records =
1441 g_ptr_array_new_with_free_func(g_object_unref);
1442 fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
1443 SendKeyEvent,
1444 ([&call_records](auto engine, const FlutterKeyEvent* event,
1445 FlutterKeyEventCallback callback, void* user_data) {
1446 g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
1447 event, callback, user_data));
1448 return kSuccess;
1449 }));
1450
1451 // Release KeyA before it was even pressed.
1452 g_autoptr(FlKeyEvent) event =
1453 fl_key_event_new(103, kRelease, kKeyCodeKeyA, GDK_KEY_q,
1454 static_cast<GdkModifierType>(0), 0);
1455 g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
1456 fl_key_embedder_responder_handle_event(
1457 responder, event, 0, nullptr,
1458 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1459 gboolean handled;
1460 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
1461 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1462 EXPECT_EQ(handled, TRUE);
1463
1464 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1465 },
1466 loop);
1467
1468 EXPECT_EQ(call_records->len, 1u);
1469
1470 FlKeyEmbedderCallRecord* record =
1471 FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1472 EXPECT_EQ(record->event->physical, 0ull);
1473 EXPECT_EQ(record->event->logical, 0ull);
1474 EXPECT_STREQ(record->event->character, nullptr);
1475 EXPECT_EQ(record->event->synthesized, false);
1476
1477 invoke_record_callback(record, TRUE);
1478 g_main_loop_run(loop);
1479 }
invoke_record_callback
static void invoke_record_callback(FlKeyEmbedderCallRecord *record, bool expected_handled)
Definition: fl_key_embedder_responder_test.cc:99
kKeyCodeKeyA
constexpr guint16 kKeyCodeKeyA
Definition: fl_keyboard_handler_test.cc:24

References fl_dart_project_new(), fl_engine_get_embedder_api(), fl_engine_new(), fl_engine_start(), fl_key_embedder_call_record_new(), fl_key_embedder_responder_handle_event(), fl_key_embedder_responder_handle_event_finish(), fl_key_embedder_responder_new(), fl_key_event_new(), g_autoptr(), invoke_record_callback(), kKeyCodeKeyA, TRUE, and user_data.

## ◆ TEST() [4/17]

TEST | ( | FlKeyEmbedderResponderTest | ,
|  | PressShiftDuringLetterKeyTap |
| ) |  |

Definition at line 306 of file fl_key_embedder_responder_test.cc.

306 {
307 g_autoptr(FlDartProject) project = fl_dart_project_new();
308 g_autoptr(FlEngine) engine = fl_engine_new(project);
309 EXPECT_TRUE(fl_engine_start(engine, nullptr));
310
311 g_autoptr(FlKeyEmbedderResponder) responder =
312 fl_key_embedder_responder_new(engine);
313
314 g_autoptr(GPtrArray) call_records =
315 g_ptr_array_new_with_free_func(g_object_unref);
316 fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
317 SendKeyEvent,
318 ([&call_records](auto engine, const FlutterKeyEvent* event,
319 FlutterKeyEventCallback callback, void* user_data) {
320 g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
321 event, callback, user_data));
322 return kSuccess;
323 }));
324
325 // Press shift right
326 g_autoptr(FlKeyEvent) event1 =
327 fl_key_event_new(101, kPress, kKeyCodeShiftRight, GDK_KEY_Shift_R,
328 static_cast<GdkModifierType>(0), 0);
329 g_autoptr(GMainLoop) loop1 = g_main_loop_new(nullptr, 0);
330 fl_key_embedder_responder_handle_event(
331 responder, event1, 0, nullptr,
332 [](GObject* object, GAsyncResult* result, gpointer user_data) {
333 gboolean handled;
334 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
335 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
336 EXPECT_EQ(handled, TRUE);
337
338 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
339 },
340 loop1);
341
342 EXPECT_EQ(call_records->len, 1u);
343 FlKeyEmbedderCallRecord* record =
344 FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
345 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
346 EXPECT_EQ(record->event->physical, kPhysicalShiftRight);
347 EXPECT_EQ(record->event->logical, kLogicalShiftRight);
348 EXPECT_STREQ(record->event->character, nullptr);
349 EXPECT_EQ(record->event->synthesized, false);
350
351 invoke_record_callback(record, TRUE);
352 g_main_loop_run(loop1);
353 clear_records(call_records);
354
355 // Press key A
356 g_autoptr(FlKeyEvent) event2 =
357 fl_key_event_new(102, kPress, kKeyCodeKeyA, GDK_KEY_A, GDK_SHIFT_MASK, 0);
358 g_autoptr(GMainLoop) loop2 = g_main_loop_new(nullptr, 0);
359 fl_key_embedder_responder_handle_event(
360 responder, event2, 0, nullptr,
361 [](GObject* object, GAsyncResult* result, gpointer user_data) {
362 gboolean handled;
363 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
364 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
365 EXPECT_EQ(handled, TRUE);
366
367 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
368 },
369 loop2);
370
371 EXPECT_EQ(call_records->len, 1u);
372 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
373 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
374 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
375 EXPECT_EQ(record->event->logical, kLogicalKeyA);
376 EXPECT_STREQ(record->event->character, "A");
377 EXPECT_EQ(record->event->synthesized, false);
378
379 invoke_record_callback(record, TRUE);
380 g_main_loop_run(loop2);
381 clear_records(call_records);
382
383 // Release shift right
384 g_autoptr(FlKeyEvent) event3 = fl_key_event_new(
385 103, kRelease, kKeyCodeShiftRight, GDK_KEY_Shift_R, GDK_SHIFT_MASK, 0);
386 g_autoptr(GMainLoop) loop3 = g_main_loop_new(nullptr, 0);
387 fl_key_embedder_responder_handle_event(
388 responder, event3, 0, nullptr,
389 [](GObject* object, GAsyncResult* result, gpointer user_data) {
390 gboolean handled;
391 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
392 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
393 EXPECT_EQ(handled, TRUE);
394
395 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
396 },
397 loop3);
398
399 EXPECT_EQ(call_records->len, 1u);
400 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
401 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
402 EXPECT_EQ(record->event->physical, kPhysicalShiftRight);
403 EXPECT_EQ(record->event->logical, kLogicalShiftRight);
404 EXPECT_STREQ(record->event->character, nullptr);
405 EXPECT_EQ(record->event->synthesized, false);
406
407 invoke_record_callback(record, TRUE);
408 g_main_loop_run(loop3);
409 clear_records(call_records);
410
411 // Release key A
412 g_autoptr(FlKeyEvent) event4 =
413 fl_key_event_new(104, kRelease, kKeyCodeKeyA, GDK_KEY_A,
414 static_cast<GdkModifierType>(0), 0);
415 g_autoptr(GMainLoop) loop4 = g_main_loop_new(nullptr, 0);
416 fl_key_embedder_responder_handle_event(
417 responder, event4, 0, nullptr,
418 [](GObject* object, GAsyncResult* result, gpointer user_data) {
419 gboolean handled;
420 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
421 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
422 EXPECT_EQ(handled, TRUE);
423
424 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
425 },
426 loop4);
427
428 EXPECT_EQ(call_records->len, 1u);
429 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
430 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
431 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
432 EXPECT_EQ(record->event->logical, kLogicalKeyA);
433 EXPECT_STREQ(record->event->character, nullptr);
434 EXPECT_EQ(record->event->synthesized, false);
435
436 invoke_record_callback(record, TRUE);
437 g_main_loop_run(loop4);
438 }

References clear_records(), fl_dart_project_new(), fl_engine_get_embedder_api(), fl_engine_new(), fl_engine_start(), fl_key_embedder_call_record_new(), fl_key_embedder_responder_handle_event(), fl_key_embedder_responder_handle_event_finish(), fl_key_embedder_responder_new(), fl_key_event_new(), g_autoptr(), invoke_record_callback(), kKeyCodeKeyA, TRUE, and user_data.

## ◆ TEST() [5/17]

TEST | ( | FlKeyEmbedderResponderTest | ,
|  | ReleaseShiftKeyBetweenDigitKeyEvents |
| ) |  |

Definition at line 698 of file fl_key_embedder_responder_test.cc.

698 {
699 g_autoptr(FlDartProject) project = fl_dart_project_new();
700 g_autoptr(FlEngine) engine = fl_engine_new(project);
701 EXPECT_TRUE(fl_engine_start(engine, nullptr));
702
703 g_autoptr(FlKeyEmbedderResponder) responder =
704 fl_key_embedder_responder_new(engine);
705
706 g_autoptr(GPtrArray) call_records =
707 g_ptr_array_new_with_free_func(g_object_unref);
708 fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
709 SendKeyEvent,
710 ([&call_records](auto engine, const FlutterKeyEvent* event,
711 FlutterKeyEventCallback callback, void* user_data) {
712 g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
713 event, callback, user_data));
714 return kSuccess;
715 }));
716
717 GdkModifierType state = static_cast<GdkModifierType>(0);
718
719 // Press shift left
720 g_autoptr(FlKeyEvent) event1 = fl_key_event_new(
721 101, kPress, kKeyCodeShiftLeft, GDK_KEY_Shift_L, state, 0);
722 g_autoptr(GMainLoop) loop1 = g_main_loop_new(nullptr, 0);
723 fl_key_embedder_responder_handle_event(
724 responder, event1, 0, nullptr,
725 [](GObject* object, GAsyncResult* result, gpointer user_data) {
726 gboolean handled;
727 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
728 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
729 EXPECT_EQ(handled, TRUE);
730
731 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
732 },
733 loop1);
734
735 EXPECT_EQ(call_records->len, 1u);
736 FlKeyEmbedderCallRecord* record =
737 FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
738 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
739 EXPECT_EQ(record->event->physical, kPhysicalShiftLeft);
740 EXPECT_EQ(record->event->logical, kLogicalShiftLeft);
741 EXPECT_STREQ(record->event->character, nullptr);
742 EXPECT_EQ(record->event->synthesized, false);
743
744 invoke_record_callback(record, TRUE);
745 g_main_loop_run(loop1);
746 clear_records(call_records);
747
748 state = GDK_SHIFT_MASK;
749
750 // Press digit 1, which is '!' on a US keyboard
751 g_autoptr(FlKeyEvent) event2 =
752 fl_key_event_new(102, kPress, kKeyCodeDigit1, GDK_KEY_exclam, state, 0);
753 g_autoptr(GMainLoop) loop2 = g_main_loop_new(nullptr, 0);
754 fl_key_embedder_responder_handle_event(
755 responder, event2, 0, nullptr,
756 [](GObject* object, GAsyncResult* result, gpointer user_data) {
757 gboolean handled;
758 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
759 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
760 EXPECT_EQ(handled, TRUE);
761
762 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
763 },
764 loop2);
765
766 EXPECT_EQ(call_records->len, 1u);
767 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
768 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
769 EXPECT_EQ(record->event->physical, kPhysicalDigit1);
770 EXPECT_EQ(record->event->logical, kLogicalExclamation);
771 EXPECT_STREQ(record->event->character, "!");
772 EXPECT_EQ(record->event->synthesized, false);
773
774 invoke_record_callback(record, TRUE);
775 g_main_loop_run(loop2);
776 clear_records(call_records);
777
778 // Release shift
779 g_autoptr(FlKeyEvent) event3 = fl_key_event_new(
780 103, kRelease, kKeyCodeShiftLeft, GDK_KEY_Shift_L, state, 0);
781 g_autoptr(GMainLoop) loop3 = g_main_loop_new(nullptr, 0);
782 fl_key_embedder_responder_handle_event(
783 responder, event3, 0, nullptr,
784 [](GObject* object, GAsyncResult* result, gpointer user_data) {
785 gboolean handled;
786 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
787 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
788 EXPECT_EQ(handled, TRUE);
789
790 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
791 },
792 loop3);
793
794 EXPECT_EQ(call_records->len, 1u);
795 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
796 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
797 EXPECT_EQ(record->event->physical, kPhysicalShiftLeft);
798 EXPECT_EQ(record->event->logical, kLogicalShiftLeft);
799 EXPECT_STREQ(record->event->character, nullptr);
800 EXPECT_EQ(record->event->synthesized, false);
801
802 invoke_record_callback(record, TRUE);
803 g_main_loop_run(loop3);
804 clear_records(call_records);
805
806 state = static_cast<GdkModifierType>(0);
807
808 // Release digit 1, which is "1" because shift has been released.
809 g_autoptr(FlKeyEvent) event4 =
810 fl_key_event_new(104, kRelease, kKeyCodeDigit1, GDK_KEY_1, state, 0);
811 g_autoptr(GMainLoop) loop4 = g_main_loop_new(nullptr, 0);
812 fl_key_embedder_responder_handle_event(
813 responder, event4, 0, nullptr,
814 [](GObject* object, GAsyncResult* result, gpointer user_data) {
815 gboolean handled;
816 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
817 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
818 EXPECT_EQ(handled, TRUE);
819
820 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
821 },
822 loop4);
823
824 EXPECT_EQ(call_records->len, 1u);
825 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
826 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
827 EXPECT_EQ(record->event->physical, kPhysicalDigit1);
828 EXPECT_EQ(record->event->logical, kLogicalExclamation); // Important
829 EXPECT_STREQ(record->event->character, nullptr);
830 EXPECT_EQ(record->event->synthesized, false);
831
832 invoke_record_callback(record, TRUE);
833 g_main_loop_run(loop4);
834 }

References clear_records(), fl_dart_project_new(), fl_engine_get_embedder_api(), fl_engine_new(), fl_engine_start(), fl_key_embedder_call_record_new(), fl_key_embedder_responder_handle_event(), fl_key_embedder_responder_handle_event_finish(), fl_key_embedder_responder_new(), fl_key_event_new(), g_autoptr(), invoke_record_callback(), TRUE, and user_data.

## ◆ TEST() [6/17]

TEST | ( | FlKeyEmbedderResponderTest | ,
|  | SendKeyEvent |
| ) |  |

Definition at line 106 of file fl_key_embedder_responder_test.cc.

106 {
107 g_autoptr(FlDartProject) project = fl_dart_project_new();
108 g_autoptr(FlEngine) engine = fl_engine_new(project);
109 EXPECT_TRUE(fl_engine_start(engine, nullptr));
110
111 g_autoptr(FlKeyEmbedderResponder) responder =
112 fl_key_embedder_responder_new(engine);
113
114 g_autoptr(GPtrArray) call_records =
115 g_ptr_array_new_with_free_func(g_object_unref);
116 fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
117 SendKeyEvent,
118 ([&call_records](auto engine, const FlutterKeyEvent* event,
119 FlutterKeyEventCallback callback, void* user_data) {
120 g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
121 event, callback, user_data));
122 return kSuccess;
123 }));
124
125 // On a QWERTY keyboard, press key Q (physically key A), and release.
126 // Key down
127 g_autoptr(FlKeyEvent) event1 =
128 fl_key_event_new(12345, kPress, kKeyCodeKeyA, GDK_KEY_a,
129 static_cast<GdkModifierType>(0), 0);
130 g_autoptr(GMainLoop) loop1 = g_main_loop_new(nullptr, 0);
131 fl_key_embedder_responder_handle_event(
132 responder, event1, 0, nullptr,
133 [](GObject* object, GAsyncResult* result, gpointer user_data) {
134 gboolean handled;
135 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
136 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
137 EXPECT_EQ(handled, TRUE);
138
139 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
140 },
141 loop1);
142
143 EXPECT_EQ(call_records->len, 1u);
144 FlKeyEmbedderCallRecord* record =
145 FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
146 EXPECT_EQ(record->event->struct_size, sizeof(FlutterKeyEvent));
147 EXPECT_EQ(record->event->timestamp, 12345000);
148 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
149 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
150 EXPECT_EQ(record->event->logical, kLogicalKeyA);
151 EXPECT_STREQ(record->event->character, "a");
152 EXPECT_EQ(record->event->synthesized, false);
153
154 invoke_record_callback(record, TRUE);
155 g_main_loop_run(loop1);
156 clear_records(call_records);
157
158 // Key up
159 g_autoptr(FlKeyEvent) event2 =
160 fl_key_event_new(12346, kRelease, kKeyCodeKeyA, GDK_KEY_a,
161 static_cast<GdkModifierType>(0), 0);
162 g_autoptr(GMainLoop) loop2 = g_main_loop_new(nullptr, 0);
163 fl_key_embedder_responder_handle_event(
164 responder, event2, 0, nullptr,
165 [](GObject* object, GAsyncResult* result, gpointer user_data) {
166 gboolean handled;
167 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
168 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
169 EXPECT_EQ(handled, FALSE);
170
171 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
172 },
173 loop2);
174
175 EXPECT_EQ(call_records->len, 1u);
176 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
177 EXPECT_EQ(record->event->struct_size, sizeof(FlutterKeyEvent));
178 EXPECT_EQ(record->event->timestamp, 12346000);
179 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
180 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
181 EXPECT_EQ(record->event->logical, kLogicalKeyA);
182 EXPECT_STREQ(record->event->character, nullptr);
183 EXPECT_EQ(record->event->synthesized, false);
184
185 invoke_record_callback(record, FALSE);
186 g_main_loop_run(loop2);
187 clear_records(call_records);
188
189 // On an AZERTY keyboard, press key Q (physically key A), and release.
190 // Key down
191 g_autoptr(FlKeyEvent) event3 =
192 fl_key_event_new(12347, kPress, kKeyCodeKeyA, GDK_KEY_q,
193 static_cast<GdkModifierType>(0), 0);
194 g_autoptr(GMainLoop) loop3 = g_main_loop_new(nullptr, 0);
195 fl_key_embedder_responder_handle_event(
196 responder, event3, 0, nullptr,
197 [](GObject* object, GAsyncResult* result, gpointer user_data) {
198 gboolean handled;
199 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
200 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
201 EXPECT_EQ(handled, TRUE);
202
203 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
204 },
205 loop3);
206
207 EXPECT_EQ(call_records->len, 1u);
208 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
209 EXPECT_EQ(record->event->struct_size, sizeof(FlutterKeyEvent));
210 EXPECT_EQ(record->event->timestamp, 12347000);
211 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
212 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
213 EXPECT_EQ(record->event->logical, kLogicalKeyQ);
214 EXPECT_STREQ(record->event->character, "q");
215 EXPECT_EQ(record->event->synthesized, false);
216
217 invoke_record_callback(record, TRUE);
218 g_main_loop_run(loop3);
219 clear_records(call_records);
220
221 // Key up
222 g_autoptr(FlKeyEvent) event4 =
223 fl_key_event_new(12348, kRelease, kKeyCodeKeyA, GDK_KEY_q,
224 static_cast<GdkModifierType>(0), 0);
225 g_autoptr(GMainLoop) loop4 = g_main_loop_new(nullptr, 0);
226 fl_key_embedder_responder_handle_event(
227 responder, event4, 0, nullptr,
228 [](GObject* object, GAsyncResult* result, gpointer user_data) {
229 gboolean handled;
230 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
231 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
232 EXPECT_EQ(handled, FALSE);
233
234 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
235 },
236 loop4);
237
238 EXPECT_EQ(call_records->len, 1u);
239 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
240 EXPECT_EQ(record->event->struct_size, sizeof(FlutterKeyEvent));
241 EXPECT_EQ(record->event->timestamp, 12348000);
242 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
243 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
244 EXPECT_EQ(record->event->logical, kLogicalKeyQ);
245 EXPECT_STREQ(record->event->character, nullptr);
246 EXPECT_EQ(record->event->synthesized, false);
247
248 invoke_record_callback(record, FALSE);
249 g_main_loop_run(loop4);
250 }

References clear_records(), fl_dart_project_new(), fl_engine_get_embedder_api(), fl_engine_new(), fl_engine_start(), fl_key_embedder_call_record_new(), fl_key_embedder_responder_handle_event(), fl_key_embedder_responder_handle_event_finish(), fl_key_embedder_responder_new(), fl_key_event_new(), g_autoptr(), invoke_record_callback(), kKeyCodeKeyA, TRUE, and user_data.

## ◆ TEST() [7/17]

TEST | ( | FlKeyEmbedderResponderTest | ,
|  | SynthesizationOccursOnIgnoredEvents |
| ) |  |

Definition at line 2217 of file fl_key_embedder_responder_test.cc.

2217 {
2218 g_autoptr(FlDartProject) project = fl_dart_project_new();
2219 g_autoptr(FlEngine) engine = fl_engine_new(project);
2220 EXPECT_TRUE(fl_engine_start(engine, nullptr));
2221
2222 g_autoptr(FlKeyEmbedderResponder) responder =
2223 fl_key_embedder_responder_new(engine);
2224
2225 g_autoptr(GPtrArray) call_records =
2226 g_ptr_array_new_with_free_func(g_object_unref);
2227 fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
2228 SendKeyEvent,
2229 ([&call_records](auto engine, const FlutterKeyEvent* event,
2230 FlutterKeyEventCallback callback, void* user_data) {
2231 g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
2232 event, callback, user_data));
2233 return kSuccess;
2234 }));
2235
2236 // The NumLock is desynchronized by being enabled, and Control is pressed.
2237 GdkModifierType state =
2238 static_cast<GdkModifierType>(GDK_MOD2_MASK | GDK_CONTROL_MASK);
2239
2240 // Send a KeyA up event, which will be ignored.
2241 g_autoptr(FlKeyEvent) event =
2242 fl_key_event_new(101, kRelease, kKeyCodeKeyA, GDK_KEY_a, state, 0);
2243 g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
2244 fl_key_embedder_responder_handle_event(
2245 responder, event, 0, nullptr,
2246 [](GObject* object, GAsyncResult* result, gpointer user_data) {
2247 gboolean handled;
2248 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
2249 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
2250 EXPECT_EQ(handled, TRUE);
2251
2252 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
2253 },
2254 loop);
2255 g_main_loop_run(loop);
2256
2257 EXPECT_EQ(call_records->len, 2u);
2258 FlKeyEmbedderCallRecord* record =
2259 FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
2260 EXPECT_EQ(record->event->timestamp, 101000);
2261 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
2262 EXPECT_EQ(record->event->physical, kPhysicalNumLock);
2263 EXPECT_EQ(record->event->logical, kLogicalNumLock);
2264 EXPECT_STREQ(record->event->character, nullptr);
2265 EXPECT_EQ(record->event->synthesized, true);
2266
2267 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 1));
2268 EXPECT_EQ(record->event->timestamp, 101000);
2269 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
2270 EXPECT_EQ(record->event->physical, kPhysicalControlLeft);
2271 EXPECT_EQ(record->event->logical, kLogicalControlLeft);
2272 EXPECT_STREQ(record->event->character, nullptr);
2273 EXPECT_EQ(record->event->synthesized, true);
2274 }

References fl_dart_project_new(), fl_engine_get_embedder_api(), fl_engine_new(), fl_engine_start(), fl_key_embedder_call_record_new(), fl_key_embedder_responder_handle_event(), fl_key_embedder_responder_handle_event_finish(), fl_key_embedder_responder_new(), fl_key_event_new(), g_autoptr(), kKeyCodeKeyA, TRUE, and user_data.

## ◆ TEST() [8/17]

TEST | ( | FlKeyEmbedderResponderTest | ,
|  | SynthesizeForDesyncLockModeOnNonSelfEvents |
| ) |  |

Definition at line 1945 of file fl_key_embedder_responder_test.cc.

1945 {
1946 g_autoptr(FlDartProject) project = fl_dart_project_new();
1947 g_autoptr(FlEngine) engine = fl_engine_new(project);
1948 EXPECT_TRUE(fl_engine_start(engine, nullptr));
1949
1950 g_autoptr(FlKeyEmbedderResponder) responder =
1951 fl_key_embedder_responder_new(engine);
1952
1953 g_autoptr(GPtrArray) call_records =
1954 g_ptr_array_new_with_free_func(g_object_unref);
1955 fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
1956 SendKeyEvent,
1957 ([&call_records](auto engine, const FlutterKeyEvent* event,
1958 FlutterKeyEventCallback callback, void* user_data) {
1959 g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
1960 event, callback, user_data));
1961 return kSuccess;
1962 }));
1963
1964 // The NumLock is desynchronized by being enabled.
1965 GdkModifierType state = GDK_MOD2_MASK;
1966
1967 // Send a normal event
1968 g_autoptr(FlKeyEvent) event1 =
1969 fl_key_event_new(101, kPress, kKeyCodeKeyA, GDK_KEY_a, state, 0);
1970 g_autoptr(GMainLoop) loop1 = g_main_loop_new(nullptr, 0);
1971 fl_key_embedder_responder_handle_event(
1972 responder, event1, 0, nullptr,
1973 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1974 gboolean handled;
1975 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
1976 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1977 EXPECT_EQ(handled, TRUE);
1978
1979 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1980 },
1981 loop1);
1982
1983 EXPECT_EQ(call_records->len, 2u);
1984 FlKeyEmbedderCallRecord* record =
1985 FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1986 EXPECT_EQ(record->event->timestamp, 101000);
1987 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1988 EXPECT_EQ(record->event->physical, kPhysicalNumLock);
1989 EXPECT_EQ(record->event->logical, kLogicalNumLock);
1990 EXPECT_STREQ(record->event->character, nullptr);
1991 EXPECT_EQ(record->event->synthesized, true);
1992
1993 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 1));
1994 EXPECT_EQ(record->event->timestamp, 101000);
1995 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1996 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
1997 EXPECT_EQ(record->event->logical, kLogicalKeyA);
1998 EXPECT_STREQ(record->event->character, "a");
1999 EXPECT_EQ(record->event->synthesized, false);
2000
2001 invoke_record_callback(record, TRUE);
2002 g_main_loop_run(loop1);
2003 clear_records(call_records);
2004
2005 // The NumLock is desynchronized by being disabled.
2006 state = static_cast<GdkModifierType>(0);
2007
2008 // Release key A
2009 g_autoptr(FlKeyEvent) event2 =
2010 fl_key_event_new(102, kRelease, kKeyCodeKeyA, GDK_KEY_A, state, 0);
2011 g_autoptr(GMainLoop) loop2 = g_main_loop_new(nullptr, 0);
2012 fl_key_embedder_responder_handle_event(
2013 responder, event2, 0, nullptr,
2014 [](GObject* object, GAsyncResult* result, gpointer user_data) {
2015 gboolean handled;
2016 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
2017 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
2018 EXPECT_EQ(handled, TRUE);
2019
2020 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
2021 },
2022 loop2);
2023
2024 EXPECT_EQ(call_records->len, 4u);
2025 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
2026 EXPECT_EQ(record->event->timestamp, 102000);
2027 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
2028 EXPECT_EQ(record->event->physical, kPhysicalNumLock);
2029 EXPECT_EQ(record->event->logical, kLogicalNumLock);
2030 EXPECT_STREQ(record->event->character, nullptr);
2031 EXPECT_EQ(record->event->synthesized, true);
2032
2033 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 1));
2034 EXPECT_EQ(record->event->timestamp, 102000);
2035 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
2036 EXPECT_EQ(record->event->physical, kPhysicalNumLock);
2037 EXPECT_EQ(record->event->logical, kLogicalNumLock);
2038 EXPECT_STREQ(record->event->character, nullptr);
2039 EXPECT_EQ(record->event->synthesized, true);
2040
2041 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 2));
2042 EXPECT_EQ(record->event->timestamp, 102000);
2043 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
2044 EXPECT_EQ(record->event->physical, kPhysicalNumLock);
2045 EXPECT_EQ(record->event->logical, kLogicalNumLock);
2046 EXPECT_STREQ(record->event->character, nullptr);
2047 EXPECT_EQ(record->event->synthesized, true);
2048
2049 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 3));
2050 EXPECT_EQ(record->event->timestamp, 102000);
2051 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
2052 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
2053 EXPECT_EQ(record->event->logical, kLogicalKeyA);
2054 EXPECT_STREQ(record->event->character, nullptr);
2055 EXPECT_EQ(record->event->synthesized, false);
2056
2057 invoke_record_callback(record, TRUE);
2058 g_main_loop_run(loop2);
2059 clear_records(call_records);
2060
2061 // Release NumLock. Since the previous event should have synthesized NumLock
2062 // to be released, this should result in only an empty event.
2063 g_autoptr(FlKeyEvent) event3 = fl_key_event_new(
2064 103, kRelease, kKeyCodeNumLock, GDK_KEY_Num_Lock, state, 0);
2065 g_autoptr(GMainLoop) loop3 = g_main_loop_new(nullptr, 0);
2066 fl_key_embedder_responder_handle_event(
2067 responder, event3, 0, nullptr,
2068 [](GObject* object, GAsyncResult* result, gpointer user_data) {
2069 gboolean handled;
2070 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
2071 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
2072 EXPECT_EQ(handled, TRUE);
2073
2074 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
2075 },
2076 loop3);
2077
2078 EXPECT_EQ(call_records->len, 1u);
2079 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
2080 EXPECT_EQ(record->event->physical, 0ull);
2081 EXPECT_EQ(record->event->logical, 0ull);
2082 EXPECT_STREQ(record->event->character, nullptr);
2083 EXPECT_EQ(record->event->synthesized, false);
2084
2085 invoke_record_callback(record, TRUE);
2086 g_main_loop_run(loop3);
2087 }

References clear_records(), fl_dart_project_new(), fl_engine_get_embedder_api(), fl_engine_new(), fl_engine_start(), fl_key_embedder_call_record_new(), fl_key_embedder_responder_handle_event(), fl_key_embedder_responder_handle_event_finish(), fl_key_embedder_responder_new(), fl_key_event_new(), g_autoptr(), invoke_record_callback(), kKeyCodeKeyA, TRUE, and user_data.

## ◆ TEST() [9/17]

TEST | ( | FlKeyEmbedderResponderTest | ,
|  | SynthesizeForDesyncLockModeOnSelfEvents |
| ) |  |

Definition at line 2091 of file fl_key_embedder_responder_test.cc.

2091 {
2092 g_autoptr(FlDartProject) project = fl_dart_project_new();
2093 g_autoptr(FlEngine) engine = fl_engine_new(project);
2094 EXPECT_TRUE(fl_engine_start(engine, nullptr));
2095
2096 g_autoptr(FlKeyEmbedderResponder) responder =
2097 fl_key_embedder_responder_new(engine);
2098
2099 g_autoptr(GPtrArray) call_records =
2100 g_ptr_array_new_with_free_func(g_object_unref);
2101 fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
2102 SendKeyEvent,
2103 ([&call_records](auto engine, const FlutterKeyEvent* event,
2104 FlutterKeyEventCallback callback, void* user_data) {
2105 g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
2106 event, callback, user_data));
2107 return kSuccess;
2108 }));
2109
2110 // The NumLock is desynchronized by being enabled.
2111 GdkModifierType state = GDK_MOD2_MASK;
2112
2113 // NumLock down
2114 g_autoptr(FlKeyEvent) event1 = fl_key_event_new(101, kPress, kKeyCodeNumLock,
2115 GDK_KEY_Num_Lock, state, 0);
2116 g_autoptr(GMainLoop) loop1 = g_main_loop_new(nullptr, 0);
2117 fl_key_embedder_responder_handle_event(
2118 responder, event1, 0, nullptr,
2119 [](GObject* object, GAsyncResult* result, gpointer user_data) {
2120 gboolean handled;
2121 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
2122 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
2123 EXPECT_EQ(handled, TRUE);
2124
2125 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
2126 },
2127 loop1);
2128
2129 EXPECT_EQ(call_records->len, 3u);
2130 FlKeyEmbedderCallRecord* record =
2131 FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
2132 EXPECT_EQ(record->event->timestamp, 101000);
2133 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
2134 EXPECT_EQ(record->event->physical, kPhysicalNumLock);
2135 EXPECT_EQ(record->event->logical, kLogicalNumLock);
2136 EXPECT_STREQ(record->event->character, nullptr);
2137 EXPECT_EQ(record->event->synthesized, true);
2138
2139 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 1));
2140 EXPECT_EQ(record->event->timestamp, 101000);
2141 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
2142 EXPECT_EQ(record->event->physical, kPhysicalNumLock);
2143 EXPECT_EQ(record->event->logical, kLogicalNumLock);
2144 EXPECT_STREQ(record->event->character, nullptr);
2145 EXPECT_EQ(record->event->synthesized, true);
2146
2147 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 2));
2148 EXPECT_EQ(record->event->timestamp, 101000);
2149 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
2150 EXPECT_EQ(record->event->physical, kPhysicalNumLock);
2151 EXPECT_EQ(record->event->logical, kLogicalNumLock);
2152 EXPECT_STREQ(record->event->character, nullptr);
2153 EXPECT_EQ(record->event->synthesized, false);
2154
2155 invoke_record_callback(record, TRUE);
2156 g_main_loop_run(loop1);
2157 clear_records(call_records);
2158
2159 // The NumLock is desynchronized by being enabled in a press event.
2160 state = GDK_MOD2_MASK;
2161
2162 // NumLock up
2163 g_autoptr(FlKeyEvent) event2 = fl_key_event_new(102, kPress, kKeyCodeNumLock,
2164 GDK_KEY_Num_Lock, state, 0);
2165 g_autoptr(GMainLoop) loop2 = g_main_loop_new(nullptr, 0);
2166 fl_key_embedder_responder_handle_event(
2167 responder, event2, 0, nullptr,
2168 [](GObject* object, GAsyncResult* result, gpointer user_data) {
2169 gboolean handled;
2170 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
2171 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
2172 EXPECT_EQ(handled, TRUE);
2173
2174 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
2175 },
2176 loop2);
2177
2178 EXPECT_EQ(call_records->len, 4u);
2179 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
2180 EXPECT_EQ(record->event->timestamp, 102000);
2181 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
2182 EXPECT_EQ(record->event->physical, kPhysicalNumLock);
2183 EXPECT_EQ(record->event->logical, kLogicalNumLock);
2184 EXPECT_STREQ(record->event->character, nullptr);
2185 EXPECT_EQ(record->event->synthesized, true);
2186
2187 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 1));
2188 EXPECT_EQ(record->event->timestamp, 102000);
2189 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
2190 EXPECT_EQ(record->event->physical, kPhysicalNumLock);
2191 EXPECT_EQ(record->event->logical, kLogicalNumLock);
2192 EXPECT_STREQ(record->event->character, nullptr);
2193 EXPECT_EQ(record->event->synthesized, true);
2194
2195 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 2));
2196 EXPECT_EQ(record->event->timestamp, 102000);
2197 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
2198 EXPECT_EQ(record->event->physical, kPhysicalNumLock);
2199 EXPECT_EQ(record->event->logical, kLogicalNumLock);
2200 EXPECT_STREQ(record->event->character, nullptr);
2201 EXPECT_EQ(record->event->synthesized, true);
2202
2203 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 3));
2204 EXPECT_EQ(record->event->timestamp, 102000);
2205 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
2206 EXPECT_EQ(record->event->physical, kPhysicalNumLock);
2207 EXPECT_EQ(record->event->logical, kLogicalNumLock);
2208 EXPECT_STREQ(record->event->character, nullptr);
2209 EXPECT_EQ(record->event->synthesized, false);
2210
2211 invoke_record_callback(record, TRUE);
2212 g_main_loop_run(loop2);
2213 }

References clear_records(), fl_dart_project_new(), fl_engine_get_embedder_api(), fl_engine_new(), fl_engine_start(), fl_key_embedder_call_record_new(), fl_key_embedder_responder_handle_event(), fl_key_embedder_responder_handle_event_finish(), fl_key_embedder_responder_new(), fl_key_event_new(), g_autoptr(), invoke_record_callback(), TRUE, and user_data.

## ◆ TEST() [10/17]

TEST | ( | FlKeyEmbedderResponderTest | ,
|  | SynthesizeForDesyncPressingStateOnNonSelfEvents |
| ) |  |

Definition at line 1671 of file fl_key_embedder_responder_test.cc.

1672 {
1673 g_autoptr(FlDartProject) project = fl_dart_project_new();
1674 g_autoptr(FlEngine) engine = fl_engine_new(project);
1675 EXPECT_TRUE(fl_engine_start(engine, nullptr));
1676
1677 g_autoptr(FlKeyEmbedderResponder) responder =
1678 fl_key_embedder_responder_new(engine);
1679
1680 g_autoptr(GPtrArray) call_records =
1681 g_ptr_array_new_with_free_func(g_object_unref);
1682 fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
1683 SendKeyEvent,
1684 ([&call_records](auto engine, const FlutterKeyEvent* event,
1685 FlutterKeyEventCallback callback, void* user_data) {
1686 g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
1687 event, callback, user_data));
1688 return kSuccess;
1689 }));
1690
1691 // A key down of control left is missed.
1692 GdkModifierType state = GDK_CONTROL_MASK;
1693
1694 // Send a normal event (KeyA down)
1695 g_autoptr(FlKeyEvent) event1 =
1696 fl_key_event_new(101, kPress, kKeyCodeKeyA, GDK_KEY_a, state, 0);
1697 g_autoptr(GMainLoop) loop1 = g_main_loop_new(nullptr, 0);
1698 fl_key_embedder_responder_handle_event(
1699 responder, event1, 0, nullptr,
1700 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1701 gboolean handled;
1702 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
1703 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1704 EXPECT_EQ(handled, TRUE);
1705
1706 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1707 },
1708 loop1);
1709
1710 EXPECT_EQ(call_records->len, 2u);
1711 FlKeyEmbedderCallRecord* record =
1712 FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1713 EXPECT_EQ(record->event->timestamp, 101000);
1714 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1715 EXPECT_EQ(record->event->physical, kPhysicalControlLeft);
1716 EXPECT_EQ(record->event->logical, kLogicalControlLeft);
1717 EXPECT_STREQ(record->event->character, nullptr);
1718 EXPECT_EQ(record->event->synthesized, true);
1719
1720 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 1));
1721 EXPECT_EQ(record->event->timestamp, 101000);
1722 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1723 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
1724 EXPECT_EQ(record->event->logical, kLogicalKeyA);
1725 EXPECT_STREQ(record->event->character, "a");
1726 EXPECT_EQ(record->event->synthesized, false);
1727
1728 invoke_record_callback(record, TRUE);
1729 g_main_loop_run(loop1);
1730 clear_records(call_records);
1731
1732 // A key up of control left is missed.
1733 state = static_cast<GdkModifierType>(0);
1734
1735 // Send a normal event (KeyA up)
1736 g_autoptr(FlKeyEvent) event2 =
1737 fl_key_event_new(102, kRelease, kKeyCodeKeyA, GDK_KEY_A, state, 0);
1738 g_autoptr(GMainLoop) loop2 = g_main_loop_new(nullptr, 0);
1739 fl_key_embedder_responder_handle_event(
1740 responder, event2, 0, nullptr,
1741 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1742 gboolean handled;
1743 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
1744 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1745 EXPECT_EQ(handled, TRUE);
1746
1747 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1748 },
1749 loop2);
1750
1751 EXPECT_EQ(call_records->len, 2u);
1752 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1753 EXPECT_EQ(record->event->timestamp, 102000);
1754 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1755 EXPECT_EQ(record->event->physical, kPhysicalControlLeft);
1756 EXPECT_EQ(record->event->logical, kLogicalControlLeft);
1757 EXPECT_STREQ(record->event->character, nullptr);
1758 EXPECT_EQ(record->event->synthesized, true);
1759
1760 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 1));
1761 EXPECT_EQ(record->event->timestamp, 102000);
1762 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1763 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
1764 EXPECT_EQ(record->event->logical, kLogicalKeyA);
1765 EXPECT_STREQ(record->event->character, nullptr);
1766 EXPECT_EQ(record->event->synthesized, false);
1767
1768 invoke_record_callback(record, TRUE);
1769 g_main_loop_run(loop2);
1770 clear_records(call_records);
1771
1772 // Test non-default key mapping.
1773
1774 // Press a key with physical CapsLock and logical ControlLeft.
1775 state = static_cast<GdkModifierType>(0);
1776
1777 g_autoptr(FlKeyEvent) event3 = fl_key_event_new(101, kPress, kKeyCodeCapsLock,
1778 GDK_KEY_Control_L, state, 0);
1779 g_autoptr(GMainLoop) loop3 = g_main_loop_new(nullptr, 0);
1780 fl_key_embedder_responder_handle_event(
1781 responder, event3, 0, nullptr,
1782 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1783 gboolean handled;
1784 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
1785 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1786 EXPECT_EQ(handled, TRUE);
1787
1788 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1789 },
1790 loop3);
1791
1792 EXPECT_EQ(call_records->len, 1u);
1793 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1794 EXPECT_EQ(record->event->timestamp, 101000);
1795 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1796 EXPECT_EQ(record->event->physical, kPhysicalCapsLock);
1797 EXPECT_EQ(record->event->logical, kLogicalControlLeft);
1798 EXPECT_STREQ(record->event->character, nullptr);
1799 EXPECT_EQ(record->event->synthesized, false);
1800
1801 invoke_record_callback(record, TRUE);
1802 g_main_loop_run(loop3);
1803 clear_records(call_records);
1804
1805 // The key up of the control left press is missed.
1806 state = static_cast<GdkModifierType>(0);
1807
1808 // Send a normal event (KeyA down).
1809 g_autoptr(FlKeyEvent) event4 =
1810 fl_key_event_new(102, kPress, kKeyCodeKeyA, GDK_KEY_A, state, 0);
1811 g_autoptr(GMainLoop) loop4 = g_main_loop_new(nullptr, 0);
1812 fl_key_embedder_responder_handle_event(
1813 responder, event4, 0, nullptr,
1814 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1815 gboolean handled;
1816 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
1817 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1818 EXPECT_EQ(handled, TRUE);
1819
1820 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1821 },
1822 loop4);
1823
1824 // The synthesized event should have physical CapsLock and logical
1825 // ControlLeft.
1826 EXPECT_EQ(call_records->len, 2u);
1827 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1828 EXPECT_EQ(record->event->timestamp, 102000);
1829 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1830 EXPECT_EQ(record->event->physical, kPhysicalCapsLock);
1831 EXPECT_EQ(record->event->logical, kLogicalControlLeft);
1832 EXPECT_STREQ(record->event->character, nullptr);
1833 EXPECT_EQ(record->event->synthesized, true);
1834
1835 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 1));
1836 EXPECT_EQ(record->event->timestamp, 102000);
1837 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1838 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
1839 EXPECT_EQ(record->event->logical, kLogicalKeyA);
1840 EXPECT_STREQ(record->event->character, "A");
1841 EXPECT_EQ(record->event->synthesized, false);
1842
1843 invoke_record_callback(record, TRUE);
1844 g_main_loop_run(loop4);
1845 }

References clear_records(), fl_dart_project_new(), fl_engine_get_embedder_api(), fl_engine_new(), fl_engine_start(), fl_key_embedder_call_record_new(), fl_key_embedder_responder_handle_event(), fl_key_embedder_responder_handle_event_finish(), fl_key_embedder_responder_new(), fl_key_event_new(), g_autoptr(), invoke_record_callback(), kKeyCodeKeyA, TRUE, and user_data.

## ◆ TEST() [11/17]

TEST | ( | FlKeyEmbedderResponderTest | ,
|  | SynthesizeForDesyncPressingStateOnRemappedEvents |
| ) |  |

Definition at line 1849 of file fl_key_embedder_responder_test.cc.

1850 {
1851 g_autoptr(FlDartProject) project = fl_dart_project_new();
1852 g_autoptr(FlEngine) engine = fl_engine_new(project);
1853 EXPECT_TRUE(fl_engine_start(engine, nullptr));
1854
1855 g_autoptr(FlKeyEmbedderResponder) responder =
1856 fl_key_embedder_responder_new(engine);
1857
1858 g_autoptr(GPtrArray) call_records =
1859 g_ptr_array_new_with_free_func(g_object_unref);
1860 fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
1861 SendKeyEvent,
1862 ([&call_records](auto engine, const FlutterKeyEvent* event,
1863 FlutterKeyEventCallback callback, void* user_data) {
1864 g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
1865 event, callback, user_data));
1866 return kSuccess;
1867 }));
1868
1869 // Press a key with physical CapsLock and logical ControlLeft.
1870 GdkModifierType state = static_cast<GdkModifierType>(0);
1871
1872 g_autoptr(FlKeyEvent) event1 = fl_key_event_new(101, kPress, kKeyCodeCapsLock,
1873 GDK_KEY_Control_L, state, 0);
1874 g_autoptr(GMainLoop) loop1 = g_main_loop_new(nullptr, 0);
1875 fl_key_embedder_responder_handle_event(
1876 responder, event1, 0, nullptr,
1877 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1878 gboolean handled;
1879 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
1880 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1881 EXPECT_EQ(handled, TRUE);
1882
1883 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1884 },
1885 loop1);
1886
1887 EXPECT_EQ(call_records->len, 1u);
1888 FlKeyEmbedderCallRecord* record =
1889 FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1890 EXPECT_EQ(record->event->timestamp, 101000);
1891 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1892 EXPECT_EQ(record->event->physical, kPhysicalCapsLock);
1893 EXPECT_EQ(record->event->logical, kLogicalControlLeft);
1894 EXPECT_STREQ(record->event->character, nullptr);
1895 EXPECT_EQ(record->event->synthesized, false);
1896
1897 invoke_record_callback(record, TRUE);
1898 g_main_loop_run(loop1);
1899 clear_records(call_records);
1900
1901 // The key up of the control left press is missed.
1902 state = static_cast<GdkModifierType>(0);
1903
1904 // Send a normal event (KeyA down).
1905 g_autoptr(FlKeyEvent) event2 =
1906 fl_key_event_new(102, kPress, kKeyCodeKeyA, GDK_KEY_A, state, 0);
1907 g_autoptr(GMainLoop) loop2 = g_main_loop_new(nullptr, 0);
1908 fl_key_embedder_responder_handle_event(
1909 responder, event2, 0, nullptr,
1910 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1911 gboolean handled;
1912 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
1913 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1914 EXPECT_EQ(handled, TRUE);
1915
1916 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1917 },
1918 loop2);
1919
1920 // The synthesized event should have physical CapsLock and logical
1921 // ControlLeft.
1922 EXPECT_EQ(call_records->len, 2u);
1923 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1924 EXPECT_EQ(record->event->timestamp, 102000);
1925 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1926 EXPECT_EQ(record->event->physical, kPhysicalCapsLock);
1927 EXPECT_EQ(record->event->logical, kLogicalControlLeft);
1928 EXPECT_STREQ(record->event->character, nullptr);
1929 EXPECT_EQ(record->event->synthesized, true);
1930
1931 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 1));
1932 EXPECT_EQ(record->event->timestamp, 102000);
1933 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1934 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
1935 EXPECT_EQ(record->event->logical, kLogicalKeyA);
1936 EXPECT_STREQ(record->event->character, "A");
1937 EXPECT_EQ(record->event->synthesized, false);
1938
1939 invoke_record_callback(record, TRUE);
1940 g_main_loop_run(loop2);
1941 }

References clear_records(), fl_dart_project_new(), fl_engine_get_embedder_api(), fl_engine_new(), fl_engine_start(), fl_key_embedder_call_record_new(), fl_key_embedder_responder_handle_event(), fl_key_embedder_responder_handle_event_finish(), fl_key_embedder_responder_new(), fl_key_event_new(), g_autoptr(), invoke_record_callback(), kKeyCodeKeyA, TRUE, and user_data.

## ◆ TEST() [12/17]

TEST | ( | FlKeyEmbedderResponderTest | ,
|  | SynthesizeForDesyncPressingStateOnSelfEvents |
| ) |  |

Definition at line 1483 of file fl_key_embedder_responder_test.cc.

1483 {
1484 g_autoptr(FlDartProject) project = fl_dart_project_new();
1485 g_autoptr(FlEngine) engine = fl_engine_new(project);
1486 EXPECT_TRUE(fl_engine_start(engine, nullptr));
1487
1488 g_autoptr(FlKeyEmbedderResponder) responder =
1489 fl_key_embedder_responder_new(engine);
1490
1491 g_autoptr(GPtrArray) call_records =
1492 g_ptr_array_new_with_free_func(g_object_unref);
1493 fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
1494 SendKeyEvent,
1495 ([&call_records](auto engine, const FlutterKeyEvent* event,
1496 FlutterKeyEventCallback callback, void* user_data) {
1497 g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
1498 event, callback, user_data));
1499 return kSuccess;
1500 }));
1501
1502 // Test 1: synthesize key down.
1503
1504 // A key down of control left is missed.
1505 GdkModifierType state = GDK_CONTROL_MASK;
1506
1507 // Send a ControlLeft up
1508 g_autoptr(FlKeyEvent) event1 = fl_key_event_new(
1509 101, kRelease, kKeyCodeControlLeft, GDK_KEY_Control_L, state, 0);
1510 g_autoptr(GMainLoop) loop1 = g_main_loop_new(nullptr, 0);
1511 fl_key_embedder_responder_handle_event(
1512 responder, event1, 0, nullptr,
1513 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1514 gboolean handled;
1515 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
1516 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1517 EXPECT_EQ(handled, TRUE);
1518
1519 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1520 },
1521 loop1);
1522
1523 EXPECT_EQ(call_records->len, 2u);
1524 FlKeyEmbedderCallRecord* record =
1525 FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1526 EXPECT_EQ(record->event->timestamp, 101000);
1527 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1528 EXPECT_EQ(record->event->physical, kPhysicalControlLeft);
1529 EXPECT_EQ(record->event->logical, kLogicalControlLeft);
1530 EXPECT_STREQ(record->event->character, nullptr);
1531 EXPECT_EQ(record->event->synthesized, true);
1532
1533 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 1));
1534 EXPECT_EQ(record->event->timestamp, 101000);
1535 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1536 EXPECT_EQ(record->event->physical, kPhysicalControlLeft);
1537 EXPECT_EQ(record->event->logical, kLogicalControlLeft);
1538 EXPECT_STREQ(record->event->character, nullptr);
1539 EXPECT_EQ(record->event->synthesized, false);
1540
1541 invoke_record_callback(record, TRUE);
1542 g_main_loop_run(loop1);
1543 clear_records(call_records);
1544
1545 // Test 2: synthesize key up.
1546
1547 // Send a ControlLeft down.
1548 state = static_cast<GdkModifierType>(0);
1549 g_autoptr(FlKeyEvent) event2 = fl_key_event_new(
1550 102, kPress, kKeyCodeControlLeft, GDK_KEY_Control_L, state, 0);
1551 g_autoptr(GMainLoop) loop2 = g_main_loop_new(nullptr, 0);
1552 fl_key_embedder_responder_handle_event(
1553 responder, event2, 0, nullptr,
1554 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1555 gboolean handled;
1556 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
1557 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1558 EXPECT_EQ(handled, TRUE);
1559
1560 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1561 },
1562 loop2);
1563 EXPECT_EQ(call_records->len, 1u);
1564 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1565 invoke_record_callback(record, TRUE);
1566 g_main_loop_run(loop2);
1567 clear_records(call_records);
1568
1569 // A key up of control left is missed.
1570 state = static_cast<GdkModifierType>(0);
1571
1572 // Send another ControlLeft down
1573 g_autoptr(FlKeyEvent) event3 = fl_key_event_new(
1574 103, kPress, kKeyCodeControlLeft, GDK_KEY_Control_L, state, 0);
1575 g_autoptr(GMainLoop) loop3 = g_main_loop_new(nullptr, 0);
1576 fl_key_embedder_responder_handle_event(
1577 responder, event3, 0, nullptr,
1578 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1579 gboolean handled;
1580 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
1581 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1582 EXPECT_EQ(handled, TRUE);
1583
1584 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1585 },
1586 loop3);
1587
1588 EXPECT_EQ(call_records->len, 2u);
1589 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1590 EXPECT_EQ(record->event->timestamp, 103000);
1591 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1592 EXPECT_EQ(record->event->physical, kPhysicalControlLeft);
1593 EXPECT_EQ(record->event->logical, kLogicalControlLeft);
1594 EXPECT_STREQ(record->event->character, nullptr);
1595 EXPECT_EQ(record->event->synthesized, true);
1596
1597 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 1));
1598 EXPECT_EQ(record->event->timestamp, 103000);
1599 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1600 EXPECT_EQ(record->event->physical, kPhysicalControlLeft);
1601 EXPECT_EQ(record->event->logical, kLogicalControlLeft);
1602 EXPECT_STREQ(record->event->character, nullptr);
1603 EXPECT_EQ(record->event->synthesized, false);
1604
1605 invoke_record_callback(record, TRUE);
1606 g_main_loop_run(loop3);
1607 clear_records(call_records);
1608
1609 // Send a ControlLeft up to clear up state.
1610 state = GDK_CONTROL_MASK;
1611 g_autoptr(FlKeyEvent) event4 = fl_key_event_new(
1612 104, kRelease, kKeyCodeControlLeft, GDK_KEY_Control_L, state, 0);
1613 g_autoptr(GMainLoop) loop4 = g_main_loop_new(nullptr, 0);
1614 fl_key_embedder_responder_handle_event(
1615 responder, event4, 0, nullptr,
1616 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1617 gboolean handled;
1618 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
1619 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1620 EXPECT_EQ(handled, TRUE);
1621
1622 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1623 },
1624 loop4);
1625 EXPECT_EQ(call_records->len, 1u);
1626 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1627 invoke_record_callback(record, TRUE);
1628 g_main_loop_run(loop4);
1629 clear_records(call_records);
1630
1631 // Test 3: synthesize by right modifier.
1632
1633 // A key down of control right is missed.
1634 state = GDK_CONTROL_MASK;
1635
1636 // Send a ControlRight up.
1637 g_autoptr(FlKeyEvent) event5 = fl_key_event_new(
1638 105, kRelease, kKeyCodeControlRight, GDK_KEY_Control_R, state, 0);
1639 g_autoptr(GMainLoop) loop5 = g_main_loop_new(nullptr, 0);
1640 fl_key_embedder_responder_handle_event(
1641 responder, event5, 0, nullptr,
1642 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1643 gboolean handled;
1644 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
1645 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1646 EXPECT_EQ(handled, TRUE);
1647
1648 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1649 },
1650 loop5);
1651
1652 // A ControlLeft down is synthesized, with an empty event.
1653 // Reason: The ControlLeft down is synthesized to synchronize the state
1654 // showing Control as pressed. The ControlRight event is ignored because
1655 // the event is considered a duplicate up event.
1656 EXPECT_EQ(call_records->len, 1u);
1657 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1658 EXPECT_EQ(record->event->timestamp, 105000);
1659 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1660 EXPECT_EQ(record->event->physical, kPhysicalControlLeft);
1661 EXPECT_EQ(record->event->logical, kLogicalControlLeft);
1662 EXPECT_STREQ(record->event->character, nullptr);
1663 EXPECT_EQ(record->event->synthesized, true);
1664
1665 invoke_record_callback(record, TRUE);
1666 g_main_loop_run(loop5);
1667 }

References clear_records(), fl_dart_project_new(), fl_engine_get_embedder_api(), fl_engine_new(), fl_engine_start(), fl_key_embedder_call_record_new(), fl_key_embedder_responder_handle_event(), fl_key_embedder_responder_handle_event_finish(), fl_key_embedder_responder_new(), fl_key_event_new(), g_autoptr(), invoke_record_callback(), TRUE, and user_data.

## ◆ TEST() [13/17]

TEST | ( | FlKeyEmbedderResponderTest | ,
|  | TapLetterKeysBetweenCapsLockEvents |
| ) |  |

Definition at line 840 of file fl_key_embedder_responder_test.cc.

840 {
841 g_autoptr(FlDartProject) project = fl_dart_project_new();
842 g_autoptr(FlEngine) engine = fl_engine_new(project);
843 EXPECT_TRUE(fl_engine_start(engine, nullptr));
844
845 g_autoptr(FlKeyEmbedderResponder) responder =
846 fl_key_embedder_responder_new(engine);
847
848 g_autoptr(GPtrArray) call_records =
849 g_ptr_array_new_with_free_func(g_object_unref);
850 fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
851 SendKeyEvent,
852 ([&call_records](auto engine, const FlutterKeyEvent* event,
853 FlutterKeyEventCallback callback, void* user_data) {
854 g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
855 event, callback, user_data));
856 return kSuccess;
857 }));
858
859 // Press CapsLock (stage 0 -> 1)
860 g_autoptr(FlKeyEvent) event1 =
861 fl_key_event_new(101, kPress, kKeyCodeCapsLock, GDK_KEY_Caps_Lock,
862 static_cast<GdkModifierType>(0), 0);
863 g_autoptr(GMainLoop) loop1 = g_main_loop_new(nullptr, 0);
864 fl_key_embedder_responder_handle_event(
865 responder, event1, 0, nullptr,
866 [](GObject* object, GAsyncResult* result, gpointer user_data) {
867 gboolean handled;
868 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
869 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
870 EXPECT_EQ(handled, TRUE);
871
872 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
873 },
874 loop1);
875
876 EXPECT_EQ(call_records->len, 1u);
877 FlKeyEmbedderCallRecord* record =
878 FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
879 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
880 EXPECT_EQ(record->event->physical, kPhysicalCapsLock);
881 EXPECT_EQ(record->event->logical, kLogicalCapsLock);
882 EXPECT_STREQ(record->event->character, nullptr);
883 EXPECT_EQ(record->event->synthesized, false);
884
885 invoke_record_callback(record, TRUE);
886 g_main_loop_run(loop1);
887 clear_records(call_records);
888
889 // Press key A (stage 1)
890 g_autoptr(FlKeyEvent) event2 =
891 fl_key_event_new(102, kPress, kKeyCodeKeyA, GDK_KEY_A, GDK_LOCK_MASK, 0);
892 g_autoptr(GMainLoop) loop2 = g_main_loop_new(nullptr, 0);
893 fl_key_embedder_responder_handle_event(
894 responder, event2, 0, nullptr,
895 [](GObject* object, GAsyncResult* result, gpointer user_data) {
896 gboolean handled;
897 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
898 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
899 EXPECT_EQ(handled, TRUE);
900
901 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
902 },
903 loop2);
904
905 EXPECT_EQ(call_records->len, 1u);
906 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
907 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
908 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
909 EXPECT_EQ(record->event->logical, kLogicalKeyA);
910 EXPECT_STREQ(record->event->character, "A");
911 EXPECT_EQ(record->event->synthesized, false);
912
913 invoke_record_callback(record, TRUE);
914 g_main_loop_run(loop2);
915 clear_records(call_records);
916
917 // Release CapsLock (stage 1 -> 2)
918 g_autoptr(FlKeyEvent) event3 = fl_key_event_new(
919 103, kRelease, kKeyCodeCapsLock, GDK_KEY_Caps_Lock, GDK_LOCK_MASK, 0);
920 g_autoptr(GMainLoop) loop3 = g_main_loop_new(nullptr, 0);
921 fl_key_embedder_responder_handle_event(
922 responder, event3, 0, nullptr,
923 [](GObject* object, GAsyncResult* result, gpointer user_data) {
924 gboolean handled;
925 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
926 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
927 EXPECT_EQ(handled, TRUE);
928
929 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
930 },
931 loop3);
932
933 EXPECT_EQ(call_records->len, 1u);
934 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
935 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
936 EXPECT_EQ(record->event->physical, kPhysicalCapsLock);
937 EXPECT_EQ(record->event->logical, kLogicalCapsLock);
938 EXPECT_STREQ(record->event->character, nullptr);
939 EXPECT_EQ(record->event->synthesized, false);
940
941 invoke_record_callback(record, TRUE);
942 g_main_loop_run(loop3);
943 clear_records(call_records);
944
945 // Release key A (stage 2)
946 g_autoptr(FlKeyEvent) event4 = fl_key_event_new(104, kRelease, kKeyCodeKeyA,
947 GDK_KEY_A, GDK_LOCK_MASK, 0);
948 g_autoptr(GMainLoop) loop4 = g_main_loop_new(nullptr, 0);
949 fl_key_embedder_responder_handle_event(
950 responder, event4, 0, nullptr,
951 [](GObject* object, GAsyncResult* result, gpointer user_data) {
952 gboolean handled;
953 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
954 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
955 EXPECT_EQ(handled, TRUE);
956
957 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
958 },
959 loop4);
960
961 EXPECT_EQ(call_records->len, 1u);
962 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
963 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
964 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
965 EXPECT_EQ(record->event->logical, kLogicalKeyA);
966 EXPECT_STREQ(record->event->character, nullptr);
967 EXPECT_EQ(record->event->synthesized, false);
968
969 invoke_record_callback(record, TRUE);
970 g_main_loop_run(loop4);
971 clear_records(call_records);
972
973 // Press CapsLock (stage 2 -> 3)
974 g_autoptr(FlKeyEvent) event5 = fl_key_event_new(
975 105, kPress, kKeyCodeCapsLock, GDK_KEY_Caps_Lock, GDK_LOCK_MASK, 0);
976 g_autoptr(GMainLoop) loop5 = g_main_loop_new(nullptr, 0);
977 fl_key_embedder_responder_handle_event(
978 responder, event5, 0, nullptr,
979 [](GObject* object, GAsyncResult* result, gpointer user_data) {
980 gboolean handled;
981 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
982 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
983 EXPECT_EQ(handled, TRUE);
984
985 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
986 },
987 loop5);
988
989 EXPECT_EQ(call_records->len, 1u);
990 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
991 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
992 EXPECT_EQ(record->event->physical, kPhysicalCapsLock);
993 EXPECT_EQ(record->event->logical, kLogicalCapsLock);
994 EXPECT_STREQ(record->event->character, nullptr);
995 EXPECT_EQ(record->event->synthesized, false);
996
997 invoke_record_callback(record, TRUE);
998 g_main_loop_run(loop5);
999 clear_records(call_records);
1000
1001 // Press key A (stage 3)
1002 g_autoptr(FlKeyEvent) event6 =
1003 fl_key_event_new(106, kPress, kKeyCodeKeyA, GDK_KEY_A, GDK_LOCK_MASK, 0);
1004 g_autoptr(GMainLoop) loop6 = g_main_loop_new(nullptr, 0);
1005 fl_key_embedder_responder_handle_event(
1006 responder, event6, 0, nullptr,
1007 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1008 gboolean handled;
1009 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
1010 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1011 EXPECT_EQ(handled, TRUE);
1012
1013 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1014 },
1015 loop6);
1016
1017 EXPECT_EQ(call_records->len, 1u);
1018 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1019 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1020 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
1021 EXPECT_EQ(record->event->logical, kLogicalKeyA);
1022 EXPECT_STREQ(record->event->character, "A");
1023 EXPECT_EQ(record->event->synthesized, false);
1024
1025 invoke_record_callback(record, TRUE);
1026 g_main_loop_run(loop6);
1027 clear_records(call_records);
1028
1029 // Release CapsLock (stage 3 -> 0)
1030 g_autoptr(FlKeyEvent) event7 = fl_key_event_new(
1031 107, kRelease, kKeyCodeCapsLock, GDK_KEY_Caps_Lock, GDK_LOCK_MASK, 0);
1032 g_autoptr(GMainLoop) loop7 = g_main_loop_new(nullptr, 0);
1033 fl_key_embedder_responder_handle_event(
1034 responder, event7, 0, nullptr,
1035 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1036 gboolean handled;
1037 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
1038 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1039 EXPECT_EQ(handled, TRUE);
1040
1041 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1042 },
1043 loop7);
1044
1045 EXPECT_EQ(call_records->len, 1u);
1046 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1047 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1048 EXPECT_EQ(record->event->physical, kPhysicalCapsLock);
1049 EXPECT_EQ(record->event->logical, kLogicalCapsLock);
1050 EXPECT_STREQ(record->event->character, nullptr);
1051 EXPECT_EQ(record->event->synthesized, false);
1052
1053 invoke_record_callback(record, TRUE);
1054 g_main_loop_run(loop7);
1055 clear_records(call_records);
1056
1057 // Release key A (stage 0)
1058 g_autoptr(FlKeyEvent) event8 =
1059 fl_key_event_new(108, kRelease, kKeyCodeKeyA, GDK_KEY_a,
1060 static_cast<GdkModifierType>(0), 0);
1061 g_autoptr(GMainLoop) loop8 = g_main_loop_new(nullptr, 0);
1062 fl_key_embedder_responder_handle_event(
1063 responder, event8, 0, nullptr,
1064 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1065 gboolean handled;
1066 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
1067 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1068 EXPECT_EQ(handled, TRUE);
1069
1070 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1071 },
1072 loop8);
1073
1074 EXPECT_EQ(call_records->len, 1u);
1075 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1076 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1077 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
1078 EXPECT_EQ(record->event->logical, kLogicalKeyA);
1079 EXPECT_STREQ(record->event->character, nullptr);
1080 EXPECT_EQ(record->event->synthesized, false);
1081
1082 invoke_record_callback(record, TRUE);
1083 g_main_loop_run(loop8);
1084 }

References clear_records(), fl_dart_project_new(), fl_engine_get_embedder_api(), fl_engine_new(), fl_engine_start(), fl_key_embedder_call_record_new(), fl_key_embedder_responder_handle_event(), fl_key_embedder_responder_handle_event_finish(), fl_key_embedder_responder_new(), fl_key_event_new(), g_autoptr(), invoke_record_callback(), kKeyCodeKeyA, TRUE, and user_data.

## ◆ TEST() [14/17]

TEST | ( | FlKeyEmbedderResponderTest | ,
|  | TapLetterKeysBetweenCapsLockEventsReversed |
| ) |  |

Definition at line 1090 of file fl_key_embedder_responder_test.cc.

1090 {
1091 g_autoptr(FlDartProject) project = fl_dart_project_new();
1092 g_autoptr(FlEngine) engine = fl_engine_new(project);
1093 EXPECT_TRUE(fl_engine_start(engine, nullptr));
1094
1095 g_autoptr(FlKeyEmbedderResponder) responder =
1096 fl_key_embedder_responder_new(engine);
1097
1098 g_autoptr(GPtrArray) call_records =
1099 g_ptr_array_new_with_free_func(g_object_unref);
1100 fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
1101 SendKeyEvent,
1102 ([&call_records](auto engine, const FlutterKeyEvent* event,
1103 FlutterKeyEventCallback callback, void* user_data) {
1104 g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
1105 event, callback, user_data));
1106 return kSuccess;
1107 }));
1108
1109 // Press key A (stage 0)
1110 g_autoptr(FlKeyEvent) event1 = fl_key_event_new(
1111 101, kPress, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0);
1112 g_autoptr(GMainLoop) loop1 = g_main_loop_new(nullptr, 0);
1113 fl_key_embedder_responder_handle_event(
1114 responder, event1, 0, nullptr,
1115 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1116 gboolean handled;
1117 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
1118 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1119 EXPECT_EQ(handled, TRUE);
1120
1121 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1122 },
1123 loop1);
1124
1125 EXPECT_EQ(call_records->len, 1u);
1126 FlKeyEmbedderCallRecord* record =
1127 FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1128 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1129 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
1130 EXPECT_EQ(record->event->logical, kLogicalKeyA);
1131 EXPECT_STREQ(record->event->character, "a");
1132 EXPECT_EQ(record->event->synthesized, false);
1133
1134 invoke_record_callback(record, TRUE);
1135 g_main_loop_run(loop1);
1136 clear_records(call_records);
1137
1138 // Press CapsLock (stage 0 -> 1)
1139 g_autoptr(FlKeyEvent) event2 = fl_key_event_new(
1140 102, kPress, kKeyCodeCapsLock, GDK_KEY_Caps_Lock, GDK_LOCK_MASK, 0);
1141 g_autoptr(GMainLoop) loop2 = g_main_loop_new(nullptr, 0);
1142 fl_key_embedder_responder_handle_event(
1143 responder, event2, 0, nullptr,
1144 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1145 gboolean handled;
1146 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
1147 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1148 EXPECT_EQ(handled, TRUE);
1149
1150 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1151 },
1152 loop2);
1153
1154 EXPECT_EQ(call_records->len, 1u);
1155 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1156 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1157 EXPECT_EQ(record->event->physical, kPhysicalCapsLock);
1158 EXPECT_EQ(record->event->logical, kLogicalCapsLock);
1159 EXPECT_STREQ(record->event->character, nullptr);
1160 EXPECT_EQ(record->event->synthesized, false);
1161
1162 invoke_record_callback(record, TRUE);
1163 g_main_loop_run(loop2);
1164 clear_records(call_records);
1165
1166 // Release CapsLock (stage 1 -> 2)
1167 g_autoptr(FlKeyEvent) event3 = fl_key_event_new(
1168 103, kRelease, kKeyCodeCapsLock, GDK_KEY_Caps_Lock, GDK_LOCK_MASK, 0);
1169 g_autoptr(GMainLoop) loop3 = g_main_loop_new(nullptr, 0);
1170 fl_key_embedder_responder_handle_event(
1171 responder, event3, 0, nullptr,
1172 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1173 gboolean handled;
1174 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
1175 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1176 EXPECT_EQ(handled, TRUE);
1177
1178 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1179 },
1180 loop3);
1181
1182 EXPECT_EQ(call_records->len, 1u);
1183 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1184 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1185 EXPECT_EQ(record->event->physical, kPhysicalCapsLock);
1186 EXPECT_EQ(record->event->logical, kLogicalCapsLock);
1187 EXPECT_STREQ(record->event->character, nullptr);
1188 EXPECT_EQ(record->event->synthesized, false);
1189
1190 invoke_record_callback(record, TRUE);
1191 g_main_loop_run(loop3);
1192 clear_records(call_records);
1193
1194 // Release key A (stage 2)
1195 g_autoptr(FlKeyEvent) event4 = fl_key_event_new(104, kRelease, kKeyCodeKeyA,
1196 GDK_KEY_A, GDK_LOCK_MASK, 0);
1197 g_autoptr(GMainLoop) loop4 = g_main_loop_new(nullptr, 0);
1198 fl_key_embedder_responder_handle_event(
1199 responder, event4, 0, nullptr,
1200 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1201 gboolean handled;
1202 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
1203 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1204 EXPECT_EQ(handled, TRUE);
1205
1206 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1207 },
1208 loop4);
1209
1210 EXPECT_EQ(call_records->len, 1u);
1211 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1212 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1213 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
1214 EXPECT_EQ(record->event->logical, kLogicalKeyA);
1215 EXPECT_STREQ(record->event->character, nullptr);
1216 EXPECT_EQ(record->event->synthesized, false);
1217
1218 invoke_record_callback(record, TRUE);
1219 g_main_loop_run(loop4);
1220 clear_records(call_records);
1221
1222 // Press key A (stage 2)
1223 g_autoptr(FlKeyEvent) event5 =
1224 fl_key_event_new(105, kPress, kKeyCodeKeyA, GDK_KEY_A, GDK_LOCK_MASK, 0);
1225 g_autoptr(GMainLoop) loop5 = g_main_loop_new(nullptr, 0);
1226 fl_key_embedder_responder_handle_event(
1227 responder, event5, 0, nullptr,
1228 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1229 gboolean handled;
1230 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
1231 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1232 EXPECT_EQ(handled, TRUE);
1233
1234 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1235 },
1236 loop5);
1237
1238 EXPECT_EQ(call_records->len, 1u);
1239 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1240 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1241 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
1242 EXPECT_EQ(record->event->logical, kLogicalKeyA);
1243 EXPECT_STREQ(record->event->character, "A");
1244 EXPECT_EQ(record->event->synthesized, false);
1245
1246 invoke_record_callback(record, TRUE);
1247 g_main_loop_run(loop5);
1248 clear_records(call_records);
1249
1250 // Press CapsLock (stage 2 -> 3)
1251 g_autoptr(FlKeyEvent) event6 =
1252 fl_key_event_new(106, kPress, kKeyCodeCapsLock, GDK_KEY_Caps_Lock,
1253 static_cast<GdkModifierType>(0), 0);
1254 g_autoptr(GMainLoop) loop6 = g_main_loop_new(nullptr, 0);
1255 fl_key_embedder_responder_handle_event(
1256 responder, event6, 0, nullptr,
1257 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1258 gboolean handled;
1259 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
1260 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1261 EXPECT_EQ(handled, TRUE);
1262
1263 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1264 },
1265 loop6);
1266
1267 EXPECT_EQ(call_records->len, 1u);
1268 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1269 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
1270 EXPECT_EQ(record->event->physical, kPhysicalCapsLock);
1271 EXPECT_EQ(record->event->logical, kLogicalCapsLock);
1272 EXPECT_STREQ(record->event->character, nullptr);
1273 EXPECT_EQ(record->event->synthesized, false);
1274
1275 invoke_record_callback(record, TRUE);
1276 g_main_loop_run(loop6);
1277 clear_records(call_records);
1278
1279 // Release CapsLock (stage 3 -> 0)
1280 g_autoptr(FlKeyEvent) event7 = fl_key_event_new(
1281 107, kRelease, kKeyCodeCapsLock, GDK_KEY_Caps_Lock, GDK_LOCK_MASK, 0);
1282 g_autoptr(GMainLoop) loop7 = g_main_loop_new(nullptr, 0);
1283 fl_key_embedder_responder_handle_event(
1284 responder, event7, 0, nullptr,
1285 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1286 gboolean handled;
1287 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
1288 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1289 EXPECT_EQ(handled, TRUE);
1290
1291 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1292 },
1293 loop7);
1294
1295 EXPECT_EQ(call_records->len, 1u);
1296 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1297 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1298 EXPECT_EQ(record->event->physical, kPhysicalCapsLock);
1299 EXPECT_EQ(record->event->logical, kLogicalCapsLock);
1300 EXPECT_STREQ(record->event->character, nullptr);
1301 EXPECT_EQ(record->event->synthesized, false);
1302
1303 invoke_record_callback(record, TRUE);
1304 g_main_loop_run(loop7);
1305 clear_records(call_records);
1306
1307 // Release key A (stage 0)
1308 g_autoptr(FlKeyEvent) event8 =
1309 fl_key_event_new(108, kRelease, kKeyCodeKeyA, GDK_KEY_a,
1310 static_cast<GdkModifierType>(0), 0);
1311 g_autoptr(GMainLoop) loop8 = g_main_loop_new(nullptr, 0);
1312 fl_key_embedder_responder_handle_event(
1313 responder, event8, 0, nullptr,
1314 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1315 gboolean handled;
1316 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
1317 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1318 EXPECT_EQ(handled, TRUE);
1319
1320 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1321 },
1322 loop8);
1323
1324 EXPECT_EQ(call_records->len, 1u);
1325 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1326 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
1327 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
1328 EXPECT_EQ(record->event->logical, kLogicalKeyA);
1329 EXPECT_STREQ(record->event->character, nullptr);
1330 EXPECT_EQ(record->event->synthesized, false);
1331
1332 invoke_record_callback(record, TRUE);
1333 g_main_loop_run(loop8);
1334 }

References clear_records(), fl_dart_project_new(), fl_engine_get_embedder_api(), fl_engine_new(), fl_engine_start(), fl_key_embedder_call_record_new(), fl_key_embedder_responder_handle_event(), fl_key_embedder_responder_handle_event_finish(), fl_key_embedder_responder_new(), fl_key_event_new(), g_autoptr(), invoke_record_callback(), kKeyCodeKeyA, TRUE, and user_data.

## ◆ TEST() [15/17]

TEST | ( | FlKeyEmbedderResponderTest | ,
|  | TapNumPadKeysBetweenNumLockEvents |
| ) |  |

Definition at line 448 of file fl_key_embedder_responder_test.cc.

448 {
449 g_autoptr(FlDartProject) project = fl_dart_project_new();
450 g_autoptr(FlEngine) engine = fl_engine_new(project);
451 EXPECT_TRUE(fl_engine_start(engine, nullptr));
452
453 g_autoptr(FlKeyEmbedderResponder) responder =
454 fl_key_embedder_responder_new(engine);
455
456 g_autoptr(GPtrArray) call_records =
457 g_ptr_array_new_with_free_func(g_object_unref);
458 fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
459 SendKeyEvent,
460 ([&call_records](auto engine, const FlutterKeyEvent* event,
461 FlutterKeyEventCallback callback, void* user_data) {
462 g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
463 event, callback, user_data));
464 return kSuccess;
465 }));
466
467 // Press Numpad 1 (stage 0)
468 g_autoptr(FlKeyEvent) event1 =
469 fl_key_event_new(101, kPress, kKeyCodeNumpad1, GDK_KEY_KP_End,
470 static_cast<GdkModifierType>(0), 0);
471 g_autoptr(GMainLoop) loop1 = g_main_loop_new(nullptr, 0);
472 fl_key_embedder_responder_handle_event(
473 responder, event1, 0, nullptr,
474 [](GObject* object, GAsyncResult* result, gpointer user_data) {
475 gboolean handled;
476 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
477 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
478 EXPECT_EQ(handled, TRUE);
479
480 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
481 },
482 loop1);
483
484 EXPECT_EQ(call_records->len, 1u);
485 FlKeyEmbedderCallRecord* record =
486 FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
487 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
488 EXPECT_EQ(record->event->physical, kPhysicalNumpad1);
489 EXPECT_EQ(record->event->logical, kLogicalNumpad1);
490 EXPECT_STREQ(record->event->character, nullptr); // TODO(chrome-bot):
491 EXPECT_EQ(record->event->synthesized, false);
492
493 invoke_record_callback(record, TRUE);
494 g_main_loop_run(loop1);
495 clear_records(call_records);
496
497 // Press NumLock (stage 0 -> 1)
498 g_autoptr(FlKeyEvent) event2 =
499 fl_key_event_new(102, kPress, kKeyCodeNumLock, GDK_KEY_Num_Lock,
500 static_cast<GdkModifierType>(0), 0);
501 g_autoptr(GMainLoop) loop2 = g_main_loop_new(nullptr, 0);
502 fl_key_embedder_responder_handle_event(
503 responder, event2, 0, nullptr,
504 [](GObject* object, GAsyncResult* result, gpointer user_data) {
505 gboolean handled;
506 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
507 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
508 EXPECT_EQ(handled, TRUE);
509
510 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
511 },
512 loop2);
513
514 EXPECT_EQ(call_records->len, 1u);
515 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
516 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
517 EXPECT_EQ(record->event->physical, kPhysicalNumLock);
518 EXPECT_EQ(record->event->logical, kLogicalNumLock);
519 EXPECT_STREQ(record->event->character, nullptr);
520 EXPECT_EQ(record->event->synthesized, false);
521
522 invoke_record_callback(record, TRUE);
523 g_main_loop_run(loop2);
524 clear_records(call_records);
525
526 // Release numpad 1 (stage 1)
527 g_autoptr(FlKeyEvent) event3 = fl_key_event_new(
528 104, kRelease, kKeyCodeNumpad1, GDK_KEY_KP_1, GDK_MOD2_MASK, 0);
529 g_autoptr(GMainLoop) loop3 = g_main_loop_new(nullptr, 0);
530 fl_key_embedder_responder_handle_event(
531 responder, event3, 0, nullptr,
532 [](GObject* object, GAsyncResult* result, gpointer user_data) {
533 gboolean handled;
534 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
535 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
536 EXPECT_EQ(handled, TRUE);
537
538 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
539 },
540 loop3);
541
542 EXPECT_EQ(call_records->len, 1u);
543 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
544 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
545 EXPECT_EQ(record->event->physical, kPhysicalNumpad1);
546 EXPECT_EQ(record->event->logical, kLogicalNumpad1);
547 EXPECT_STREQ(record->event->character, nullptr);
548 EXPECT_EQ(record->event->synthesized, false);
549
550 invoke_record_callback(record, TRUE);
551 g_main_loop_run(loop3);
552 clear_records(call_records);
553
554 // Release NumLock (stage 1 -> 2)
555 g_autoptr(FlKeyEvent) event4 = fl_key_event_new(
556 103, kRelease, kKeyCodeNumLock, GDK_KEY_Num_Lock, GDK_MOD2_MASK, 0);
557 g_autoptr(GMainLoop) loop4 = g_main_loop_new(nullptr, 0);
558 fl_key_embedder_responder_handle_event(
559 responder, event4, 0, nullptr,
560 [](GObject* object, GAsyncResult* result, gpointer user_data) {
561 gboolean handled;
562 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
563 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
564 EXPECT_EQ(handled, TRUE);
565
566 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
567 },
568 loop4);
569
570 EXPECT_EQ(call_records->len, 1u);
571 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
572 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
573 EXPECT_EQ(record->event->physical, kPhysicalNumLock);
574 EXPECT_EQ(record->event->logical, kLogicalNumLock);
575 EXPECT_STREQ(record->event->character, nullptr);
576 EXPECT_EQ(record->event->synthesized, false);
577
578 invoke_record_callback(record, TRUE);
579 g_main_loop_run(loop4);
580 clear_records(call_records);
581
582 // Press Numpad 1 (stage 2)
583 g_autoptr(FlKeyEvent) event5 = fl_key_event_new(
584 101, kPress, kKeyCodeNumpad1, GDK_KEY_KP_End, GDK_MOD2_MASK, 0);
585 g_autoptr(GMainLoop) loop5 = g_main_loop_new(nullptr, 0);
586 fl_key_embedder_responder_handle_event(
587 responder, event5, 0, nullptr,
588 [](GObject* object, GAsyncResult* result, gpointer user_data) {
589 gboolean handled;
590 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
591 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
592 EXPECT_EQ(handled, TRUE);
593
594 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
595 },
596 loop5);
597
598 EXPECT_EQ(call_records->len, 1u);
599 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
600 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
601 EXPECT_EQ(record->event->physical, kPhysicalNumpad1);
602 EXPECT_EQ(record->event->logical, kLogicalNumpad1);
603 EXPECT_STREQ(record->event->character, nullptr); // TODO(chrome-bot):
604 EXPECT_EQ(record->event->synthesized, false);
605
606 invoke_record_callback(record, TRUE);
607 g_main_loop_run(loop5);
608 clear_records(call_records);
609
610 // Press NumLock (stage 2 -> 3)
611 g_autoptr(FlKeyEvent) event6 = fl_key_event_new(
612 102, kPress, kKeyCodeNumLock, GDK_KEY_Num_Lock, GDK_MOD2_MASK, 0);
613 g_autoptr(GMainLoop) loop6 = g_main_loop_new(nullptr, 0);
614 fl_key_embedder_responder_handle_event(
615 responder, event6, 0, nullptr,
616 [](GObject* object, GAsyncResult* result, gpointer user_data) {
617 gboolean handled;
618 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
619 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
620 EXPECT_EQ(handled, TRUE);
621
622 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
623 },
624 loop6);
625
626 EXPECT_EQ(call_records->len, 1u);
627 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
628 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
629 EXPECT_EQ(record->event->physical, kPhysicalNumLock);
630 EXPECT_EQ(record->event->logical, kLogicalNumLock);
631 EXPECT_STREQ(record->event->character, nullptr);
632 EXPECT_EQ(record->event->synthesized, false);
633
634 invoke_record_callback(record, TRUE);
635 g_main_loop_run(loop6);
636 clear_records(call_records);
637
638 // Release numpad 1 (stage 3)
639 g_autoptr(FlKeyEvent) event7 = fl_key_event_new(
640 104, kRelease, kKeyCodeNumpad1, GDK_KEY_KP_1, GDK_MOD2_MASK, 0);
641 g_autoptr(GMainLoop) loop7 = g_main_loop_new(nullptr, 0);
642 fl_key_embedder_responder_handle_event(
643 responder, event7, 0, nullptr,
644 [](GObject* object, GAsyncResult* result, gpointer user_data) {
645 gboolean handled;
646 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
647 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
648 EXPECT_EQ(handled, TRUE);
649
650 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
651 },
652 loop7);
653
654 EXPECT_EQ(call_records->len, 1u);
655 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
656 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
657 EXPECT_EQ(record->event->physical, kPhysicalNumpad1);
658 EXPECT_EQ(record->event->logical, kLogicalNumpad1);
659 EXPECT_STREQ(record->event->character, nullptr);
660 EXPECT_EQ(record->event->synthesized, false);
661
662 invoke_record_callback(record, TRUE);
663 g_main_loop_run(loop7);
664 clear_records(call_records);
665
666 // Release NumLock (stage 3 -> 0)
667 g_autoptr(FlKeyEvent) event8 = fl_key_event_new(
668 103, kRelease, kKeyCodeNumLock, GDK_KEY_Num_Lock, GDK_MOD2_MASK, 0);
669 g_autoptr(GMainLoop) loop8 = g_main_loop_new(nullptr, 0);
670 fl_key_embedder_responder_handle_event(
671 responder, event8, 0, nullptr,
672 [](GObject* object, GAsyncResult* result, gpointer user_data) {
673 gboolean handled;
674 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
675 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
676 EXPECT_EQ(handled, TRUE);
677
678 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
679 },
680 loop8);
681
682 EXPECT_EQ(call_records->len, 1u);
683 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
684 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeUp);
685 EXPECT_EQ(record->event->physical, kPhysicalNumLock);
686 EXPECT_EQ(record->event->logical, kLogicalNumLock);
687 EXPECT_STREQ(record->event->character, nullptr);
688 EXPECT_EQ(record->event->synthesized, false);
689
690 invoke_record_callback(record, TRUE);
691 g_main_loop_run(loop8);
692 }

References clear_records(), fl_dart_project_new(), fl_engine_get_embedder_api(), fl_engine_new(), fl_engine_start(), fl_key_embedder_call_record_new(), fl_key_embedder_responder_handle_event(), fl_key_embedder_responder_handle_event_finish(), fl_key_embedder_responder_new(), fl_key_event_new(), g_autoptr(), invoke_record_callback(), TRUE, and user_data.

## ◆ TEST() [16/17]

TEST | ( | FlKeyEmbedderResponderTest | ,
|  | TurnDuplicateDownEventsToRepeats |
| ) |  |

Definition at line 1336 of file fl_key_embedder_responder_test.cc.

1336 {
1337 g_autoptr(FlDartProject) project = fl_dart_project_new();
1338 g_autoptr(FlEngine) engine = fl_engine_new(project);
1339 EXPECT_TRUE(fl_engine_start(engine, nullptr));
1340
1341 g_autoptr(FlKeyEmbedderResponder) responder =
1342 fl_key_embedder_responder_new(engine);
1343
1344 g_autoptr(GPtrArray) call_records =
1345 g_ptr_array_new_with_free_func(g_object_unref);
1346 fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
1347 SendKeyEvent,
1348 ([&call_records](auto engine, const FlutterKeyEvent* event,
1349 FlutterKeyEventCallback callback, void* user_data) {
1350 g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
1351 event, callback, user_data));
1352 return kSuccess;
1353 }));
1354
1355 // Press KeyA
1356 g_autoptr(FlKeyEvent) event1 = fl_key_event_new(
1357 101, kPress, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0);
1358 g_autoptr(GMainLoop) loop1 = g_main_loop_new(nullptr, 0);
1359 fl_key_embedder_responder_handle_event(
1360 responder, event1, 0, nullptr,
1361 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1362 gboolean handled;
1363 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
1364 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1365 EXPECT_EQ(handled, TRUE);
1366
1367 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1368 },
1369 loop1);
1370
1371 EXPECT_EQ(call_records->len, 1u);
1372
1373 FlKeyEmbedderCallRecord* record =
1374 FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1375 invoke_record_callback(record, TRUE);
1376 g_main_loop_run(loop1);
1377 clear_records(call_records);
1378
1379 // Another KeyA down events, which usually means a repeated event.
1380 g_autoptr(FlKeyEvent) event2 = fl_key_event_new(
1381 102, kPress, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0);
1382 g_autoptr(GMainLoop) loop2 = g_main_loop_new(nullptr, 0);
1383 fl_key_embedder_responder_handle_event(
1384 responder, event2, 0, nullptr,
1385 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1386 gboolean handled;
1387 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
1388 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1389 EXPECT_EQ(handled, TRUE);
1390
1391 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1392 },
1393 loop2);
1394
1395 EXPECT_EQ(call_records->len, 1u);
1396
1397 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1398 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeRepeat);
1399 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
1400 EXPECT_EQ(record->event->logical, kLogicalKeyA);
1401 EXPECT_STREQ(record->event->character, "a");
1402 EXPECT_EQ(record->event->synthesized, false);
1403 EXPECT_NE(record->callback, nullptr);
1404
1405 invoke_record_callback(record, TRUE);
1406 g_main_loop_run(loop2);
1407 clear_records(call_records);
1408
1409 // Release KeyA
1410 g_autoptr(FlKeyEvent) event3 =
1411 fl_key_event_new(103, kRelease, kKeyCodeKeyA, GDK_KEY_q,
1412 static_cast<GdkModifierType>(0), 0);
1413 g_autoptr(GMainLoop) loop3 = g_main_loop_new(nullptr, 0);
1414 fl_key_embedder_responder_handle_event(
1415 responder, event3, 0, nullptr,
1416 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1417 gboolean handled;
1418 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
1419 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1420 EXPECT_EQ(handled, TRUE);
1421
1422 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1423 },
1424 loop3);
1425
1426 EXPECT_EQ(call_records->len, 1u);
1427 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1428 invoke_record_callback(record, TRUE);
1429 g_main_loop_run(loop3);
1430 }

References clear_records(), fl_dart_project_new(), fl_engine_get_embedder_api(), fl_engine_new(), fl_engine_start(), fl_key_embedder_call_record_new(), fl_key_embedder_responder_handle_event(), fl_key_embedder_responder_handle_event_finish(), fl_key_embedder_responder_new(), fl_key_event_new(), g_autoptr(), invoke_record_callback(), kKeyCodeKeyA, TRUE, and user_data.

## ◆ TEST() [17/17]

TEST | ( | FlKeyEmbedderResponderTest | ,
|  | UsesSpecifiedLogicalKey |
| ) |  |

Definition at line 253 of file fl_key_embedder_responder_test.cc.

253 {
254 g_autoptr(FlDartProject) project = fl_dart_project_new();
255 g_autoptr(FlEngine) engine = fl_engine_new(project);
256 EXPECT_TRUE(fl_engine_start(engine, nullptr));
257
258 g_autoptr(FlKeyEmbedderResponder) responder =
259 fl_key_embedder_responder_new(engine);
260
261 g_autoptr(GPtrArray) call_records =
262 g_ptr_array_new_with_free_func(g_object_unref);
263 fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
264 SendKeyEvent,
265 ([&call_records](auto engine, const FlutterKeyEvent* event,
266 FlutterKeyEventCallback callback, void* user_data) {
267 g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
268 event, callback, user_data));
269 return kSuccess;
270 }));
271
272 // On an AZERTY keyboard, press physical key 1, and release.
273 // Key down
274 g_autoptr(FlKeyEvent) event =
275 fl_key_event_new(12345, kPress, kKeyCodeDigit1, GDK_KEY_ampersand,
276 static_cast<GdkModifierType>(0), 0);
277 g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
278 fl_key_embedder_responder_handle_event(
279 responder, event, kLogicalDigit1, nullptr,
280 [](GObject* object, GAsyncResult* result, gpointer user_data) {
281 gboolean handled;
282 EXPECT_TRUE(fl_key_embedder_responder_handle_event_finish(
283 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
284 EXPECT_EQ(handled, TRUE);
285
286 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
287 },
288 loop);
289
290 EXPECT_EQ(call_records->len, 1u);
291 FlKeyEmbedderCallRecord* record =
292 FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
293 EXPECT_EQ(record->event->struct_size, sizeof(FlutterKeyEvent));
294 EXPECT_EQ(record->event->timestamp, 12345000);
295 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
296 EXPECT_EQ(record->event->physical, kPhysicalDigit1);
297 EXPECT_EQ(record->event->logical, kLogicalDigit1);
298 EXPECT_STREQ(record->event->character, "&");
299 EXPECT_EQ(record->event->synthesized, false);
300
301 invoke_record_callback(record, TRUE);
302 g_main_loop_run(loop);
303 }

References fl_dart_project_new(), fl_engine_get_embedder_api(), fl_engine_new(), fl_engine_start(), fl_key_embedder_call_record_new(), fl_key_embedder_responder_handle_event(), fl_key_embedder_responder_handle_event_finish(), fl_key_embedder_responder_new(), fl_key_event_new(), g_autoptr(), invoke_record_callback(), TRUE, and user_data.