Flutter Engine
 
Loading...
Searching...
No Matches
fl_key_embedder_responder_test.cc File Reference

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(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), and 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}
static void fl_key_embedder_call_record_dispose(GObject *object)

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}

References self.

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}
FlutterDesktopBinaryReply callback
const char * character
Definition embedder.h:1409

References callback, FlutterKeyEvent::character, self, and user_data.

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

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

References callback, engine, 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(), kFlutterKeyEventTypeDown, kFlutterKeyEventTypeUp, kSuccess, MOCK_ENGINE_PROC, send_key_event(), FlutterEngineProcTable::SendKeyEvent, 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 =
1439
1440 g_autoptr(GPtrArray) call_records =
1441 g_ptr_array_new_with_free_func(g_object_unref);
1443 SendKeyEvent,
1444 ([&call_records](auto engine, const FlutterKeyEvent* event,
1446 g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
1447 event, callback, user_data));
1448 return kSuccess;
1449 }));
1450
1451 // Release KeyA before it was even pressed.
1452 g_autoptr(FlKeyEvent) event =
1453 fl_key_event_new(103, kRelease, kKeyCodeKeyA, GDK_KEY_q,
1454 static_cast<GdkModifierType>(0), 0);
1455 g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
1457 responder, event, 0, nullptr,
1458 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1459 gboolean handled;
1461 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1462 EXPECT_EQ(handled, TRUE);
1463
1464 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1465 },
1466 loop);
1467
1468 EXPECT_EQ(call_records->len, 1u);
1469
1470 FlKeyEmbedderCallRecord* record =
1471 FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1472 EXPECT_EQ(record->event->physical, 0ull);
1473 EXPECT_EQ(record->event->logical, 0ull);
1474 EXPECT_STREQ(record->event->character, nullptr);
1475 EXPECT_EQ(record->event->synthesized, false);
1476
1478 g_main_loop_run(loop);
1479}
static void invoke_record_callback(FlKeyEmbedderCallRecord *record, bool expected_handled)
constexpr guint16 kKeyCodeKeyA

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

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

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

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

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

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

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

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

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

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

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

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

References callback, clear_records(), engine, 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(), kFlutterKeyEventTypeDown, kFlutterKeyEventTypeUp, kSuccess, MOCK_ENGINE_PROC, FlutterEngineProcTable::SendKeyEvent, 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 =
1343
1344 g_autoptr(GPtrArray) call_records =
1345 g_ptr_array_new_with_free_func(g_object_unref);
1347 SendKeyEvent,
1348 ([&call_records](auto engine, const FlutterKeyEvent* event,
1350 g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
1351 event, callback, user_data));
1352 return kSuccess;
1353 }));
1354
1355 // Press KeyA
1356 g_autoptr(FlKeyEvent) event1 = fl_key_event_new(
1357 101, kPress, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0);
1358 g_autoptr(GMainLoop) loop1 = g_main_loop_new(nullptr, 0);
1360 responder, event1, 0, nullptr,
1361 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1362 gboolean handled;
1364 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1365 EXPECT_EQ(handled, TRUE);
1366
1367 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1368 },
1369 loop1);
1370
1371 EXPECT_EQ(call_records->len, 1u);
1372
1373 FlKeyEmbedderCallRecord* record =
1374 FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1376 g_main_loop_run(loop1);
1377 clear_records(call_records);
1378
1379 // Another KeyA down events, which usually means a repeated event.
1380 g_autoptr(FlKeyEvent) event2 = fl_key_event_new(
1381 102, kPress, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0);
1382 g_autoptr(GMainLoop) loop2 = g_main_loop_new(nullptr, 0);
1384 responder, event2, 0, nullptr,
1385 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1386 gboolean handled;
1388 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1389 EXPECT_EQ(handled, TRUE);
1390
1391 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1392 },
1393 loop2);
1394
1395 EXPECT_EQ(call_records->len, 1u);
1396
1397 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1398 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeRepeat);
1399 EXPECT_EQ(record->event->physical, kPhysicalKeyA);
1400 EXPECT_EQ(record->event->logical, kLogicalKeyA);
1401 EXPECT_STREQ(record->event->character, "a");
1402 EXPECT_EQ(record->event->synthesized, false);
1403 EXPECT_NE(record->callback, nullptr);
1404
1406 g_main_loop_run(loop2);
1407 clear_records(call_records);
1408
1409 // Release KeyA
1410 g_autoptr(FlKeyEvent) event3 =
1411 fl_key_event_new(103, kRelease, kKeyCodeKeyA, GDK_KEY_q,
1412 static_cast<GdkModifierType>(0), 0);
1413 g_autoptr(GMainLoop) loop3 = g_main_loop_new(nullptr, 0);
1415 responder, event3, 0, nullptr,
1416 [](GObject* object, GAsyncResult* result, gpointer user_data) {
1417 gboolean handled;
1419 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
1420 EXPECT_EQ(handled, TRUE);
1421
1422 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
1423 },
1424 loop3);
1425
1426 EXPECT_EQ(call_records->len, 1u);
1427 record = FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
1429 g_main_loop_run(loop3);
1430}
@ kFlutterKeyEventTypeRepeat
Definition embedder.h:1349

References callback, clear_records(), engine, 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(), kFlutterKeyEventTypeRepeat, kKeyCodeKeyA, kSuccess, MOCK_ENGINE_PROC, FlutterEngineProcTable::SendKeyEvent, 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 =
260
261 g_autoptr(GPtrArray) call_records =
262 g_ptr_array_new_with_free_func(g_object_unref);
264 SendKeyEvent,
265 ([&call_records](auto engine, const FlutterKeyEvent* event,
267 g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
268 event, callback, user_data));
269 return kSuccess;
270 }));
271
272 // On an AZERTY keyboard, press physical key 1, and release.
273 // Key down
274 g_autoptr(FlKeyEvent) event =
275 fl_key_event_new(12345, kPress, kKeyCodeDigit1, GDK_KEY_ampersand,
276 static_cast<GdkModifierType>(0), 0);
277 g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
279 responder, event, kLogicalDigit1, nullptr,
280 [](GObject* object, GAsyncResult* result, gpointer user_data) {
281 gboolean handled;
283 FL_KEY_EMBEDDER_RESPONDER(object), result, &handled, nullptr));
284 EXPECT_EQ(handled, TRUE);
285
286 g_main_loop_quit(static_cast<GMainLoop*>(user_data));
287 },
288 loop);
289
290 EXPECT_EQ(call_records->len, 1u);
291 FlKeyEmbedderCallRecord* record =
292 FL_KEY_EMBEDDER_CALL_RECORD(g_ptr_array_index(call_records, 0));
293 EXPECT_EQ(record->event->struct_size, sizeof(FlutterKeyEvent));
294 EXPECT_EQ(record->event->timestamp, 12345000);
295 EXPECT_EQ(record->event->type, kFlutterKeyEventTypeDown);
296 EXPECT_EQ(record->event->physical, kPhysicalDigit1);
297 EXPECT_EQ(record->event->logical, kLogicalDigit1);
298 EXPECT_STREQ(record->event->character, "&");
299 EXPECT_EQ(record->event->synthesized, false);
300
302 g_main_loop_run(loop);
303}

References callback, engine, 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(), kFlutterKeyEventTypeDown, kSuccess, MOCK_ENGINE_PROC, FlutterEngineProcTable::SendKeyEvent, TRUE, and user_data.