Flutter Linux Embedder
fl_key_embedder_responder_test.cc File Reference
#include "flutter/shell/platform/linux/fl_key_embedder_responder.h"
#include "gtest/gtest.h"
#include "flutter/shell/platform/embedder/test_utils/key_codes.g.h"
#include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h"
#include "flutter/shell/platform/linux/public/flutter_linux/fl_engine.h"
#include "flutter/shell/platform/linux/testing/fl_test.h"

Go to the source code of this file.

Classes

struct  _FlKeyEmbedderCallRecord
 

Functions

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

Function Documentation

◆ clear_records()

static void clear_records ( GPtrArray *  array)
static

Definition at line 33 of file fl_key_embedder_responder_test.cc.

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

Referenced by TEST().

◆ fl_key_embedder_call_record_class_init()

static void fl_key_embedder_call_record_class_init ( FlKeyEmbedderCallRecordClass *  klass)
static

Definition at line 70 of file fl_key_embedder_responder_test.cc.

71  {
72  G_OBJECT_CLASS(klass)->dispose = fl_key_embedder_call_record_dispose;
73 }

References fl_key_embedder_call_record_dispose().

◆ fl_key_embedder_call_record_dispose()

static void fl_key_embedder_call_record_dispose ( GObject *  object)
static

Definition at line 58 of file fl_key_embedder_responder_test.cc.

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

Referenced by fl_key_embedder_call_record_class_init().

◆ fl_key_embedder_call_record_new()

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

Definition at line 75 of file fl_key_embedder_responder_test.cc.

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

References user_data.

Referenced by TEST().

◆ G_DECLARE_FINAL_TYPE()

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

◆ G_DEFINE_TYPE()

G_DEFINE_TYPE ( FlKeyEmbedderCallRecord  ,
fl_key_embedder_call_record  ,
G_TYPE_OBJECT   
)

Definition at line 51 of file fl_key_embedder_responder_test.cc.

55  {}

◆ invoke_record_callback()

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

Definition at line 99 of file fl_key_embedder_responder_test.cc.

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

Referenced by TEST().

◆ TEST() [1/17]

TEST ( FlKeyEmbedderResponderTest  ,
HandlesShiftAltLeftIsMetaLeft   
)

Definition at line 2413 of file fl_key_embedder_responder_test.cc.

2413  {
2414  g_autoptr(FlDartProject) project = fl_dart_project_new();
2415  g_autoptr(FlEngine) engine = fl_engine_new(project);
2416  EXPECT_TRUE(fl_engine_start(engine, nullptr));
2417 
2418  g_autoptr(FlKeyEmbedderResponder) responder =
2420 
2421  g_autoptr(GPtrArray) call_records =
2422  g_ptr_array_new_with_free_func(g_object_unref);
2423  fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
2424  SendKeyEvent,
2425  ([&call_records](auto engine, const FlutterKeyEvent* event,
2426  FlutterKeyEventCallback callback, void* user_data) {
2427  g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
2428  event, callback, user_data));
2429  callback(true, user_data);
2430  return kSuccess;
2431  }));
2432 
2433  guint32 now_time = 1;
2434  // A convenient shorthand to simulate events.
2435  auto send_key_event = [responder, &now_time](bool is_press, guint keyval,
2436  guint16 keycode,
2437  GdkModifierType state) {
2438  now_time += 1;
2439  g_autoptr(FlKeyEvent) event =
2440  fl_key_event_new(now_time, is_press, keycode, keyval, state, 0);
2441  g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
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 }

References clear_records(), fl_dart_project_new(), fl_engine_get_embedder_api(), fl_engine_new(), fl_engine_start(), fl_key_embedder_call_record_new(), fl_key_embedder_responder_handle_event(), fl_key_embedder_responder_handle_event_finish(), fl_key_embedder_responder_new(), fl_key_event_new(), send_key_event(), state, 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);
2296  fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
2297  SendKeyEvent,
2298  ([&call_records](auto engine, const FlutterKeyEvent* event,
2299  FlutterKeyEventCallback callback, void* user_data) {
2300  g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
2301  event, callback, user_data));
2302  callback(true, user_data);
2303  return kSuccess;
2304  }));
2305 
2306  guint32 now_time = 1;
2307  // A convenient shorthand to simulate events.
2308  auto send_key_event = [responder, &now_time](bool is_press, guint keyval,
2309  guint16 keycode,
2310  GdkModifierType state) {
2311  now_time += 1;
2312  g_autoptr(FlKeyEvent) event =
2313  fl_key_event_new(now_time, is_press, keycode, keyval, state, 0);
2314  g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
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 }

References fl_dart_project_new(), fl_engine_get_embedder_api(), fl_engine_new(), fl_engine_start(), fl_key_embedder_call_record_new(), fl_key_embedder_responder_handle_event(), fl_key_embedder_responder_handle_event_finish(), fl_key_embedder_responder_new(), fl_key_event_new(), send_key_event(), state, 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);
1442  fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
1443  SendKeyEvent,
1444  ([&call_records](auto engine, const FlutterKeyEvent* event,
1445  FlutterKeyEventCallback callback, void* user_data) {
1446  g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
1447  event, callback, user_data));
1448  return kSuccess;
1449  }));
1450 
1451  // Release KeyA before it was even pressed.
1452  g_autoptr(FlKeyEvent) event =
1453  fl_key_event_new(103, kRelease, kKeyCodeKeyA, GDK_KEY_q,
1454  static_cast<GdkModifierType>(0), 0);
1455  g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
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 
1477  invoke_record_callback(record, TRUE);
1478  g_main_loop_run(loop);
1479 }

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

◆ TEST() [4/17]

TEST ( FlKeyEmbedderResponderTest  ,
PressShiftDuringLetterKeyTap   
)

Definition at line 306 of file fl_key_embedder_responder_test.cc.

