Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Macros
fl_keyboard_manager_test.cc File Reference
#include "flutter/shell/platform/linux/fl_keyboard_manager.h"
#include <cstring>
#include <vector>
#include "flutter/shell/platform/embedder/test_utils/key_codes.g.h"
#include "flutter/shell/platform/linux/fl_binary_messenger_private.h"
#include "flutter/shell/platform/linux/fl_method_codec_private.h"
#include "flutter/shell/platform/linux/key_mapping.h"
#include "flutter/shell/platform/linux/public/flutter_linux/fl_json_message_codec.h"
#include "flutter/shell/platform/linux/public/flutter_linux/fl_method_codec.h"
#include "flutter/shell/platform/linux/public/flutter_linux/fl_standard_method_codec.h"
#include "flutter/shell/platform/linux/testing/fl_test.h"
#include "flutter/shell/platform/linux/testing/mock_binary_messenger.h"
#include "flutter/shell/platform/linux/testing/mock_text_input_plugin.h"
#include "flutter/testing/testing.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"

Go to the source code of this file.

Macros

#define EXPECT_KEY_EVENT(RECORD, TYPE, PHYSICAL, LOGICAL, CHAR, SYNTHESIZED)
 
#define VERIFY_DOWN(OUT_LOGICAL, OUT_CHAR)
 
#define FL_MOCK_KEY_BINARY_MESSENGER_GET_PRIVATE(obj)
 
#define FL_MOCK_VIEW_DELEGATE_GET_PRIVATE(obj)
 

Macro Definition Documentation

◆ EXPECT_KEY_EVENT

#define EXPECT_KEY_EVENT (   RECORD,
  TYPE,
  PHYSICAL,
  LOGICAL,
  CHAR,
  SYNTHESIZED 
)
Value:
EXPECT_EQ((RECORD).type, CallRecord::kKeyCallEmbedder); \
EXPECT_EQ((RECORD).event->type, (TYPE)); \
EXPECT_EQ((RECORD).event->physical, (PHYSICAL)); \
EXPECT_EQ((RECORD).event->logical, (LOGICAL)); \
EXPECT_STREQ((RECORD).event->character, (CHAR)); \
EXPECT_EQ((RECORD).event->synthesized, (SYNTHESIZED));
#define RECORD(T, tags,...)
Definition SkRecords.h:170
#define TYPE(t)
FlKeyEvent * event
char CHAR

Definition at line 28 of file fl_keyboard_manager_test.cc.