306  {
307  g_autoptr(FlDartProject) project = fl_dart_project_new();
308  g_autoptr(FlEngine) engine = fl_engine_new(project);
309  EXPECT_TRUE(fl_engine_start(engine, nullptr));
310 
311  g_autoptr(FlKeyEmbedderResponder) responder =
313 
314  g_autoptr(GPtrArray) call_records =
315  g_ptr_array_new_with_free_func(g_object_unref);
316  fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
317  SendKeyEvent,
318  ([&call_records](auto engine, const FlutterKeyEvent* event,
319  FlutterKeyEventCallback callback, void* user_data) {
320  g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
321  event, callback, user_data));
322  return kSuccess;
323  }));
324 
325  // Press shift right
326  g_autoptr(FlKeyEvent) event1 =
327  fl_key_event_new(101, kPress, kKeyCodeShiftRight, GDK_KEY_Shift_R,
328  static_cast<GdkModifierType>(0), 0);
329  g_autoptr(GMainLoop) loop1 = g_main_loop_new(nullptr, 0);
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 
351  invoke_record_callback(record, TRUE);
352  g_main_loop_run(loop1);
353  clear_records(call_records);
354 
355  // Press key A
356  g_autoptr(FlKeyEvent) event2 =
357  fl_key_event_new(102, kPress, kKeyCodeKeyA, GDK_KEY_A, GDK_SHIFT_MASK, 0);
358  g_autoptr(GMainLoop) loop2 = g_main_loop_new(nullptr, 0);
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 
379  invoke_record_callback(record, TRUE);
380  g_main_loop_run(loop2);
381  clear_records(call_records);
382 
383  // Release shift right
384  g_autoptr(FlKeyEvent) event3 = fl_key_event_new(
385  103, kRelease, kKeyCodeShiftRight, GDK_KEY_Shift_R, GDK_SHIFT_MASK, 0);
386  g_autoptr(GMainLoop) loop3 = g_main_loop_new(nullptr, 0);
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 
407  invoke_record_callback(record, TRUE);
408  g_main_loop_run(loop3);
409  clear_records(call_records);
410 
411  // Release key A
412  g_autoptr(FlKeyEvent) event4 =
413  fl_key_event_new(104, kRelease, kKeyCodeKeyA, GDK_KEY_A,
414  static_cast<GdkModifierType>(0), 0);
415  g_autoptr(GMainLoop) loop4 = g_main_loop_new(nullptr, 0);
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 
436  invoke_record_callback(record, TRUE);
437  g_main_loop_run(loop4);
438 }

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

◆ TEST() [5/17]

TEST ( FlKeyEmbedderResponderTest  ,
ReleaseShiftKeyBetweenDigitKeyEvents   
)

Definition at line 698 of file fl_key_embedder_responder_test.cc.

698  {
699  g_autoptr(FlDartProject) project = fl_dart_project_new();
700  g_autoptr(FlEngine) engine = fl_engine_new(project);
701  EXPECT_TRUE(fl_engine_start(engine, nullptr));
702 
703  g_autoptr(FlKeyEmbedderResponder) responder =
705 
706  g_autoptr(GPtrArray) call_records =
707  g_ptr_array_new_with_free_func(g_object_unref);
708  fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
709  SendKeyEvent,
710  ([&call_records](auto engine, const FlutterKeyEvent* event,
711  FlutterKeyEventCallback callback, void* user_data) {
712  g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
713  event, callback, user_data));
714  return kSuccess;
715  }));
716 
717  GdkModifierType state = static_cast<GdkModifierType>(0);
718 
719  // Press shift left
720  g_autoptr(FlKeyEvent) event1 = fl_key_event_new(
721  101, kPress, kKeyCodeShiftLeft, GDK_KEY_Shift_L, state, 0);
722  g_autoptr(GMainLoop) loop1 = g_main_loop_new(nullptr, 0);
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 
744  invoke_record_callback(record, TRUE);
745  g_main_loop_run(loop1);
746  clear_records(call_records);
747 
748  state = GDK_SHIFT_MASK;
749 
750  // Press digit 1, which is '!' on a US keyboard
751  g_autoptr(FlKeyEvent) event2 =
752  fl_key_event_new(102, kPress, kKeyCodeDigit1, GDK_KEY_exclam, state, 0);
753  g_autoptr(GMainLoop) loop2 = g_main_loop_new(nullptr, 0);
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 
774  invoke_record_callback(record, TRUE);
775  g_main_loop_run(loop2);
776  clear_records(call_records);
777 
778  // Release shift
779  g_autoptr(FlKeyEvent) event3 = fl_key_event_new(
780  103, kRelease, kKeyCodeShiftLeft, GDK_KEY_Shift_L, state, 0);
781  g_autoptr(GMainLoop) loop3 = g_main_loop_new(nullptr, 0);
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 
802  invoke_record_callback(record, TRUE);
803  g_main_loop_run(loop3);
804  clear_records(call_records);
805 
806  state = static_cast<GdkModifierType>(0);
807 
808  // Release digit 1, which is "1" because shift has been released.
809  g_autoptr(FlKeyEvent) event4 =
810  fl_key_event_new(104, kRelease, kKeyCodeDigit1, GDK_KEY_1, state, 0);
811  g_autoptr(GMainLoop) loop4 = g_main_loop_new(nullptr, 0);
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 
832  invoke_record_callback(record, TRUE);
833  g_main_loop_run(loop4);
834 }

References clear_records(), fl_dart_project_new(), fl_engine_get_embedder_api(), fl_engine_new(), fl_engine_start(), fl_key_embedder_call_record_new(), fl_key_embedder_responder_handle_event(), fl_key_embedder_responder_handle_event_finish(), fl_key_embedder_responder_new(), fl_key_event_new(), invoke_record_callback(), state, 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);
116  fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
117  SendKeyEvent,
118  ([&call_records](auto engine, const FlutterKeyEvent* event,
119  FlutterKeyEventCallback callback, void* user_data) {
120  g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
121  event, callback, user_data));
122  return kSuccess;
123  }));
124 
125  // On a QWERTY keyboard, press key Q (physically key A), and release.
126  // Key down
127  g_autoptr(FlKeyEvent) event1 =
128  fl_key_event_new(12345, kPress, kKeyCodeKeyA, GDK_KEY_a,
129  static_cast<GdkModifierType>(0), 0);
130  g_autoptr(GMainLoop) loop1 = g_main_loop_new(nullptr, 0);
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 
154  invoke_record_callback(record, TRUE);
155  g_main_loop_run(loop1);
156  clear_records(call_records);
157 
158  // Key up
159  g_autoptr(FlKeyEvent) event2 =
160  fl_key_event_new(12346, kRelease, kKeyCodeKeyA, GDK_KEY_a,
161  static_cast<GdkModifierType>(0), 0);
162  g_autoptr(GMainLoop) loop2 = g_main_loop_new(nullptr, 0);
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 
217  invoke_record_callback(record, TRUE);
218  g_main_loop_run(loop3);
219  clear_records(call_records);
220 
221  // Key up
222  g_autoptr(FlKeyEvent) event4 =
223  fl_key_event_new(12348, kRelease, kKeyCodeKeyA, GDK_KEY_q,
224  static_cast<GdkModifierType>(0), 0);
225  g_autoptr(GMainLoop) loop4 = g_main_loop_new(nullptr, 0);
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 clear_records(), fl_dart_project_new(), fl_engine_get_embedder_api(), fl_engine_new(), fl_engine_start(), fl_key_embedder_call_record_new(), fl_key_embedder_responder_handle_event(), fl_key_embedder_responder_handle_event_finish(), fl_key_embedder_responder_new(), fl_key_event_new(), invoke_record_callback(), kKeyCodeKeyA, TRUE, and user_data.

◆ TEST() [7/17]

TEST ( FlKeyEmbedderResponderTest  ,
SynthesizationOccursOnIgnoredEvents   
)

Definition at line 2217 of file fl_key_embedder_responder_test.cc.

2217  {
2218  g_autoptr(FlDartProject) project = fl_dart_project_new();
2219  g_autoptr(FlEngine) engine = fl_engine_new(project);
2220  EXPECT_TRUE(fl_engine_start(engine, nullptr));
2221 
2222  g_autoptr(FlKeyEmbedderResponder) responder =
2224 
2225  g_autoptr(GPtrArray) call_records =
2226  g_ptr_array_new_with_free_func(g_object_unref);
2227  fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
2228  SendKeyEvent,
2229  ([&call_records](auto engine, const FlutterKeyEvent* event,
2230  FlutterKeyEventCallback callback, void* user_data) {
2231  g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
2232  event, callback, user_data));
2233  return kSuccess;
2234  }));
2235 
2236  // The NumLock is desynchronized by being enabled, and Control is pressed.
2237  GdkModifierType state =
2238  static_cast<GdkModifierType>(GDK_MOD2_MASK | GDK_CONTROL_MASK);
2239 
2240  // Send a KeyA up event, which will be ignored.
2241  g_autoptr(FlKeyEvent) event =
2242  fl_key_event_new(101, kRelease, kKeyCodeKeyA, GDK_KEY_a, state, 0);
2243  g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
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 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(), kKeyCodeKeyA, state, 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);
1955  fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
1956  SendKeyEvent,
1957  ([&call_records](auto engine, const FlutterKeyEvent* event,
1958  FlutterKeyEventCallback callback, void* user_data) {
1959  g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
1960  event, callback, user_data));
1961  return kSuccess;
1962  }));
1963 
1964  // The NumLock is desynchronized by being enabled.
1965  GdkModifierType state = GDK_MOD2_MASK;
1966 
1967  // Send a normal event
1968  g_autoptr(FlKeyEvent) event1 =
1969  fl_key_event_new(101, kPress, kKeyCodeKeyA, GDK_KEY_a, state, 0);
1970  g_autoptr(GMainLoop) loop1 = g_main_loop_new(nullptr, 0);
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 
2001  invoke_record_callback(record, TRUE);
2002  g_main_loop_run(loop1);
2003  clear_records(call_records);
2004 
2005  // The NumLock is desynchronized by being disabled.
2006  state = static_cast<GdkModifierType>(0);
2007 
2008  // Release key A
2009  g_autoptr(FlKeyEvent) event2 =
2010  fl_key_event_new(102, kRelease, kKeyCodeKeyA, GDK_KEY_A, state, 0);
2011  g_autoptr(GMainLoop) loop2 = g_main_loop_new(nullptr, 0);
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 
2057  invoke_record_callback(record, TRUE);
2058  g_main_loop_run(loop2);
2059  clear_records(call_records);
2060 
2061  // Release NumLock. Since the previous event should have synthesized NumLock
2062  // to be released, this should result in only an empty event.
2063  g_autoptr(FlKeyEvent) event3 = fl_key_event_new(
2064  103, kRelease, kKeyCodeNumLock, GDK_KEY_Num_Lock, state, 0);
2065  g_autoptr(GMainLoop) loop3 = g_main_loop_new(nullptr, 0);
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 
2085  invoke_record_callback(record, TRUE);
2086  g_main_loop_run(loop3);
2087 }

References clear_records(), fl_dart_project_new(), fl_engine_get_embedder_api(), fl_engine_new(), fl_engine_start(), fl_key_embedder_call_record_new(), fl_key_embedder_responder_handle_event(), fl_key_embedder_responder_handle_event_finish(), fl_key_embedder_responder_new(), fl_key_event_new(), invoke_record_callback(), kKeyCodeKeyA, state, 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);
2101  fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
2102  SendKeyEvent,
2103  ([&call_records](auto engine, const FlutterKeyEvent* event,
2104  FlutterKeyEventCallback callback, void* user_data) {
2105  g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
2106  event, callback, user_data));
2107  return kSuccess;
2108  }));
2109 
2110  // The NumLock is desynchronized by being enabled.
2111  GdkModifierType state = GDK_MOD2_MASK;
2112 
2113  // NumLock down
2114  g_autoptr(FlKeyEvent) event1 = fl_key_event_new(101, kPress, kKeyCodeNumLock,
2115  GDK_KEY_Num_Lock, state, 0);
2116  g_autoptr(GMainLoop) loop1 = g_main_loop_new(nullptr, 0);
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 
2155  invoke_record_callback(record, TRUE);
2156  g_main_loop_run(loop1);
2157  clear_records(call_records);
2158 
2159  // The NumLock is desynchronized by being enabled in a press event.
2160  state = GDK_MOD2_MASK;
2161 
2162  // NumLock up
2163  g_autoptr(FlKeyEvent) event2 = fl_key_event_new(102, kPress, kKeyCodeNumLock,
2164  GDK_KEY_Num_Lock, state, 0);
2165  g_autoptr(GMainLoop) loop2 = g_main_loop_new(nullptr, 0);
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 
2211  invoke_record_callback(record, TRUE);
2212  g_main_loop_run(loop2);
2213 }