43 {
44using ::flutter::testing::keycodes::kLogicalAltLeft;
45using ::flutter::testing::keycodes::kLogicalBracketLeft;
46using ::flutter::testing::keycodes::kLogicalComma;
47using ::flutter::testing::keycodes::kLogicalControlLeft;
48using ::flutter::testing::keycodes::kLogicalDigit1;
49using ::flutter::testing::keycodes::kLogicalKeyA;
50using ::flutter::testing::keycodes::kLogicalKeyB;
51using ::flutter::testing::keycodes::kLogicalKeyM;
52using ::flutter::testing::keycodes::kLogicalKeyQ;
53using ::flutter::testing::keycodes::kLogicalMetaLeft;
54using ::flutter::testing::keycodes::kLogicalMinus;
55using ::flutter::testing::keycodes::kLogicalParenthesisRight;
56using ::flutter::testing::keycodes::kLogicalSemicolon;
57using ::flutter::testing::keycodes::kLogicalShiftLeft;
58using ::flutter::testing::keycodes::kLogicalUnderscore;
59
60using ::flutter::testing::keycodes::kPhysicalAltLeft;
61using ::flutter::testing::keycodes::kPhysicalControlLeft;
62using ::flutter::testing::keycodes::kPhysicalKeyA;
63using ::flutter::testing::keycodes::kPhysicalKeyB;
64using ::flutter::testing::keycodes::kPhysicalMetaLeft;
65using ::flutter::testing::keycodes::kPhysicalShiftLeft;
66
67// Hardware key codes.
68typedef std::function<void(bool handled)> AsyncKeyCallback;
69typedef std::function<void(AsyncKeyCallback callback)> ChannelCallHandler;
70typedef std::function<void(const FlutterKeyEvent* event,
71 AsyncKeyCallback callback)>
72 EmbedderCallHandler;
73typedef std::function<void(std::unique_ptr<FlKeyEvent>)> RedispatchHandler;
74
75// A type that can record all kinds of effects that the keyboard manager
76// triggers.
77//
78// An instance of `CallRecord` might not have all the fields filled.
79typedef struct {
80 enum {
81 kKeyCallEmbedder,
82 kKeyCallChannel,
83 } type;
84
85 AsyncKeyCallback callback;
86 std::unique_ptr<FlutterKeyEvent> event;
87 std::unique_ptr<char[]> event_character;
88} CallRecord;
89
90// Clone a C-string.
91//
92// Must be deleted by delete[].
93char* cloneString(const char* source) {
94 if (source == nullptr) {
95 return nullptr;
96 }
97 size_t charLen = strlen(source);
98 char* target = new char[charLen + 1];
99 strncpy(target, source, charLen + 1);
100 return target;
101}
102
103constexpr guint16 kKeyCodeKeyA = 0x26u;
104constexpr guint16 kKeyCodeKeyB = 0x38u;
105constexpr guint16 kKeyCodeKeyM = 0x3au;
106constexpr guint16 kKeyCodeDigit1 = 0x0au;
107constexpr guint16 kKeyCodeMinus = 0x14u;
108constexpr guint16 kKeyCodeSemicolon = 0x2fu;
109constexpr guint16 kKeyCodeKeyLeftBracket = 0x22u;
110
111static constexpr char kKeyEventChannelName[] = "flutter/keyevent";
112static constexpr char kKeyboardChannelName[] = "flutter/keyboard";
113static constexpr char kGetKeyboardStateMethod[] = "getKeyboardState";
114static constexpr uint64_t kMockPhysicalKey = 42;
115static constexpr uint64_t kMockLogicalKey = 42;
116
117// All key clues for a keyboard layout.
118//
119// The index is (keyCode * 2 + hasShift), where each value is the character for
120// this key (GTK only supports UTF-16.) Since the maximum keycode of interest
121// is 128, it has a total of 256 entries..
122typedef std::array<uint32_t, 256> MockGroupLayoutData;
123typedef std::vector<const MockGroupLayoutData*> MockLayoutData;
124
125extern const MockLayoutData kLayoutUs;
126extern const MockLayoutData kLayoutRussian;
127extern const MockLayoutData kLayoutFrench;
128
129G_BEGIN_DECLS
130
131G_DECLARE_FINAL_TYPE(FlMockViewDelegate,
132 fl_mock_view_delegate,
133 FL,
134 MOCK_VIEW_DELEGATE,
135 GObject);
136
137G_DECLARE_FINAL_TYPE(FlMockKeyBinaryMessenger,
138 fl_mock_key_binary_messenger,
139 FL,
140 MOCK_KEY_BINARY_MESSENGER,
141 GObject)
142
143G_END_DECLS
144
145MATCHER_P(MethodSuccessResponse, result, "") {
146 g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
147 g_autoptr(FlMethodResponse) response =
148 fl_method_codec_decode_response(FL_METHOD_CODEC(codec), arg, nullptr);
149 fl_method_response_get_result(response, nullptr);
150 if (fl_value_equal(fl_method_response_get_result(response, nullptr),
151 result)) {
152 return true;
153 }
154 *result_listener << ::testing::PrintToString(response);
155 return false;
156}
157
158/***** FlMockKeyBinaryMessenger *****/
159/* Mock a binary messenger that only processes messages from the embedding on
160 * the key event channel, and does so according to the callback set by
161 * fl_mock_key_binary_messenger_set_callback_handler */
162
163struct _FlMockKeyBinaryMessenger {
164 GObject parent_instance;
165};
166
167struct FlMockKeyBinaryMessengerPrivate {
168 ChannelCallHandler callback_handler;
169};
170
171static void fl_mock_key_binary_messenger_iface_init(
172 FlBinaryMessengerInterface* iface);
173
175 FlMockKeyBinaryMessenger,
176 fl_mock_key_binary_messenger,
177 G_TYPE_OBJECT,
178 G_IMPLEMENT_INTERFACE(fl_binary_messenger_get_type(),
179 fl_mock_key_binary_messenger_iface_init);
180 G_ADD_PRIVATE(FlMockKeyBinaryMessenger))
181
183 static_cast<FlMockKeyBinaryMessengerPrivate*>( \
184 fl_mock_key_binary_messenger_get_instance_private( \
185 FL_MOCK_KEY_BINARY_MESSENGER(obj)))
186
187static void fl_mock_key_binary_messenger_init(FlMockKeyBinaryMessenger* self) {
188 FlMockKeyBinaryMessengerPrivate* priv =
190 new (priv) FlMockKeyBinaryMessengerPrivate();
191}
192
193static void fl_mock_key_binary_messenger_finalize(GObject* object) {
195 ->~FlMockKeyBinaryMessengerPrivate();
196}
197
198static void fl_mock_key_binary_messenger_class_init(
199 FlMockKeyBinaryMessengerClass* klass) {
200 G_OBJECT_CLASS(klass)->finalize = fl_mock_key_binary_messenger_finalize;
201}
202
203static void fl_mock_key_binary_messenger_send_on_channel(
204 FlBinaryMessenger* messenger,
205 const gchar* channel,
206 GBytes* message,
207 GCancellable* cancellable,
208 GAsyncReadyCallback callback,
209 gpointer user_data) {
210 FlMockKeyBinaryMessenger* self = FL_MOCK_KEY_BINARY_MESSENGER(messenger);
211
212 if (callback != nullptr) {
213 EXPECT_STREQ(channel, kKeyEventChannelName);
214 FL_MOCK_KEY_BINARY_MESSENGER_GET_PRIVATE(self)->callback_handler(
215 [self, cancellable, callback, user_data](bool handled) {
216 g_autoptr(GTask) task =
217 g_task_new(self, cancellable, callback, user_data);
218 g_autoptr(FlValue) result = fl_value_new_map();
220 fl_value_new_bool(handled));
221 g_autoptr(FlJsonMessageCodec) codec = fl_json_message_codec_new();
222 g_autoptr(GError) error = nullptr;
224 FL_MESSAGE_CODEC(codec), result, &error);
225
226 g_task_return_pointer(
227 task, data, reinterpret_cast<GDestroyNotify>(g_bytes_unref));
228 });
229 }
230}
231
232static GBytes* fl_mock_key_binary_messenger_send_on_channel_finish(
233 FlBinaryMessenger* messenger,
234 GAsyncResult* result,
235 GError** error) {
236 return static_cast<GBytes*>(g_task_propagate_pointer(G_TASK(result), error));
237}
238
240 FlBinaryMessenger* messenger,
241 const gchar* channel,
242 int64_t new_size) {
243 // Mock implementation. Do nothing.
244}
245
247 FlBinaryMessenger* messenger,
248 const gchar* channel,
249 bool warns) {
250 // Mock implementation. Do nothing.
251}
252
253static void fl_mock_key_binary_messenger_iface_init(
254 FlBinaryMessengerInterface* iface) {
255 iface->set_message_handler_on_channel =
256 [](FlBinaryMessenger* messenger, const gchar* channel,
258 GDestroyNotify destroy_notify) {
259 EXPECT_STREQ(channel, kKeyEventChannelName);
260 // No need to mock. The key event channel expects no incoming messages
261 // from the framework.
262 };
263 iface->send_response = [](FlBinaryMessenger* messenger,
264 FlBinaryMessengerResponseHandle* response_handle,
265 GBytes* response, GError** error) -> gboolean {
266 // The key event channel expects no incoming messages from the framework,
267 // hence no responses either.
268 g_return_val_if_reached(TRUE);
269 return TRUE;
270 };
271 iface->send_on_channel = fl_mock_key_binary_messenger_send_on_channel;
272 iface->send_on_channel_finish =
273 fl_mock_key_binary_messenger_send_on_channel_finish;
274 iface->resize_channel = fl_mock_binary_messenger_resize_channel;
275 iface->set_warns_on_channel_overflow =
277}
278
279static FlMockKeyBinaryMessenger* fl_mock_key_binary_messenger_new() {
280 FlMockKeyBinaryMessenger* self = FL_MOCK_KEY_BINARY_MESSENGER(
281 g_object_new(fl_mock_key_binary_messenger_get_type(), NULL));
282
283 // Added to stop compiler complaining about an unused function.
284 FL_IS_MOCK_KEY_BINARY_MESSENGER(self);
285
286 return self;
287}
288
289static void fl_mock_key_binary_messenger_set_callback_handler(
290 FlMockKeyBinaryMessenger* self,
291 ChannelCallHandler handler) {
292 FL_MOCK_KEY_BINARY_MESSENGER_GET_PRIVATE(self)->callback_handler =
293 std::move(handler);
294}
295
296/***** FlMockViewDelegate *****/
297
298struct _FlMockViewDelegate {
299 GObject parent_instance;
300};
301
302struct FlMockViewDelegatePrivate {
303 FlMockKeyBinaryMessenger* messenger;
304 EmbedderCallHandler embedder_handler;
305 bool text_filter_result;
306 RedispatchHandler redispatch_handler;
307 KeyboardLayoutNotifier layout_notifier;
308 const MockLayoutData* layout_data;
309};
310
311static void fl_mock_view_keyboard_delegate_iface_init(
312 FlKeyboardViewDelegateInterface* iface);
313
315 FlMockViewDelegate,
316 fl_mock_view_delegate,
317 G_TYPE_OBJECT,
318 G_IMPLEMENT_INTERFACE(fl_keyboard_view_delegate_get_type(),
319 fl_mock_view_keyboard_delegate_iface_init);
320 G_ADD_PRIVATE(FlMockViewDelegate))
321
323 static_cast<FlMockViewDelegatePrivate*>( \
324 fl_mock_view_delegate_get_instance_private(FL_MOCK_VIEW_DELEGATE(obj)))
325
326static void fl_mock_view_delegate_init(FlMockViewDelegate* self) {
327 FlMockViewDelegatePrivate* priv = FL_MOCK_VIEW_DELEGATE_GET_PRIVATE(self);
328 new (priv) FlMockViewDelegatePrivate();
329}
330
331static void fl_mock_view_delegate_finalize(GObject* object) {
332 FL_MOCK_VIEW_DELEGATE_GET_PRIVATE(object)->~FlMockViewDelegatePrivate();
333}
334
335static void fl_mock_view_delegate_dispose(GObject* object) {
336 FlMockViewDelegatePrivate* priv = FL_MOCK_VIEW_DELEGATE_GET_PRIVATE(object);
337
338 g_clear_object(&priv->messenger);
339
340 G_OBJECT_CLASS(fl_mock_view_delegate_parent_class)->dispose(object);
341}
342
343static void fl_mock_view_delegate_class_init(FlMockViewDelegateClass* klass) {
344 G_OBJECT_CLASS(klass)->dispose = fl_mock_view_delegate_dispose;
345 G_OBJECT_CLASS(klass)->finalize = fl_mock_view_delegate_finalize;
346}
347
348static void fl_mock_view_keyboard_send_key_event(
349 FlKeyboardViewDelegate* view_delegate,
350 const FlutterKeyEvent* event,
352 void* user_data) {
353 FlMockViewDelegatePrivate* priv =
355 priv->embedder_handler(event, [callback, user_data](bool handled) {
356 if (callback != nullptr) {
357 callback(handled, user_data);
358 }
359 });
360}
361
362static gboolean fl_mock_view_keyboard_text_filter_key_press(
363 FlKeyboardViewDelegate* view_delegate,
364 FlKeyEvent* event) {
365 FlMockViewDelegatePrivate* priv =
367 return priv->text_filter_result;
368}
369
370static FlBinaryMessenger* fl_mock_view_keyboard_get_messenger(
371 FlKeyboardViewDelegate* view_delegate) {
372 FlMockViewDelegatePrivate* priv =
374 return FL_BINARY_MESSENGER(priv->messenger);
375}
376
377static void fl_mock_view_keyboard_redispatch_event(
378 FlKeyboardViewDelegate* view_delegate,
379 std::unique_ptr<FlKeyEvent> event) {
380 FlMockViewDelegatePrivate* priv =
382 if (priv->redispatch_handler) {
383 priv->redispatch_handler(std::move(event));
384 }
385}
386
387static void fl_mock_view_keyboard_subscribe_to_layout_change(
388 FlKeyboardViewDelegate* delegate,
389 KeyboardLayoutNotifier notifier) {
390 FlMockViewDelegatePrivate* priv = FL_MOCK_VIEW_DELEGATE_GET_PRIVATE(delegate);
391 priv->layout_notifier = std::move(notifier);
392}
393
394static guint fl_mock_view_keyboard_lookup_key(FlKeyboardViewDelegate* delegate,
395 const GdkKeymapKey* key) {
396 FlMockViewDelegatePrivate* priv = FL_MOCK_VIEW_DELEGATE_GET_PRIVATE(delegate);
397 guint8 group = static_cast<guint8>(key->group);
398 EXPECT_LT(group, priv->layout_data->size());
399 const MockGroupLayoutData* group_layout = (*priv->layout_data)[group];
400 EXPECT_TRUE(group_layout != nullptr);
401 EXPECT_TRUE(key->level == 0 || key->level == 1);
402 bool shift = key->level == 1;
403 return (*group_layout)[key->keycode * 2 + shift];
404}
405
406static GHashTable* fl_mock_view_keyboard_get_keyboard_state(
407 FlKeyboardViewDelegate* view_delegate) {
408 GHashTable* result = g_hash_table_new(g_direct_hash, g_direct_equal);
409 g_hash_table_insert(result, reinterpret_cast<gpointer>(kMockPhysicalKey),
410 reinterpret_cast<gpointer>(kMockLogicalKey));
411
412 return result;
413}
414
415static void fl_mock_view_keyboard_delegate_iface_init(
416 FlKeyboardViewDelegateInterface* iface) {
417 iface->send_key_event = fl_mock_view_keyboard_send_key_event;
418 iface->text_filter_key_press = fl_mock_view_keyboard_text_filter_key_press;
419 iface->get_messenger = fl_mock_view_keyboard_get_messenger;
420 iface->redispatch_event = fl_mock_view_keyboard_redispatch_event;
421 iface->subscribe_to_layout_change =
422 fl_mock_view_keyboard_subscribe_to_layout_change;
423 iface->lookup_key = fl_mock_view_keyboard_lookup_key;
424 iface->get_keyboard_state = fl_mock_view_keyboard_get_keyboard_state;
425}
426
427static FlMockViewDelegate* fl_mock_view_delegate_new() {
428 FlMockViewDelegate* self = FL_MOCK_VIEW_DELEGATE(
429 g_object_new(fl_mock_view_delegate_get_type(), nullptr));
430
431 // Added to stop compiler complaining about an unused function.
432 FL_IS_MOCK_VIEW_DELEGATE(self);
433
434 FlMockViewDelegatePrivate* priv = FL_MOCK_VIEW_DELEGATE_GET_PRIVATE(self);
435 priv->messenger = fl_mock_key_binary_messenger_new();
436
437 return self;
438}
439
440static void fl_mock_view_set_embedder_handler(FlMockViewDelegate* self,
441 EmbedderCallHandler handler) {
442 FlMockViewDelegatePrivate* priv = FL_MOCK_VIEW_DELEGATE_GET_PRIVATE(self);
443 priv->embedder_handler = std::move(handler);
444}
445
446static void fl_mock_view_set_text_filter_result(FlMockViewDelegate* self,
447 bool result) {
448 FlMockViewDelegatePrivate* priv = FL_MOCK_VIEW_DELEGATE_GET_PRIVATE(self);
449 priv->text_filter_result = result;
450}
451
452static void fl_mock_view_set_redispatch_handler(FlMockViewDelegate* self,
453 RedispatchHandler handler) {
454 FlMockViewDelegatePrivate* priv = FL_MOCK_VIEW_DELEGATE_GET_PRIVATE(self);
455 priv->redispatch_handler = std::move(handler);
456}
457
458static void fl_mock_view_set_layout(FlMockViewDelegate* self,
459 const MockLayoutData* layout) {
460 FlMockViewDelegatePrivate* priv = FL_MOCK_VIEW_DELEGATE_GET_PRIVATE(self);
461 priv->layout_data = layout;
462 if (priv->layout_notifier != nullptr) {
463 priv->layout_notifier();
464 }
465}
466
467/***** End FlMockViewDelegate *****/
468
469// Create a new #FlKeyEvent with the given information.
470static FlKeyEvent* fl_key_event_new_by_mock(bool is_press,
471 guint keyval,
472 guint16 keycode,
473 GdkModifierType state,
474 gboolean is_modifier,
475 guint8 group = 0) {
476 FlKeyEvent* event = g_new0(FlKeyEvent, 1);
477 event->is_press = is_press;
478 event->time = 0;
479 event->state = state;
480 event->keyval = keyval;
481 event->group = group;
482 event->keycode = keycode;
483 return event;
484}
485
486class KeyboardTester {
487 public:
489 ::testing::NiceMock<flutter::testing::MockBinaryMessenger> messenger;
490
491 view_ = fl_mock_view_delegate_new();
492 respondToEmbedderCallsWith(false);
493 respondToChannelCallsWith(false);
494 respondToTextInputWith(false);
495 setLayout(kLayoutUs);
496
497 manager_ =
498 fl_keyboard_manager_new(messenger, FL_KEYBOARD_VIEW_DELEGATE(view_));
499 }
500
502 g_clear_object(&view_);
503 g_clear_object(&manager_);
504 }
505
506 FlKeyboardManager* manager() { return manager_; }
507
508 // Block until all GdkMainLoop messages are processed, which is basically
509 // used only for channel messages.
510 void flushChannelMessages() {
511 GMainLoop* loop = g_main_loop_new(nullptr, 0);
512 g_idle_add(_flushChannelMessagesCb, loop);
513 g_main_loop_run(loop);
514 }
515
516 // Dispatch each of the given events, expect their results to be false
517 // (unhandled), and clear the event array.
518 //
519 // Returns the number of events redispatched. If any result is unexpected
520 // (handled), return a minus number `-x` instead, where `x` is the index of
521 // the first unexpected redispatch.
522 int redispatchEventsAndClear(
523 std::vector<std::unique_ptr<FlKeyEvent>>& events) {
524 size_t event_count = events.size();
525 int first_error = -1;
526 during_redispatch_ = true;
527 for (size_t event_id = 0; event_id < event_count; event_id += 1) {
529 manager_, events[event_id].release());
530 EXPECT_FALSE(handled);
531 if (handled) {
532 first_error = first_error == -1 ? event_id : first_error;
533 }
534 }
535 during_redispatch_ = false;
536 events.clear();
537 return first_error < 0 ? event_count : -first_error;
538 }
539
540 void respondToEmbedderCallsWith(bool response) {
541 fl_mock_view_set_embedder_handler(
542 view_, [response, this](const FlutterKeyEvent* event,
543 const AsyncKeyCallback& callback) {
544 EXPECT_FALSE(during_redispatch_);
545 callback(response);
546 });
547 }
548
549 void recordEmbedderCallsTo(std::vector<CallRecord>& storage) {
550 fl_mock_view_set_embedder_handler(
551 view_, [&storage, this](const FlutterKeyEvent* event,
552 AsyncKeyCallback callback) {
553 EXPECT_FALSE(during_redispatch_);
554 auto new_event = std::make_unique<FlutterKeyEvent>(*event);
555 char* new_event_character = cloneString(event->character);
556 new_event->character = new_event_character;
557 storage.push_back(CallRecord{
558 .type = CallRecord::kKeyCallEmbedder,
559 .callback = std::move(callback),
560 .event = std::move(new_event),
561 .event_character = std::unique_ptr<char[]>(new_event_character),
562 });
563 });
564 }
565
566 void respondToEmbedderCallsWithAndRecordsTo(
567 bool response,
568 std::vector<CallRecord>& storage) {
569 fl_mock_view_set_embedder_handler(
570 view_, [&storage, response, this](const FlutterKeyEvent* event,
571 const AsyncKeyCallback& callback) {
572 EXPECT_FALSE(during_redispatch_);
573 auto new_event = std::make_unique<FlutterKeyEvent>(*event);
574 char* new_event_character = cloneString(event->character);
575 new_event->character = new_event_character;
576 storage.push_back(CallRecord{
577 .type = CallRecord::kKeyCallEmbedder,
578 .event = std::move(new_event),
579 .event_character = std::unique_ptr<char[]>(new_event_character),
580 });
581 callback(response);
582 });
583 }
584
585 void respondToChannelCallsWith(bool response) {
586 FlMockViewDelegatePrivate* priv = FL_MOCK_VIEW_DELEGATE_GET_PRIVATE(view_);
587
588 fl_mock_key_binary_messenger_set_callback_handler(
589 priv->messenger, [response, this](const AsyncKeyCallback& callback) {
590 EXPECT_FALSE(during_redispatch_);
591 callback(response);
592 });
593 }
594
595 void recordChannelCallsTo(std::vector<CallRecord>& storage) {
596 FlMockViewDelegatePrivate* priv = FL_MOCK_VIEW_DELEGATE_GET_PRIVATE(view_);
597
598 fl_mock_key_binary_messenger_set_callback_handler(
599 priv->messenger, [&storage, this](AsyncKeyCallback callback) {
600 EXPECT_FALSE(during_redispatch_);
601 storage.push_back(CallRecord{
602 .type = CallRecord::kKeyCallChannel,
603 .callback = std::move(callback),
604 });
605 });
606 }
607
608 void respondToTextInputWith(bool response) {
609 fl_mock_view_set_text_filter_result(view_, response);
610 }
611
612 void recordRedispatchedEventsTo(
613 std::vector<std::unique_ptr<FlKeyEvent>>& storage) {
614 fl_mock_view_set_redispatch_handler(
615 view_, [&storage](std::unique_ptr<FlKeyEvent> key) {
616 storage.push_back(std::move(key));
617 });
618 }
619
620 void setLayout(const MockLayoutData& layout) {
621 fl_mock_view_set_layout(view_, &layout);
622 }
623
624 private:
625 FlMockViewDelegate* view_;
626 FlKeyboardManager* manager_;
627 bool during_redispatch_ = false;
628
629 static gboolean _flushChannelMessagesCb(gpointer data) {
630 g_autoptr(GMainLoop) loop = reinterpret_cast<GMainLoop*>(data);
631 g_main_loop_quit(loop);
632 return FALSE;
633 }
634};
635
636// Make sure that the keyboard can be disposed without crashes when there are
637// unresolved pending events.
638TEST(FlKeyboardManagerTest, DisposeWithUnresolvedPends) {
640 std::vector<CallRecord> call_records;
641
642 // Record calls so that they aren't responded.
643 tester.recordEmbedderCallsTo(call_records);
645 tester.manager(),
646 fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA,
647 static_cast<GdkModifierType>(0), false));
648
649 tester.respondToEmbedderCallsWith(true);
651 tester.manager(),
652 fl_key_event_new_by_mock(false, GDK_KEY_a, kKeyCodeKeyA,
653 static_cast<GdkModifierType>(0), false));
654
655 tester.flushChannelMessages();
656
657 // Passes if the cleanup does not crash.
658}
659
660TEST(FlKeyboardManagerTest, SingleDelegateWithAsyncResponds) {
662 std::vector<CallRecord> call_records;
663 std::vector<std::unique_ptr<FlKeyEvent>> redispatched;
664
665 gboolean manager_handled = false;
666
667 /// Test 1: One event that is handled by the framework
668 tester.recordEmbedderCallsTo(call_records);
669 tester.recordRedispatchedEventsTo(redispatched);
670
671 // Dispatch a key event
672 manager_handled = fl_keyboard_manager_handle_event(
673 tester.manager(),
674 fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA,
675 static_cast<GdkModifierType>(0), false));
676 tester.flushChannelMessages();
677 EXPECT_EQ(manager_handled, true);
678 EXPECT_EQ(redispatched.size(), 0u);
679 EXPECT_EQ(call_records.size(), 1u);
680 EXPECT_KEY_EVENT(call_records[0], kFlutterKeyEventTypeDown, kPhysicalKeyA,
681 kLogicalKeyA, "a", false);
682
683 call_records[0].callback(true);
684 tester.flushChannelMessages();
685 EXPECT_EQ(redispatched.size(), 0u);
687 call_records.clear();
688
689 /// Test 2: Two events that are unhandled by the framework
690 manager_handled = fl_keyboard_manager_handle_event(
691 tester.manager(),
692 fl_key_event_new_by_mock(false, GDK_KEY_a, kKeyCodeKeyA,
693 static_cast<GdkModifierType>(0), false));
694 tester.flushChannelMessages();
695 EXPECT_EQ(manager_handled, true);
696 EXPECT_EQ(redispatched.size(), 0u);
697 EXPECT_EQ(call_records.size(), 1u);
698 EXPECT_KEY_EVENT(call_records[0], kFlutterKeyEventTypeUp, kPhysicalKeyA,
699 kLogicalKeyA, nullptr, false);
700
701 // Dispatch another key event
702 manager_handled = fl_keyboard_manager_handle_event(
703 tester.manager(),
704 fl_key_event_new_by_mock(true, GDK_KEY_b, kKeyCodeKeyB,
705 static_cast<GdkModifierType>(0), false));
706 tester.flushChannelMessages();
707 EXPECT_EQ(manager_handled, true);
708 EXPECT_EQ(redispatched.size(), 0u);
709 EXPECT_EQ(call_records.size(), 2u);
710 EXPECT_KEY_EVENT(call_records[1], kFlutterKeyEventTypeDown, kPhysicalKeyB,
711 kLogicalKeyB, "b", false);
712
713 // Resolve the second event first to test out-of-order response
714 call_records[1].callback(false);
715 EXPECT_EQ(redispatched.size(), 1u);
716 EXPECT_EQ(redispatched[0]->keyval, 0x62u);
717 call_records[0].callback(false);
718 tester.flushChannelMessages();
719 EXPECT_EQ(redispatched.size(), 2u);
720 EXPECT_EQ(redispatched[1]->keyval, 0x61u);
721
722 EXPECT_FALSE(fl_keyboard_manager_is_state_clear(tester.manager()));
723 call_records.clear();
724
725 // Resolve redispatches
726 EXPECT_EQ(tester.redispatchEventsAndClear(redispatched), 2);
727 tester.flushChannelMessages();
728 EXPECT_EQ(call_records.size(), 0u);
730
731 /// Test 3: Dispatch the same event again to ensure that prevention from
732 /// redispatching only works once.
733 manager_handled = fl_keyboard_manager_handle_event(
734 tester.manager(),
735 fl_key_event_new_by_mock(false, GDK_KEY_a, kKeyCodeKeyA,
736 static_cast<GdkModifierType>(0), false));
737 tester.flushChannelMessages();
738 EXPECT_EQ(manager_handled, true);
739 EXPECT_EQ(redispatched.size(), 0u);
740 EXPECT_EQ(call_records.size(), 1u);
741
742 call_records[0].callback(true);
744}
745
746TEST(FlKeyboardManagerTest, SingleDelegateWithSyncResponds) {
748 gboolean manager_handled = false;
749 std::vector<CallRecord> call_records;
750 std::vector<std::unique_ptr<FlKeyEvent>> redispatched;
751
752 /// Test 1: One event that is handled by the framework
753 tester.respondToEmbedderCallsWithAndRecordsTo(true, call_records);
754 tester.recordRedispatchedEventsTo(redispatched);
755
756 // Dispatch a key event
757 manager_handled = fl_keyboard_manager_handle_event(
758 tester.manager(),
759 fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA,
760 static_cast<GdkModifierType>(0), false));
761 tester.flushChannelMessages();
762 EXPECT_EQ(manager_handled, true);
763 EXPECT_EQ(call_records.size(), 1u);
764 EXPECT_KEY_EVENT(call_records[0], kFlutterKeyEventTypeDown, kPhysicalKeyA,
765 kLogicalKeyA, "a", false);
766 EXPECT_EQ(redispatched.size(), 0u);
767 call_records.clear();
768
770 redispatched.clear();
771
772 /// Test 2: An event unhandled by the framework
773 tester.respondToEmbedderCallsWithAndRecordsTo(false, call_records);
774 manager_handled = fl_keyboard_manager_handle_event(
775 tester.manager(),
776 fl_key_event_new_by_mock(false, GDK_KEY_a, kKeyCodeKeyA,
777 static_cast<GdkModifierType>(0), false));
778 tester.flushChannelMessages();
779 EXPECT_EQ(manager_handled, true);
780 EXPECT_EQ(call_records.size(), 1u);
781 EXPECT_KEY_EVENT(call_records[0], kFlutterKeyEventTypeUp, kPhysicalKeyA,
782 kLogicalKeyA, nullptr, false);
783 EXPECT_EQ(redispatched.size(), 1u);
784 call_records.clear();
785
786 EXPECT_FALSE(fl_keyboard_manager_is_state_clear(tester.manager()));
787
788 EXPECT_EQ(tester.redispatchEventsAndClear(redispatched), 1);
789 EXPECT_EQ(call_records.size(), 0u);
790
792}
793
794TEST(FlKeyboardManagerTest, WithTwoAsyncDelegates) {
796 std::vector<CallRecord> call_records;
797 std::vector<std::unique_ptr<FlKeyEvent>> redispatched;
798
799 gboolean manager_handled = false;
800
801 tester.recordEmbedderCallsTo(call_records);
802 tester.recordChannelCallsTo(call_records);
803 tester.recordRedispatchedEventsTo(redispatched);
804
805 /// Test 1: One delegate responds true, the other false
806
807 manager_handled = fl_keyboard_manager_handle_event(
808 tester.manager(),
809 fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA,
810 static_cast<GdkModifierType>(0), false));
811
812 EXPECT_EQ(manager_handled, true);
813 EXPECT_EQ(redispatched.size(), 0u);
814 EXPECT_EQ(call_records.size(), 2u);
815
816 EXPECT_EQ(call_records[0].type, CallRecord::kKeyCallEmbedder);
817 EXPECT_EQ(call_records[1].type, CallRecord::kKeyCallChannel);
818
819 call_records[0].callback(true);
820 call_records[1].callback(false);
821 tester.flushChannelMessages();
822 EXPECT_EQ(redispatched.size(), 0u);
823
825 call_records.clear();
826
827 /// Test 2: All delegates respond false
828 manager_handled = fl_keyboard_manager_handle_event(
829 tester.manager(),
830 fl_key_event_new_by_mock(false, GDK_KEY_a, kKeyCodeKeyA,
831 static_cast<GdkModifierType>(0), false));
832
833 EXPECT_EQ(manager_handled, true);
834 EXPECT_EQ(redispatched.size(), 0u);
835 EXPECT_EQ(call_records.size(), 2u);
836
837 EXPECT_EQ(call_records[0].type, CallRecord::kKeyCallEmbedder);
838 EXPECT_EQ(call_records[1].type, CallRecord::kKeyCallChannel);
839
840 call_records[0].callback(false);
841 call_records[1].callback(false);
842
843 call_records.clear();
844
845 // Resolve redispatch
846 tester.flushChannelMessages();
847 EXPECT_EQ(redispatched.size(), 1u);
848 EXPECT_EQ(tester.redispatchEventsAndClear(redispatched), 1);
849 EXPECT_EQ(call_records.size(), 0u);
850
852}
853
854TEST(FlKeyboardManagerTest, TextInputPluginReturnsFalse) {
856 std::vector<std::unique_ptr<FlKeyEvent>> redispatched;
857 gboolean manager_handled = false;
858 tester.recordRedispatchedEventsTo(redispatched);
859 tester.respondToTextInputWith(false);
860
861 // Dispatch a key event.
862 manager_handled = fl_keyboard_manager_handle_event(
863 tester.manager(),
864 fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA,
865 static_cast<GdkModifierType>(0), false));
866 tester.flushChannelMessages();
867 EXPECT_EQ(manager_handled, true);
868 // The event was redispatched because no one handles it.
869 EXPECT_EQ(redispatched.size(), 1u);
870
871 // Resolve redispatched event.
872 EXPECT_EQ(tester.redispatchEventsAndClear(redispatched), 1);
873
875}
876
877TEST(FlKeyboardManagerTest, TextInputPluginReturnsTrue) {
879 std::vector<std::unique_ptr<FlKeyEvent>> redispatched;
880 gboolean manager_handled = false;
881 tester.recordRedispatchedEventsTo(redispatched);
882 tester.respondToTextInputWith(true);
883
884 // Dispatch a key event.
885 manager_handled = fl_keyboard_manager_handle_event(
886 tester.manager(),
887 fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA,
888 static_cast<GdkModifierType>(0), false));
889 tester.flushChannelMessages();
890 EXPECT_EQ(manager_handled, true);
891 // The event was not redispatched because text input plugin handles it.
892 EXPECT_EQ(redispatched.size(), 0u);
893
895}
896
897TEST(FlKeyboardManagerTest, CorrectLogicalKeyForLayouts) {
899
900 std::vector<CallRecord> call_records;
901 tester.recordEmbedderCallsTo(call_records);
902
903 auto sendTap = [&](guint8 keycode, guint keyval, guint8 group) {
906 true, keyval, keycode,
907 static_cast<GdkModifierType>(0), false, group));
910 false, keyval, keycode,
911 static_cast<GdkModifierType>(0), false, group));
912 };
913
914 /* US keyboard layout */
915
916 sendTap(kKeyCodeKeyA, GDK_KEY_a, 0); // KeyA
917 VERIFY_DOWN(kLogicalKeyA, "a");
918
919 sendTap(kKeyCodeKeyA, GDK_KEY_A, 0); // Shift-KeyA
920 VERIFY_DOWN(kLogicalKeyA, "A");
921
922 sendTap(kKeyCodeDigit1, GDK_KEY_1, 0); // Digit1
923 VERIFY_DOWN(kLogicalDigit1, "1");
924
925 sendTap(kKeyCodeDigit1, GDK_KEY_exclam, 0); // Shift-Digit1
926 VERIFY_DOWN(kLogicalDigit1, "!");
927
928 sendTap(kKeyCodeMinus, GDK_KEY_minus, 0); // Minus
929 VERIFY_DOWN(kLogicalMinus, "-");
930
931 sendTap(kKeyCodeMinus, GDK_KEY_underscore, 0); // Shift-Minus
932 VERIFY_DOWN(kLogicalUnderscore, "_");
933
934 /* French keyboard layout, group 3, which is when the input method is showing
935 * "Fr" */
936
937 tester.setLayout(kLayoutFrench);
938
939 sendTap(kKeyCodeKeyA, GDK_KEY_q, 3); // KeyA
940 VERIFY_DOWN(kLogicalKeyQ, "q");
941
942 sendTap(kKeyCodeKeyA, GDK_KEY_Q, 3); // Shift-KeyA
943 VERIFY_DOWN(kLogicalKeyQ, "Q");
944
945 sendTap(kKeyCodeSemicolon, GDK_KEY_m, 3); // ; but prints M
946 VERIFY_DOWN(kLogicalKeyM, "m");
947
948 sendTap(kKeyCodeKeyM, GDK_KEY_comma, 3); // M but prints ,
949 VERIFY_DOWN(kLogicalComma, ",");
950
951 sendTap(kKeyCodeDigit1, GDK_KEY_ampersand, 3); // Digit1
952 VERIFY_DOWN(kLogicalDigit1, "&");
953
954 sendTap(kKeyCodeDigit1, GDK_KEY_1, 3); // Shift-Digit1
955 VERIFY_DOWN(kLogicalDigit1, "1");
956
957 sendTap(kKeyCodeMinus, GDK_KEY_parenright, 3); // Minus
958 VERIFY_DOWN(kLogicalParenthesisRight, ")");
959
960 sendTap(kKeyCodeMinus, GDK_KEY_degree, 3); // Shift-Minus
961 VERIFY_DOWN(static_cast<uint32_t>(L'°'), "°");
962
963 /* French keyboard layout, group 0, which is pressing the "extra key for
964 * triggering input method" key once after switching to French IME. */
965
966 sendTap(kKeyCodeKeyA, GDK_KEY_a, 0); // KeyA
967 VERIFY_DOWN(kLogicalKeyA, "a");
968
969 sendTap(kKeyCodeDigit1, GDK_KEY_1, 0); // Digit1
970 VERIFY_DOWN(kLogicalDigit1, "1");
971
972 /* Russian keyboard layout, group 2 */
973 tester.setLayout(kLayoutRussian);
974
975 sendTap(kKeyCodeKeyA, GDK_KEY_Cyrillic_ef, 2); // KeyA
976 VERIFY_DOWN(kLogicalKeyA, "Ñ„");
977
978 sendTap(kKeyCodeDigit1, GDK_KEY_1, 2); // Shift-Digit1
979 VERIFY_DOWN(kLogicalDigit1, "1");
980
981 sendTap(kKeyCodeKeyLeftBracket, GDK_KEY_Cyrillic_ha, 2);
982 VERIFY_DOWN(kLogicalBracketLeft, "Ñ…");
983
984 /* Russian keyboard layout, group 0 */
985 sendTap(kKeyCodeKeyA, GDK_KEY_a, 0); // KeyA
986 VERIFY_DOWN(kLogicalKeyA, "a");
987
988 sendTap(kKeyCodeKeyLeftBracket, GDK_KEY_bracketleft, 0);
989 VERIFY_DOWN(kLogicalBracketLeft, "[");
990}
991
992TEST(FlKeyboardManagerTest, SynthesizeModifiersIfNeeded) {
994 std::vector<CallRecord> call_records;
995 tester.recordEmbedderCallsTo(call_records);
996
997 auto verifyModifierIsSynthesized = [&](GdkModifierType mask,
998 uint64_t physical, uint64_t logical) {
999 // Modifier is pressed.
1000 guint state = mask;
1002 EXPECT_EQ(call_records.size(), 1u);
1003 EXPECT_KEY_EVENT(call_records[0], kFlutterKeyEventTypeDown, physical,
1004 logical, NULL, true);
1005 // Modifier is released.
1006 state = state ^ mask;
1008 EXPECT_EQ(call_records.size(), 2u);
1009 EXPECT_KEY_EVENT(call_records[1], kFlutterKeyEventTypeUp, physical, logical,
1010 NULL, true);
1011 call_records.clear();
1012 };
1013
1014 // No modifiers pressed.
1015 guint state = 0;
1017 EXPECT_EQ(call_records.size(), 0u);
1018 call_records.clear();
1019
1020 // Press and release each modifier once.
1021 verifyModifierIsSynthesized(GDK_CONTROL_MASK, kPhysicalControlLeft,
1022 kLogicalControlLeft);
1023 verifyModifierIsSynthesized(GDK_META_MASK, kPhysicalMetaLeft,
1024 kLogicalMetaLeft);
1025 verifyModifierIsSynthesized(GDK_MOD1_MASK, kPhysicalAltLeft, kLogicalAltLeft);
1026 verifyModifierIsSynthesized(GDK_SHIFT_MASK, kPhysicalShiftLeft,
1027 kLogicalShiftLeft);
1028}
1029
1030TEST(FlKeyboardManagerTest, GetPressedState) {
1032 tester.respondToTextInputWith(true);
1033
1034 // Dispatch a key event.
1036 tester.manager(),
1037 fl_key_event_new_by_mock(true, GDK_KEY_a, kKeyCodeKeyA,
1038 static_cast<GdkModifierType>(0), false));
1039
1040 GHashTable* pressedState =
1042 EXPECT_EQ(g_hash_table_size(pressedState), 1u);
1043
1044 gpointer physical_key =
1045 g_hash_table_lookup(pressedState, uint64_to_gpointer(kPhysicalKeyA));
1046 EXPECT_EQ(gpointer_to_uint64(physical_key), kLogicalKeyA);
1047}
1048
1049TEST(FlKeyboardPluginTest, KeyboardChannelGetPressedState) {
1050 ::testing::NiceMock<flutter::testing::MockBinaryMessenger> messenger;
1051
1053 messenger, FL_KEYBOARD_VIEW_DELEGATE(fl_mock_view_delegate_new()));
1054 EXPECT_NE(manager, nullptr);
1055
1056 g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
1057 g_autoptr(GBytes) message = fl_method_codec_encode_method_call(
1058 FL_METHOD_CODEC(codec), kGetKeyboardStateMethod, nullptr, nullptr);
1059
1060 g_autoptr(FlValue) response = fl_value_new_map();
1061 fl_value_set_take(response, fl_value_new_int(kMockPhysicalKey),
1062 fl_value_new_int(kMockLogicalKey));
1063 EXPECT_CALL(messenger,
1065 ::testing::Eq<FlBinaryMessenger*>(messenger), ::testing::_,
1066 MethodSuccessResponse(response), ::testing::_))
1067 .WillOnce(::testing::Return(true));
1068
1069 messenger.ReceiveMessage(kKeyboardChannelName, message);
1070}
1071
1072// The following layout data is generated using DEBUG_PRINT_LAYOUT.
1073
1074const MockGroupLayoutData kLayoutUs0{{
1075 // +0x0 Shift +0x1 Shift +0x2 Shift +0x3 Shift
1076 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, // 0x00
1077 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, // 0x04
1078 0xffff, 0x0031, 0xffff, 0x0031, 0x0031, 0x0021, 0x0032, 0x0040, // 0x08
1079 0x0033, 0x0023, 0x0034, 0x0024, 0x0035, 0x0025, 0x0036, 0x005e, // 0x0c
1080 0x0037, 0x0026, 0x0038, 0x002a, 0x0039, 0x0028, 0x0030, 0x0029, // 0x10
1081 0x002d, 0x005f, 0x003d, 0x002b, 0xffff, 0xffff, 0xffff, 0xffff, // 0x14
1082 0x0071, 0x0051, 0x0077, 0x0057, 0x0065, 0x0045, 0x0072, 0x0052, // 0x18
1083 0x0074, 0x0054, 0x0079, 0x0059, 0x0075, 0x0055, 0x0069, 0x0049, // 0x1c
1084 0x006f, 0x004f, 0x0070, 0x0050, 0x005b, 0x007b, 0x005d, 0x007d, // 0x20
1085 0xffff, 0xffff, 0xffff, 0x0061, 0x0061, 0x0041, 0x0073, 0x0053, // 0x24
1086 0x0064, 0x0044, 0x0066, 0x0046, 0x0067, 0x0047, 0x0068, 0x0048, // 0x28
1087 0x006a, 0x004a, 0x006b, 0x004b, 0x006c, 0x004c, 0x003b, 0x003a, // 0x2c
1088 0x0027, 0x0022, 0x0060, 0x007e, 0xffff, 0x005c, 0x005c, 0x007c, // 0x30
1089 0x007a, 0x005a, 0x0078, 0x0058, 0x0063, 0x0043, 0x0076, 0x0056, // 0x34
1090 0x0062, 0x0042, 0x006e, 0x004e, 0x006d, 0x004d, 0x002c, 0x003c, // 0x38
1091 0x002e, 0x003e, 0x002f, 0x003f, 0xffff, 0xffff, 0xffff, 0xffff, // 0x3c
1092 0xffff, 0xffff, 0x0020, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x40
1093 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x44
1094 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x48
1095 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x4c
1096 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x50
1097 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x54
1098 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x58
1099 0xffff, 0xffff, 0x003c, 0x003e, 0x003c, 0x003e, 0xffff, 0xffff, // 0x5c
1100 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x60
1101 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x64
1102 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x68
1103 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x6c
1104 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x70
1105 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x74
1106 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x78
1107 0xffff, 0xffff, 0xffff, 0x00b1, 0x00b1, 0xffff, 0xffff, 0xffff, // 0x7c
1108}};
1109
1110const MockGroupLayoutData kLayoutRussian0{
1111 // +0x0 Shift +0x1 Shift +0x2 Shift +0x3 Shift
1112 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, // 0x00
1113 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, // 0x04
1114 0x0000, 0xffff, 0xffff, 0x0031, 0x0031, 0x0021, 0x0032, 0x0040, // 0x08
1115 0x0033, 0x0023, 0x0034, 0x0024, 0x0035, 0x0025, 0x0036, 0x005e, // 0x0c
1116 0x0037, 0x0026, 0x0038, 0x002a, 0x0039, 0x0028, 0x0030, 0x0029, // 0x10
1117 0x002d, 0x005f, 0x003d, 0x002b, 0xffff, 0xffff, 0xffff, 0xffff, // 0x14
1118 0x0071, 0x0051, 0x0077, 0x0057, 0x0065, 0x0045, 0x0072, 0x0052, // 0x18
1119 0x0074, 0x0054, 0x0079, 0x0059, 0x0075, 0x0055, 0x0069, 0x0049, // 0x1c
1120 0x006f, 0x004f, 0x0070, 0x0050, 0x005b, 0x007b, 0x005d, 0x007d, // 0x20
1121 0xffff, 0xffff, 0xffff, 0x0061, 0x0061, 0x0041, 0x0073, 0x0053, // 0x24
1122 0x0064, 0x0044, 0x0066, 0x0046, 0x0067, 0x0047, 0x0068, 0x0048, // 0x28
1123 0x006a, 0x004a, 0x006b, 0x004b, 0x006c, 0x004c, 0x003b, 0x003a, // 0x2c
1124 0x0027, 0x0022, 0x0060, 0x007e, 0xffff, 0x005c, 0x005c, 0x007c, // 0x30
1125 0x007a, 0x005a, 0x0078, 0x0058, 0x0063, 0x0043, 0x0076, 0x0056, // 0x34
1126 0x0062, 0x0042, 0x006e, 0x004e, 0x006d, 0x004d, 0x002c, 0x003c, // 0x38
1127 0x002e, 0x003e, 0x002f, 0x003f, 0xffff, 0xffff, 0xffff, 0xffff, // 0x3c
1128 0xffff, 0xffff, 0x0020, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x40
1129 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x44
1130 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x48
1131 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x4c
1132 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x50
1133 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x54
1134 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x58
1135 0xffff, 0xffff, 0x0000, 0xffff, 0x003c, 0x003e, 0xffff, 0xffff, // 0x5c
1136 0xffff, 0xffff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x60
1137 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0xffff, // 0x64
1138 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x68
1139 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x6c
1140 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x70
1141 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x74
1142 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x78
1143 0xffff, 0xffff, 0xffff, 0x00b1, 0x00b1, 0xffff, 0xffff, 0xffff, // 0x7c
1144};
1145
1146const MockGroupLayoutData kLayoutRussian2{{
1147 // +0x0 Shift +0x1 Shift +0x2 Shift +0x3 Shift
1148 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, // 0x00
1149 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, // 0x04
1150 0xffff, 0x0031, 0x0021, 0x0000, 0x0031, 0x0021, 0x0032, 0x0022, // 0x08
1151 0x0033, 0x06b0, 0x0034, 0x003b, 0x0035, 0x0025, 0x0036, 0x003a, // 0x0c
1152 0x0037, 0x003f, 0x0038, 0x002a, 0x0039, 0x0028, 0x0030, 0x0029, // 0x10
1153 0x002d, 0x005f, 0x003d, 0x002b, 0x0071, 0x0051, 0x0000, 0x0000, // 0x14
1154 0x06ca, 0x06ea, 0x06c3, 0x06e3, 0x06d5, 0x06f5, 0x06cb, 0x06eb, // 0x18
1155 0x06c5, 0x06e5, 0x06ce, 0x06ee, 0x06c7, 0x06e7, 0x06db, 0x06fb, // 0x1c
1156 0x06dd, 0x06fd, 0x06da, 0x06fa, 0x06c8, 0x06e8, 0x06df, 0x06ff, // 0x20
1157 0x0061, 0x0041, 0x0041, 0x0000, 0x06c6, 0x06e6, 0x06d9, 0x06f9, // 0x24
1158 0x06d7, 0x06f7, 0x06c1, 0x06e1, 0x06d0, 0x06f0, 0x06d2, 0x06f2, // 0x28
1159 0x06cf, 0x06ef, 0x06cc, 0x06ec, 0x06c4, 0x06e4, 0x06d6, 0x06f6, // 0x2c
1160 0x06dc, 0x06fc, 0x06a3, 0x06b3, 0x007c, 0x0000, 0x005c, 0x002f, // 0x30
1161 0x06d1, 0x06f1, 0x06de, 0x06fe, 0x06d3, 0x06f3, 0x06cd, 0x06ed, // 0x34
1162 0x06c9, 0x06e9, 0x06d4, 0x06f4, 0x06d8, 0x06f8, 0x06c2, 0x06e2, // 0x38
1163 0x06c0, 0x06e0, 0x002e, 0x002c, 0xffff, 0xffff, 0xffff, 0xffff, // 0x3c
1164 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x40
1165 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x44
1166 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x48
1167 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x4c
1168 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x50
1169 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x54
1170 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x58
1171 0xffff, 0xffff, 0x003c, 0x003e, 0x002f, 0x007c, 0xffff, 0xffff, // 0x5c
1172 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x60
1173 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x64
1174 0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0xffff, 0xffff, 0x0000, // 0x68
1175 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x6c
1176 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x70
1177 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x74
1178 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x00b1, // 0x78
1179 0x00b1, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x7c
1180}};
1181
1182const MockGroupLayoutData kLayoutFrench0 = {
1183 // +0x0 Shift +0x1 Shift +0x2 Shift +0x3 Shift
1184 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, // 0x00
1185 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, // 0x04
1186 0x0000, 0xffff, 0xffff, 0x0031, 0x0031, 0x0021, 0x0032, 0x0040, // 0x08
1187 0x0033, 0x0023, 0x0034, 0x0024, 0x0035, 0x0025, 0x0036, 0x005e, // 0x0c
1188 0x0037, 0x0026, 0x0038, 0x002a, 0x0039, 0x0028, 0x0030, 0x0029, // 0x10
1189 0x002d, 0x005f, 0x003d, 0x002b, 0xffff, 0xffff, 0xffff, 0xffff, // 0x14
1190 0x0071, 0x0051, 0x0077, 0x0057, 0x0065, 0x0045, 0x0072, 0x0052, // 0x18
1191 0x0074, 0x0054, 0x0079, 0x0059, 0x0075, 0x0055, 0x0069, 0x0049, // 0x1c
1192 0x006f, 0x004f, 0x0070, 0x0050, 0x005b, 0x007b, 0x005d, 0x007d, // 0x20
1193 0xffff, 0xffff, 0xffff, 0x0061, 0x0061, 0x0041, 0x0073, 0x0053, // 0x24
1194 0x0064, 0x0044, 0x0066, 0x0046, 0x0067, 0x0047, 0x0068, 0x0048, // 0x28
1195 0x006a, 0x004a, 0x006b, 0x004b, 0x006c, 0x004c, 0x003b, 0x003a, // 0x2c
1196 0x0027, 0x0022, 0x0060, 0x007e, 0xffff, 0x005c, 0x005c, 0x007c, // 0x30
1197 0x007a, 0x005a, 0x0078, 0x0058, 0x0063, 0x0043, 0x0076, 0x0056, // 0x34
1198 0x0062, 0x0042, 0x006e, 0x004e, 0x006d, 0x004d, 0x002c, 0x003c, // 0x38
1199 0x002e, 0x003e, 0x002f, 0x003f, 0xffff, 0xffff, 0xffff, 0xffff, // 0x3c
1200 0xffff, 0xffff, 0x0020, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x40
1201 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x44
1202 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x48
1203 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x4c
1204 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x50
1205 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x54
1206 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x58
1207 0xffff, 0xffff, 0x0000, 0xffff, 0x003c, 0x003e, 0xffff, 0xffff, // 0x5c
1208 0xffff, 0xffff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x60
1209 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0xffff, // 0x64
1210 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x68
1211 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x6c
1212 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x70
1213 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x74
1214 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x78
1215 0xffff, 0xffff, 0xffff, 0x00b1, 0x00b1, 0xffff, 0xffff, 0xffff, // 0x7c
1216};
1217
1218const MockGroupLayoutData kLayoutFrench3 = {
1219 // +0x0 Shift +0x1 Shift +0x2 Shift +0x3 Shift
1220 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, // 0x00
1221 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, 0x0000, 0xffff, // 0x04
1222 0x0000, 0xffff, 0x0000, 0x0000, 0x0026, 0x0031, 0x00e9, 0x0032, // 0x08
1223 0x0022, 0x0033, 0x0027, 0x0034, 0x0028, 0x0035, 0x002d, 0x0036, // 0x0c
1224 0x00e8, 0x0037, 0x005f, 0x0038, 0x00e7, 0x0039, 0x00e0, 0x0030, // 0x10
1225 0x0029, 0x00b0, 0x003d, 0x002b, 0x0000, 0x0000, 0x0061, 0x0041, // 0x14
1226 0x0061, 0x0041, 0x007a, 0x005a, 0x0065, 0x0045, 0x0072, 0x0052, // 0x18
1227 0x0074, 0x0054, 0x0079, 0x0059, 0x0075, 0x0055, 0x0069, 0x0049, // 0x1c
1228 0x006f, 0x004f, 0x0070, 0x0050, 0xffff, 0xffff, 0x0024, 0x00a3, // 0x20
1229 0x0041, 0x0000, 0x0000, 0x0000, 0x0071, 0x0051, 0x0073, 0x0053, // 0x24
1230 0x0064, 0x0044, 0x0066, 0x0046, 0x0067, 0x0047, 0x0068, 0x0048, // 0x28
1231 0x006a, 0x004a, 0x006b, 0x004b, 0x006c, 0x004c, 0x006d, 0x004d, // 0x2c
1232 0x00f9, 0x0025, 0x00b2, 0x007e, 0x0000, 0x0000, 0x002a, 0x00b5, // 0x30
1233 0x0077, 0x0057, 0x0078, 0x0058, 0x0063, 0x0043, 0x0076, 0x0056, // 0x34
1234 0x0062, 0x0042, 0x006e, 0x004e, 0x002c, 0x003f, 0x003b, 0x002e, // 0x38
1235 0x003a, 0x002f, 0x0021, 0x00a7, 0xffff, 0xffff, 0xffff, 0xffff, // 0x3c
1236 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x40
1237 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x44
1238 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x48
1239 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x4c
1240 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x50
1241 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x54
1242 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x58
1243 0xffff, 0x003c, 0x0000, 0xffff, 0x003c, 0x003e, 0xffff, 0xffff, // 0x5c
1244 0xffff, 0xffff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x60
1245 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x0000, 0xffff, // 0x64
1246 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x68
1247 0xffff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x6c
1248 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x70
1249 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x74
1250 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0x00b1, 0x00b1, 0xffff, // 0x78
1251 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, // 0x7c
1252};
1253
1254const MockLayoutData kLayoutUs{&kLayoutUs0};
1255const MockLayoutData kLayoutRussian{&kLayoutRussian0, nullptr,
1256 &kLayoutRussian2};
1257const MockLayoutData kLayoutFrench{&kLayoutFrench0, nullptr, nullptr,
1258 &kLayoutFrench3};
1259
1260} // namespace
#define TEST(S, s, D, expected)
void(* FlutterKeyEventCallback)(bool, void *)
Definition embedder.h:1153
@ kFlutterKeyEventTypeDown
Definition embedder.h:1074
@ kFlutterKeyEventTypeUp
Definition embedder.h:1073
SkBitmap source
Definition examples.cpp:28
G_DEFINE_TYPE_WITH_CODE(FlAccessibleNode, fl_accessible_node, ATK_TYPE_OBJECT, G_IMPLEMENT_INTERFACE(ATK_TYPE_COMPONENT, fl_accessible_node_component_interface_init) G_IMPLEMENT_INTERFACE(ATK_TYPE_ACTION, fl_accessible_node_action_interface_init)) static gboolean flag_is_changed(FlutterSemanticsFlag old_flags
AtkStateType state
G_BEGIN_DECLS G_DECLARE_FINAL_TYPE(FlAccessibleTextField, fl_accessible_text_field, FL, ACCESSIBLE_TEXT_FIELD, FlAccessibleNode)
G_MODULE_EXPORT gboolean fl_binary_messenger_send_response(FlBinaryMessenger *self, FlBinaryMessengerResponseHandle *response_handle, GBytes *response, GError **error)
G_MODULE_EXPORT GObject typedef void(* FlBinaryMessengerMessageHandler)(FlBinaryMessenger *messenger, const gchar *channel, GBytes *message, FlBinaryMessengerResponseHandle *response_handle, gpointer user_data)
G_MODULE_EXPORT FlJsonMessageCodec * fl_json_message_codec_new()
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
static FlKeyEvent * fl_key_event_new_by_mock(guint32 time_in_milliseconds, bool is_press, guint keyval, guint16 keycode, GdkModifierType state, gboolean is_modifier)
typedefG_BEGIN_DECLS struct _FlKeyboardManager FlKeyboardManager
gboolean fl_keyboard_manager_is_state_clear(FlKeyboardManager *self)
gboolean fl_keyboard_manager_handle_event(FlKeyboardManager *self, FlKeyEvent *event)
GHashTable * fl_keyboard_manager_get_pressed_state(FlKeyboardManager *self)
static constexpr char kGetKeyboardStateMethod[]
FlKeyboardManager * fl_keyboard_manager_new(FlBinaryMessenger *messenger, FlKeyboardViewDelegate *view_delegate)
void fl_keyboard_manager_sync_modifier_if_needed(FlKeyboardManager *self, guint state, double event_time)
#define EXPECT_KEY_EVENT(RECORD, TYPE, PHYSICAL, LOGICAL, CHAR, SYNTHESIZED)
#define FL_MOCK_KEY_BINARY_MESSENGER_GET_PRIVATE(obj)
#define FL_MOCK_VIEW_DELEGATE_GET_PRIVATE(obj)
#define VERIFY_DOWN(OUT_LOGICAL, OUT_CHAR)
std::function< void()> KeyboardLayoutNotifier
G_MODULE_EXPORT GBytes * fl_message_codec_encode_message(FlMessageCodec *self, FlValue *message, GError **error)
FlMethodResponse * fl_method_codec_decode_response(FlMethodCodec *self, GBytes *message, GError **error)
GBytes * fl_method_codec_encode_method_call(FlMethodCodec *self, const gchar *name, FlValue *args, GError **error)
G_MODULE_EXPORT FlValue * fl_method_response_get_result(FlMethodResponse *self, GError **error)
FlPixelBufferTexturePrivate * priv
const uint8_t uint32_t uint32_t GError ** error
MATCHER_P(SuccessResponse, result, "")
G_MODULE_EXPORT FlStandardMethodCodec * fl_standard_method_codec_new()
GAsyncResult * result
uint32_t * target
G_MODULE_EXPORT FlValue * fl_value_new_map()
Definition fl_value.cc:366
G_MODULE_EXPORT void fl_value_set_string_take(FlValue *self, const gchar *key, FlValue *value)
Definition fl_value.cc:650
G_MODULE_EXPORT FlValue * fl_value_new_bool(bool value)
Definition fl_value.cc:255
G_MODULE_EXPORT void fl_value_set_take(FlValue *self, FlValue *key, FlValue *value)
Definition fl_value.cc:618
G_MODULE_EXPORT FlValue * fl_value_new_int(int64_t value)
Definition fl_value.cc:262
G_MODULE_EXPORT bool fl_value_equal(FlValue *a, FlValue *b)
Definition fl_value.cc:471
typedefG_BEGIN_DECLS struct _FlValue FlValue
Definition fl_value.h:42
FlutterKeyboardManager * manager
gpointer uint64_to_gpointer(uint64_t number)
Definition key_mapping.h:17
uint64_t gpointer_to_uint64(gpointer pointer)
Definition key_mapping.h:13
CallbackHandler callback_handler
Win32Message message
static void fl_mock_binary_messenger_resize_channel(FlBinaryMessenger *messenger, const gchar *channel, int64_t new_size)
static void fl_mock_binary_messenger_set_warns_on_channel_overflow(FlBinaryMessenger *messenger, const gchar *channel, bool warns)
return FALSE
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font manager
Definition switches.h:218
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition switches.h:41
#define EXPECT_TRUE(handle)
Definition unit_test.h:685

◆ FL_MOCK_KEY_BINARY_MESSENGER_GET_PRIVATE

#define FL_MOCK_KEY_BINARY_MESSENGER_GET_PRIVATE (   obj)
Value:
static_cast<FlMockKeyBinaryMessengerPrivate*>( \
fl_mock_key_binary_messenger_get_instance_private( \
FL_MOCK_KEY_BINARY_MESSENGER(obj)))

◆ FL_MOCK_VIEW_DELEGATE_GET_PRIVATE

#define FL_MOCK_VIEW_DELEGATE_GET_PRIVATE (   obj)
Value:
static_cast<FlMockViewDelegatePrivate*>( \
fl_mock_view_delegate_get_instance_private(FL_MOCK_VIEW_DELEGATE(obj)))

◆ VERIFY_DOWN

#define VERIFY_DOWN (   OUT_LOGICAL,
  OUT_CHAR 
)
Value:
EXPECT_EQ(call_records[0].type, CallRecord::kKeyCallEmbedder); \
EXPECT_EQ(call_records[0].event->type, kFlutterKeyEventTypeDown); \
EXPECT_EQ(call_records[0].event->logical, (OUT_LOGICAL)); \
EXPECT_STREQ(call_records[0].event->character, (OUT_CHAR)); \
EXPECT_EQ(call_records[0].event->synthesized, false); \
call_records.clear()

Definition at line 36 of file fl_keyboard_manager_test.cc.