References clear_records(), fl_dart_project_new(), fl_engine_get_embedder_api(), fl_engine_new(), fl_engine_start(), fl_key_embedder_call_record_new(), fl_key_embedder_responder_handle_event(), fl_key_embedder_responder_handle_event_finish(), fl_key_embedder_responder_new(), fl_key_event_new(), invoke_record_callback(), state, 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);
1682  fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
1683  SendKeyEvent,
1684  ([&call_records](auto engine, const FlutterKeyEvent* event,
1685  FlutterKeyEventCallback callback, void* user_data) {
1686  g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
1687  event, callback, user_data));
1688  return kSuccess;
1689  }));
1690 
1691  // A key down of control left is missed.
1692  GdkModifierType state = GDK_CONTROL_MASK;
1693 
1694  // Send a normal event (KeyA down)
1695  g_autoptr(FlKeyEvent) event1 =
1696  fl_key_event_new(101, kPress, kKeyCodeKeyA, GDK_KEY_a, state, 0);
1697  g_autoptr(GMainLoop) loop1 = g_main_loop_new(nullptr, 0);
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 
1728  invoke_record_callback(record, TRUE);
1729  g_main_loop_run(loop1);
1730  clear_records(call_records);
1731 
1732  // A key up of control left is missed.
1733  state = static_cast<GdkModifierType>(0);
1734 
1735  // Send a normal event (KeyA up)
1736  g_autoptr(FlKeyEvent) event2 =
1737  fl_key_event_new(102, kRelease, kKeyCodeKeyA, GDK_KEY_A, state, 0);
1738  g_autoptr(GMainLoop) loop2 = g_main_loop_new(nullptr, 0);
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 
1768  invoke_record_callback(record, TRUE);
1769  g_main_loop_run(loop2);
1770  clear_records(call_records);
1771 
1772  // Test non-default key mapping.
1773 
1774  // Press a key with physical CapsLock and logical ControlLeft.
1775  state = static_cast<GdkModifierType>(0);
1776 
1777  g_autoptr(FlKeyEvent) event3 = fl_key_event_new(101, kPress, kKeyCodeCapsLock,
1778  GDK_KEY_Control_L, state, 0);
1779  g_autoptr(GMainLoop) loop3 = g_main_loop_new(nullptr, 0);
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 
1801  invoke_record_callback(record, TRUE);
1802  g_main_loop_run(loop3);
1803  clear_records(call_records);
1804 
1805  // The key up of the control left press is missed.
1806  state = static_cast<GdkModifierType>(0);
1807 
1808  // Send a normal event (KeyA down).
1809  g_autoptr(FlKeyEvent) event4 =
1810  fl_key_event_new(102, kPress, kKeyCodeKeyA, GDK_KEY_A, state, 0);
1811  g_autoptr(GMainLoop) loop4 = g_main_loop_new(nullptr, 0);
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 
1843  invoke_record_callback(record, TRUE);
1844  g_main_loop_run(loop4);
1845 }

References clear_records(), fl_dart_project_new(), fl_engine_get_embedder_api(), fl_engine_new(), fl_engine_start(), fl_key_embedder_call_record_new(), fl_key_embedder_responder_handle_event(), fl_key_embedder_responder_handle_event_finish(), fl_key_embedder_responder_new(), fl_key_event_new(), invoke_record_callback(), kKeyCodeKeyA, state, 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);
1860  fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
1861  SendKeyEvent,
1862  ([&call_records](auto engine, const FlutterKeyEvent* event,
1863  FlutterKeyEventCallback callback, void* user_data) {
1864  g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
1865  event, callback, user_data));
1866  return kSuccess;
1867  }));
1868 
1869  // Press a key with physical CapsLock and logical ControlLeft.
1870  GdkModifierType state = static_cast<GdkModifierType>(0);
1871 
1872  g_autoptr(FlKeyEvent) event1 = fl_key_event_new(101, kPress, kKeyCodeCapsLock,
1873  GDK_KEY_Control_L, state, 0);
1874  g_autoptr(GMainLoop) loop1 = g_main_loop_new(nullptr, 0);
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 
1897  invoke_record_callback(record, TRUE);
1898  g_main_loop_run(loop1);
1899  clear_records(call_records);
1900 
1901  // The key up of the control left press is missed.
1902  state = static_cast<GdkModifierType>(0);
1903 
1904  // Send a normal event (KeyA down).
1905  g_autoptr(FlKeyEvent) event2 =
1906  fl_key_event_new(102, kPress, kKeyCodeKeyA, GDK_KEY_A, state, 0);
1907  g_autoptr(GMainLoop) loop2 = g_main_loop_new(nullptr, 0);
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 
1939  invoke_record_callback(record, TRUE);
1940  g_main_loop_run(loop2);
1941 }

References clear_records(), fl_dart_project_new(), fl_engine_get_embedder_api(), fl_engine_new(), fl_engine_start(), fl_key_embedder_call_record_new(), fl_key_embedder_responder_handle_event(), fl_key_embedder_responder_handle_event_finish(), fl_key_embedder_responder_new(), fl_key_event_new(), invoke_record_callback(), kKeyCodeKeyA, state, 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);
1493  fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
1494  SendKeyEvent,
1495  ([&call_records](auto engine, const FlutterKeyEvent* event,
1496  FlutterKeyEventCallback callback, void* user_data) {
1497  g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
1498  event, callback, user_data));
1499  return kSuccess;
1500  }));
1501 
1502  // Test 1: synthesize key down.
1503 
1504  // A key down of control left is missed.
1505  GdkModifierType state = GDK_CONTROL_MASK;
1506 
1507  // Send a ControlLeft up
1508  g_autoptr(FlKeyEvent) event1 = fl_key_event_new(
1509  101, kRelease, kKeyCodeControlLeft, GDK_KEY_Control_L, state, 0);
1510  g_autoptr(GMainLoop) loop1 = g_main_loop_new(nullptr, 0);
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 
1541  invoke_record_callback(record, TRUE);
1542  g_main_loop_run(loop1);
1543  clear_records(call_records);
1544 
1545  // Test 2: synthesize key up.
1546 
1547  // Send a ControlLeft down.
1548  state = static_cast<GdkModifierType>(0);
1549  g_autoptr(FlKeyEvent) event2 = fl_key_event_new(
1550  102, kPress, kKeyCodeControlLeft, GDK_KEY_Control_L, state, 0);
1551  g_autoptr(GMainLoop) loop2 = g_main_loop_new(nullptr, 0);
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));
1565  invoke_record_callback(record, TRUE);
1566  g_main_loop_run(loop2);
1567  clear_records(call_records);
1568 
1569  // A key up of control left is missed.
1570  state = static_cast<GdkModifierType>(0);
1571 
1572  // Send another ControlLeft down
1573  g_autoptr(FlKeyEvent) event3 = fl_key_event_new(
1574  103, kPress, kKeyCodeControlLeft, GDK_KEY_Control_L, state, 0);
1575  g_autoptr(GMainLoop) loop3 = g_main_loop_new(nullptr, 0);
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 
1605  invoke_record_callback(record, TRUE);
1606  g_main_loop_run(loop3);
1607  clear_records(call_records);
1608 
1609  // Send a ControlLeft up to clear up state.
1610  state = GDK_CONTROL_MASK;
1611  g_autoptr(FlKeyEvent) event4 = fl_key_event_new(
1612  104, kRelease, kKeyCodeControlLeft, GDK_KEY_Control_L, state, 0);
1613  g_autoptr(GMainLoop) loop4 = g_main_loop_new(nullptr, 0);
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));
1627  invoke_record_callback(record, TRUE);
1628  g_main_loop_run(loop4);
1629  clear_records(call_records);
1630 
1631  // Test 3: synthesize by right modifier.
1632 
1633  // A key down of control right is missed.
1634  state = GDK_CONTROL_MASK;
1635 
1636  // Send a ControlRight up.
1637  g_autoptr(FlKeyEvent) event5 = fl_key_event_new(
1638  105, kRelease, kKeyCodeControlRight, GDK_KEY_Control_R, state, 0);
1639  g_autoptr(GMainLoop) loop5 = g_main_loop_new(nullptr, 0);
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 
1665  invoke_record_callback(record, TRUE);
1666  g_main_loop_run(loop5);
1667 }

References clear_records(), fl_dart_project_new(), fl_engine_get_embedder_api(), fl_engine_new(), fl_engine_start(), fl_key_embedder_call_record_new(), fl_key_embedder_responder_handle_event(), fl_key_embedder_responder_handle_event_finish(), fl_key_embedder_responder_new(), fl_key_event_new(), invoke_record_callback(), state, 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);
850  fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
851  SendKeyEvent,
852  ([&call_records](auto engine, const FlutterKeyEvent* event,
853  FlutterKeyEventCallback callback, void* user_data) {
854  g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
855  event, callback, user_data));
856  return kSuccess;
857  }));
858 
859  // Press CapsLock (stage 0 -> 1)
860  g_autoptr(FlKeyEvent) event1 =
861  fl_key_event_new(101, kPress, kKeyCodeCapsLock, GDK_KEY_Caps_Lock,
862  static_cast<GdkModifierType>(0), 0);
863  g_autoptr(GMainLoop) loop1 = g_main_loop_new(nullptr, 0);
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 
885  invoke_record_callback(record, TRUE);
886  g_main_loop_run(loop1);
887  clear_records(call_records);
888 
889  // Press key A (stage 1)
890  g_autoptr(FlKeyEvent) event2 =
891  fl_key_event_new(102, kPress, kKeyCodeKeyA, GDK_KEY_A, GDK_LOCK_MASK, 0);
892  g_autoptr(GMainLoop) loop2 = g_main_loop_new(nullptr, 0);
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 
913  invoke_record_callback(record, TRUE);
914  g_main_loop_run(loop2);
915  clear_records(call_records);
916 
917  // Release CapsLock (stage 1 -> 2)
918  g_autoptr(FlKeyEvent) event3 = fl_key_event_new(
919  103, kRelease, kKeyCodeCapsLock, GDK_KEY_Caps_Lock, GDK_LOCK_MASK, 0);
920  g_autoptr(GMainLoop) loop3 = g_main_loop_new(nullptr, 0);
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 
941  invoke_record_callback(record, TRUE);
942  g_main_loop_run(loop3);
943  clear_records(call_records);
944 
945  // Release key A (stage 2)
946  g_autoptr(FlKeyEvent) event4 = fl_key_event_new(104, kRelease, kKeyCodeKeyA,
947  GDK_KEY_A, GDK_LOCK_MASK, 0);
948  g_autoptr(GMainLoop) loop4 = g_main_loop_new(nullptr, 0);
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 
969  invoke_record_callback(record, TRUE);
970  g_main_loop_run(loop4);
971  clear_records(call_records);
972 
973  // Press CapsLock (stage 2 -> 3)
974  g_autoptr(FlKeyEvent) event5 = fl_key_event_new(
975  105, kPress, kKeyCodeCapsLock, GDK_KEY_Caps_Lock, GDK_LOCK_MASK, 0);
976  g_autoptr(GMainLoop) loop5 = g_main_loop_new(nullptr, 0);
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 
997  invoke_record_callback(record, TRUE);
998  g_main_loop_run(loop5);
999  clear_records(call_records);
1000 
1001  // Press key A (stage 3)
1002  g_autoptr(FlKeyEvent) event6 =
1003  fl_key_event_new(106, kPress, kKeyCodeKeyA, GDK_KEY_A, GDK_LOCK_MASK, 0);
1004  g_autoptr(GMainLoop) loop6 = g_main_loop_new(nullptr, 0);
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 
1025  invoke_record_callback(record, TRUE);
1026  g_main_loop_run(loop6);
1027  clear_records(call_records);
1028 
1029  // Release CapsLock (stage 3 -> 0)
1030  g_autoptr(FlKeyEvent) event7 = fl_key_event_new(
1031  107, kRelease, kKeyCodeCapsLock, GDK_KEY_Caps_Lock, GDK_LOCK_MASK, 0);
1032  g_autoptr(GMainLoop) loop7 = g_main_loop_new(nullptr, 0);
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 
1053  invoke_record_callback(record, TRUE);
1054  g_main_loop_run(loop7);
1055  clear_records(call_records);
1056 
1057  // Release key A (stage 0)
1058  g_autoptr(FlKeyEvent) event8 =
1059  fl_key_event_new(108, kRelease, kKeyCodeKeyA, GDK_KEY_a,
1060  static_cast<GdkModifierType>(0), 0);
1061  g_autoptr(GMainLoop) loop8 = g_main_loop_new(nullptr, 0);
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 
1082  invoke_record_callback(record, TRUE);
1083  g_main_loop_run(loop8);
1084 }

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

◆ TEST() [14/17]

TEST ( FlKeyEmbedderResponderTest  ,
TapLetterKeysBetweenCapsLockEventsReversed   
)

Definition at line 1090 of file fl_key_embedder_responder_test.cc.

1090  {
1091  g_autoptr(FlDartProject) project = fl_dart_project_new();
1092  g_autoptr(FlEngine) engine = fl_engine_new(project);
1093  EXPECT_TRUE(fl_engine_start(engine, nullptr));
1094 
1095  g_autoptr(FlKeyEmbedderResponder) responder =
1097 
1098  g_autoptr(GPtrArray) call_records =
1099  g_ptr_array_new_with_free_func(g_object_unref);
1100  fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
1101  SendKeyEvent,
1102  ([&call_records](auto engine, const FlutterKeyEvent* event,
1103  FlutterKeyEventCallback callback, void* user_data) {
1104  g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
1105  event, callback, user_data));
1106  return kSuccess;
1107  }));
1108 
1109  // Press key A (stage 0)
1110  g_autoptr(FlKeyEvent) event1 = fl_key_event_new(
1111  101, kPress, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0);
1112  g_autoptr(GMainLoop) loop1 = g_main_loop_new(nullptr, 0);
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 
1134  invoke_record_callback(record, TRUE);
1135  g_main_loop_run(loop1);
1136  clear_records(call_records);
1137 
1138  // Press CapsLock (stage 0 -> 1)
1139  g_autoptr(FlKeyEvent) event2 = fl_key_event_new(
1140  102, kPress, kKeyCodeCapsLock, GDK_KEY_Caps_Lock, GDK_LOCK_MASK, 0);
1141  g_autoptr(GMainLoop) loop2 = g_main_loop_new(nullptr, 0);
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 
1162  invoke_record_callback(record, TRUE);
1163  g_main_loop_run(loop2);
1164  clear_records(call_records);
1165 
1166  // Release CapsLock (stage 1 -> 2)
1167  g_autoptr(FlKeyEvent) event3 = fl_key_event_new(
1168  103, kRelease, kKeyCodeCapsLock, GDK_KEY_Caps_Lock, GDK_LOCK_MASK, 0);
1169  g_autoptr(GMainLoop) loop3 = g_main_loop_new(nullptr, 0);
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 
1190  invoke_record_callback(record, TRUE);
1191  g_main_loop_run(loop3);
1192  clear_records(call_records);
1193 
1194  // Release key A (stage 2)
1195  g_autoptr(FlKeyEvent) event4 = fl_key_event_new(104, kRelease, kKeyCodeKeyA,
1196  GDK_KEY_A, GDK_LOCK_MASK, 0);
1197  g_autoptr(GMainLoop) loop4 = g_main_loop_new(nullptr, 0);
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 
1218  invoke_record_callback(record, TRUE);
1219  g_main_loop_run(loop4);
1220  clear_records(call_records);
1221 
1222  // Press key A (stage 2)
1223  g_autoptr(FlKeyEvent) event5 =
1224  fl_key_event_new(105, kPress, kKeyCodeKeyA, GDK_KEY_A, GDK_LOCK_MASK, 0);
1225  g_autoptr(GMainLoop) loop5 = g_main_loop_new(nullptr, 0);
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 
1246  invoke_record_callback(record, TRUE);
1247  g_main_loop_run(loop5);
1248  clear_records(call_records);
1249 
1250  // Press CapsLock (stage 2 -> 3)
1251  g_autoptr(FlKeyEvent) event6 =
1252  fl_key_event_new(106, kPress, kKeyCodeCapsLock, GDK_KEY_Caps_Lock,
1253  static_cast<GdkModifierType>(0), 0);
1254  g_autoptr(GMainLoop) loop6 = g_main_loop_new(nullptr, 0);
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 
1275  invoke_record_callback(record, TRUE);
1276  g_main_loop_run(loop6);
1277  clear_records(call_records);
1278 
1279  // Release CapsLock (stage 3 -> 0)
1280  g_autoptr(FlKeyEvent) event7 = fl_key_event_new(
1281  107, kRelease, kKeyCodeCapsLock, GDK_KEY_Caps_Lock, GDK_LOCK_MASK, 0);
1282  g_autoptr(GMainLoop) loop7 = g_main_loop_new(nullptr, 0);
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 
1303  invoke_record_callback(record, TRUE);
1304  g_main_loop_run(loop7);
1305  clear_records(call_records);
1306 
1307  // Release key A (stage 0)
1308  g_autoptr(FlKeyEvent) event8 =
1309  fl_key_event_new(108, kRelease, kKeyCodeKeyA, GDK_KEY_a,
1310  static_cast<GdkModifierType>(0), 0);
1311  g_autoptr(GMainLoop) loop8 = g_main_loop_new(nullptr, 0);
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 
1332  invoke_record_callback(record, TRUE);
1333  g_main_loop_run(loop8);
1334 }

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

◆ TEST() [15/17]

TEST ( FlKeyEmbedderResponderTest  ,
TapNumPadKeysBetweenNumLockEvents   
)

Definition at line 448 of file fl_key_embedder_responder_test.cc.

448  {
449  g_autoptr(FlDartProject) project = fl_dart_project_new();
450  g_autoptr(FlEngine) engine = fl_engine_new(project);
451  EXPECT_TRUE(fl_engine_start(engine, nullptr));
452 
453  g_autoptr(FlKeyEmbedderResponder) responder =
455 
456  g_autoptr(GPtrArray) call_records =
457  g_ptr_array_new_with_free_func(g_object_unref);
458  fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
459  SendKeyEvent,
460  ([&call_records](auto engine, const FlutterKeyEvent* event,
461  FlutterKeyEventCallback callback, void* user_data) {
462  g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
463  event, callback, user_data));
464  return kSuccess;
465  }));
466 
467  // Press Numpad 1 (stage 0)
468  g_autoptr(FlKeyEvent) event1 =
469  fl_key_event_new(101, kPress, kKeyCodeNumpad1, GDK_KEY_KP_End,
470  static_cast<GdkModifierType>(0), 0);
471  g_autoptr(GMainLoop) loop1 = g_main_loop_new(nullptr, 0);
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 
493  invoke_record_callback(record, TRUE);
494  g_main_loop_run(loop1);
495  clear_records(call_records);
496 
497  // Press NumLock (stage 0 -> 1)
498  g_autoptr(FlKeyEvent) event2 =
499  fl_key_event_new(102, kPress, kKeyCodeNumLock, GDK_KEY_Num_Lock,
500  static_cast<GdkModifierType>(0), 0);
501  g_autoptr(GMainLoop) loop2 = g_main_loop_new(nullptr, 0);
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 
522  invoke_record_callback(record, TRUE);
523  g_main_loop_run(loop2);
524  clear_records(call_records);
525 
526  // Release numpad 1 (stage 1)
527  g_autoptr(FlKeyEvent) event3 = fl_key_event_new(
528  104, kRelease, kKeyCodeNumpad1, GDK_KEY_KP_1, GDK_MOD2_MASK, 0);
529  g_autoptr(GMainLoop) loop3 = g_main_loop_new(nullptr, 0);
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 
550  invoke_record_callback(record, TRUE);
551  g_main_loop_run(loop3);
552  clear_records(call_records);
553 
554  // Release NumLock (stage 1 -> 2)
555  g_autoptr(FlKeyEvent) event4 = fl_key_event_new(
556  103, kRelease, kKeyCodeNumLock, GDK_KEY_Num_Lock, GDK_MOD2_MASK, 0);
557  g_autoptr(GMainLoop) loop4 = g_main_loop_new(nullptr, 0);
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 
578  invoke_record_callback(record, TRUE);
579  g_main_loop_run(loop4);
580  clear_records(call_records);
581 
582  // Press Numpad 1 (stage 2)
583  g_autoptr(FlKeyEvent) event5 = fl_key_event_new(
584  101, kPress, kKeyCodeNumpad1, GDK_KEY_KP_End, GDK_MOD2_MASK, 0);
585  g_autoptr(GMainLoop) loop5 = g_main_loop_new(nullptr, 0);
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 
606  invoke_record_callback(record, TRUE);
607  g_main_loop_run(loop5);
608  clear_records(call_records);
609 
610  // Press NumLock (stage 2 -> 3)
611  g_autoptr(FlKeyEvent) event6 = fl_key_event_new(
612  102, kPress, kKeyCodeNumLock, GDK_KEY_Num_Lock, GDK_MOD2_MASK, 0);
613  g_autoptr(GMainLoop) loop6 = g_main_loop_new(nullptr, 0);
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 
634  invoke_record_callback(record, TRUE);
635  g_main_loop_run(loop6);
636  clear_records(call_records);
637 
638  // Release numpad 1 (stage 3)
639  g_autoptr(FlKeyEvent) event7 = fl_key_event_new(
640  104, kRelease, kKeyCodeNumpad1, GDK_KEY_KP_1, GDK_MOD2_MASK, 0);
641  g_autoptr(GMainLoop) loop7 = g_main_loop_new(nullptr, 0);
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 
662  invoke_record_callback(record, TRUE);
663  g_main_loop_run(loop7);
664  clear_records(call_records);
665 
666  // Release NumLock (stage 3 -> 0)
667  g_autoptr(FlKeyEvent) event8 = fl_key_event_new(
668  103, kRelease, kKeyCodeNumLock, GDK_KEY_Num_Lock, GDK_MOD2_MASK, 0);
669  g_autoptr(GMainLoop) loop8 = g_main_loop_new(nullptr, 0);
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 
690  invoke_record_callback(record, TRUE);
691  g_main_loop_run(loop8);
692 }

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

◆ TEST() [16/17]

TEST ( FlKeyEmbedderResponderTest  ,
TurnDuplicateDownEventsToRepeats   
)

Definition at line 1336 of file fl_key_embedder_responder_test.cc.

1336  {
1337  g_autoptr(FlDartProject) project = fl_dart_project_new();
1338  g_autoptr(FlEngine) engine = fl_engine_new(project);
1339  EXPECT_TRUE(fl_engine_start(engine, nullptr));
1340 
1341  g_autoptr(FlKeyEmbedderResponder) responder =
1343 
1344  g_autoptr(GPtrArray) call_records =
1345  g_ptr_array_new_with_free_func(g_object_unref);
1346  fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
1347  SendKeyEvent,
1348  ([&call_records](auto engine, const FlutterKeyEvent* event,
1349  FlutterKeyEventCallback callback, void* user_data) {
1350  g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
1351  event, callback, user_data));
1352  return kSuccess;
1353  }));
1354 
1355  // Press KeyA
1356  g_autoptr(FlKeyEvent) event1 = fl_key_event_new(
1357  101, kPress, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0);
1358  g_autoptr(GMainLoop) loop1 = g_main_loop_new(nullptr, 0);
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));
1375  invoke_record_callback(record, TRUE);
1376  g_main_loop_run(loop1);
1377  clear_records(call_records);
1378 
1379  // Another KeyA down events, which usually means a repeated event.
1380  g_autoptr(FlKeyEvent) event2 = fl_key_event_new(
1381  102, kPress, kKeyCodeKeyA, GDK_KEY_a, static_cast<GdkModifierType>(0), 0);
1382  g_autoptr(GMainLoop) loop2 = g_main_loop_new(nullptr, 0);
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 
1405  invoke_record_callback(record, TRUE);
1406  g_main_loop_run(loop2);
1407  clear_records(call_records);
1408 
1409  // Release KeyA
1410  g_autoptr(FlKeyEvent) event3 =
1411  fl_key_event_new(103, kRelease, kKeyCodeKeyA, GDK_KEY_q,
1412  static_cast<GdkModifierType>(0), 0);
1413  g_autoptr(GMainLoop) loop3 = g_main_loop_new(nullptr, 0);
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));
1428  invoke_record_callback(record, TRUE);
1429  g_main_loop_run(loop3);
1430 }

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

◆ TEST() [17/17]

TEST ( FlKeyEmbedderResponderTest  ,
UsesSpecifiedLogicalKey   
)

Definition at line 253 of file fl_key_embedder_responder_test.cc.

253  {
254  g_autoptr(FlDartProject) project = fl_dart_project_new();
255  g_autoptr(FlEngine) engine = fl_engine_new(project);
256  EXPECT_TRUE(fl_engine_start(engine, nullptr));
257 
258  g_autoptr(FlKeyEmbedderResponder) responder =
260 
261  g_autoptr(GPtrArray) call_records =
262  g_ptr_array_new_with_free_func(g_object_unref);
263  fl_engine_get_embedder_api(engine)->SendKeyEvent = MOCK_ENGINE_PROC(
264  SendKeyEvent,
265  ([&call_records](auto engine, const FlutterKeyEvent* event,
266  FlutterKeyEventCallback callback, void* user_data) {
267  g_ptr_array_add(call_records, fl_key_embedder_call_record_new(
268  event, callback, user_data));
269  return kSuccess;
270  }));
271 
272  // On an AZERTY keyboard, press physical key 1, and release.
273  // Key down
274  g_autoptr(FlKeyEvent) event =
275  fl_key_event_new(12345, kPress, kKeyCodeDigit1, GDK_KEY_ampersand,
276  static_cast<GdkModifierType>(0), 0);
277  g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, 0);
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 
301  invoke_record_callback(record, TRUE);
302  g_main_loop_run(loop);
303 }

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

fl_engine_get_embedder_api
FlutterEngineProcTable * fl_engine_get_embedder_api(FlEngine *self)
Definition: fl_engine.cc:721
fl_key_embedder_responder_handle_event
void fl_key_embedder_responder_handle_event(FlKeyEmbedderResponder *self, FlKeyEvent *event, uint64_t specified_logical_key, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
Definition: fl_key_embedder_responder.cc:737
fl_dart_project_new
G_MODULE_EXPORT FlDartProject * fl_dart_project_new()
Definition: fl_dart_project.cc:50
state
AtkStateType state
Definition: fl_accessible_node.cc:10
fl_key_embedder_responder_new
FlKeyEmbedderResponder * fl_key_embedder_responder_new(FlEngine *engine)
Definition: fl_key_embedder_responder.cc:181
invoke_record_callback
static void invoke_record_callback(FlKeyEmbedderCallRecord *record, bool expected_handled)
Definition: fl_key_embedder_responder_test.cc:99
user_data
G_BEGIN_DECLS G_MODULE_EXPORT FlValue gpointer user_data
Definition: fl_event_channel.h:90
TRUE
return TRUE
Definition: fl_pixel_buffer_texture_test.cc:53
fl_key_embedder_call_record_dispose
static void fl_key_embedder_call_record_dispose(GObject *object)
Definition: fl_key_embedder_responder_test.cc:58
clear_records
static void clear_records(GPtrArray *array)
Definition: fl_key_embedder_responder_test.cc:33
fl_key_embedder_call_record_new
static FlKeyEmbedderCallRecord * fl_key_embedder_call_record_new(const FlutterKeyEvent *event, FlutterKeyEventCallback callback, gpointer user_data)
Definition: fl_key_embedder_responder_test.cc:75
fl_engine_new
G_MODULE_EXPORT FlEngine * fl_engine_new(FlDartProject *project)
Definition: fl_engine.cc:580
send_key_event
static void send_key_event(FlTextInputHandler *handler, gint keyval, gint state=0)
Definition: fl_text_input_handler_test.cc:143
fl_engine_start
gboolean fl_engine_start(FlEngine *self, GError **error)
Definition: fl_engine.cc:607
fl_key_embedder_responder_handle_event_finish
gboolean fl_key_embedder_responder_handle_event_finish(FlKeyEmbedderResponder *self, GAsyncResult *result, gboolean *handled, GError **error)
Definition: fl_key_embedder_responder.cc:757
kKeyCodeKeyA
constexpr guint16 kKeyCodeKeyA
Definition: fl_keyboard_handler_test.cc:24
fl_key_event_new
FlKeyEvent * fl_key_event_new(guint32 time, gboolean is_press, guint16 keycode, guint keyval, GdkModifierType state, guint8 group)
Definition: fl_key_event.cc:34