43 {
44
45
46
47
48
49constexpr size_t kLayoutSize = 128;
50
51
52
53typedef std::array<uint64_t, kLayoutSize> DerivedGroupLayout;
54
55
56
57typedef std::map<guint8, DerivedGroupLayout> DerivedLayout;
58
59
60typedef struct {
64} DispatchToResponderLoopContext;
65
68}
69
70#ifdef DEBUG_PRINT_LAYOUT
71
72void debug_format_layout_data(std::string& debug_layout_data,
73 uint16_t keycode,
74 uint16_t clue1,
75 uint16_t clue2) {
76 if (keycode % 4 == 0) {
77 debug_layout_data.append(" ");
78 }
79
84
86 debug_layout_data.append(
buffer);
87
88 if (keycode % 4 == 3) {
90 debug_layout_data.append(
buffer);
91 }
92}
93#endif
94
95}
96
98 const DerivedLayout& layout) {
99 guint8
group =
event->group;
100 guint16 keycode = event->keycode;
101 if (keycode >= kLayoutSize) {
102 return 0;
103 }
104
105 auto found_group_layout = layout.find(group);
106 if (found_group_layout != layout.end()) {
107 return found_group_layout->second[keycode];
108 }
109 return 0;
110}
111
112
113
114
115
116
117
118
119
120
121
122
125
126
127
128
129 std::unique_ptr<FlKeyEvent>
event;
130
131
132
133
135
137
139
140
141
143};
144
145G_DEFINE_TYPE(FlKeyboardPendingEvent, fl_keyboard_pending_event, G_TYPE_OBJECT)
146
148
149
150 g_return_if_fail(FL_IS_KEYBOARD_PENDING_EVENT(object));
151
152 FlKeyboardPendingEvent* self = FL_KEYBOARD_PENDING_EVENT(object);
153 if (
self->event !=
nullptr) {
155 }
156 G_OBJECT_CLASS(fl_keyboard_pending_event_parent_class)->dispose(object);
157}
158
160 FlKeyboardPendingEventClass* klass) {
162}
163
165
166
167
169
170
171
172
174 static_cast<uint64_t>(event->is_press ? GDK_KEY_PRESS : GDK_KEY_RELEASE);
175 guint64 keycode = static_cast<uint64_t>(event->keycode);
176 return (
event->
time & 0xffffffff) | ((
type & 0xffff) << 32) |
177 ((keycode & 0xffff) << 48);
178}
179
180
181
182
183
185 std::unique_ptr<FlKeyEvent>
event,
186 uint64_t sequence_id,
187 size_t to_reply) {
188 FlKeyboardPendingEvent* self = FL_KEYBOARD_PENDING_EVENT(
189 g_object_new(fl_keyboard_pending_event_get_type(), nullptr));
190
191 self->event = std::move(
event);
192 self->sequence_id = sequence_id;
193 self->unreplied = to_reply;
194 self->any_handled = false;
196 return self;
197}
198
199
200
201
202
203
204
205
206
209
210
213};
214
216 fl_keyboard_manager_user_data,
217 G_TYPE_OBJECT)
218
219static void fl_keyboard_manager_user_data_dispose(GObject* object) {
220 g_return_if_fail(FL_IS_KEYBOARD_MANAGER_USER_DATA(object));
221 FlKeyboardManagerUserData* self = FL_KEYBOARD_MANAGER_USER_DATA(object);
222 if (
self->manager !=
nullptr) {
223 g_object_remove_weak_pointer(G_OBJECT(
self->manager),
224 reinterpret_cast<gpointer*
>(&(
self->manager)));
225 self->manager = nullptr;
226 }
227}
228
230 FlKeyboardManagerUserDataClass* klass) {
231 G_OBJECT_CLASS(klass)->dispose = fl_keyboard_manager_user_data_dispose;
232}
233
235 FlKeyboardManagerUserData* self) {}
236
237
240 uint64_t sequence_id) {
241 FlKeyboardManagerUserData* self = FL_KEYBOARD_MANAGER_USER_DATA(
242 g_object_new(fl_keyboard_manager_user_data_get_type(), nullptr));
243
245
246
248 reinterpret_cast<gpointer*
>(&(
self->manager)));
249 self->sequence_id = sequence_id;
250 return self;
251}
252
253
254
257
259
260
261
262
264
265
266
267
268
269
271
272
273
274
276
277
279
280
281
282
283
284
286
287
288
290
291
292
293 std::unique_ptr<std::map<uint64_t, const LayoutGoal*>>
295
296
298};
299
301
303
306}
307
309 self->derived_layout = std::make_unique<DerivedLayout>();
310
311 self->keycode_to_goals =
312 std::make_unique<std::map<uint16_t, const LayoutGoal*>>();
313 self->logical_to_mandatory_goals =
314 std::make_unique<std::map<uint64_t, const LayoutGoal*>>();
316 (*self->keycode_to_goals)[goal.keycode] = &goal;
317 if (goal.mandatory) {
318 (*self->logical_to_mandatory_goals)[goal.logical_key] = &goal;
319 }
320 }
321
322 self->responder_list = g_ptr_array_new_with_free_func(g_object_unref);
323
324 self->pending_responds = g_ptr_array_new();
325 self->pending_redispatches = g_ptr_array_new_with_free_func(g_object_unref);
326
327 self->last_sequence_id = 1;
328}
329
332
333 if (
self->view_delegate !=
nullptr) {
335 nullptr);
336 g_object_remove_weak_pointer(
337 G_OBJECT(
self->view_delegate),
338 reinterpret_cast<gpointer*
>(&(
self->view_delegate)));
339 self->view_delegate = nullptr;
340 }
341
342 self->derived_layout.reset();
343 self->keycode_to_goals.reset();
344 self->logical_to_mandatory_goals.reset();
345
346 g_ptr_array_free(
self->responder_list,
TRUE);
347 g_ptr_array_set_free_func(
self->pending_responds, g_object_unref);
348 g_ptr_array_free(
self->pending_responds,
TRUE);
349 g_ptr_array_free(
self->pending_redispatches,
TRUE);
350
351 G_OBJECT_CLASS(fl_keyboard_manager_parent_class)->dispose(object);
352}
353
354
355
356
357
358
360 gconstpointer needle,
361 GEqualFunc equal_func,
362 guint* index_) {
363 guint i;
364 g_return_val_if_fail(haystack != NULL,
FALSE);
365 if (equal_func == NULL) {
366 equal_func = g_direct_equal;
367 }
368 for (i = 0; i < haystack->len; i++) {
369 if (equal_func(g_ptr_array_index(haystack, i), needle)) {
370 if (index_ != NULL) {
371 *index_ = i;
372 }
374 }
375 }
376
378}
379
380
381
383 gconstpointer pending,
384 gconstpointer needle_sequence_id) {
385 uint64_t sequence_id = *reinterpret_cast<const uint64_t*>(needle_sequence_id);
386 return static_cast<const FlKeyboardPendingEvent*>(pending)->sequence_id ==
387 sequence_id;
388}
389
390
391
393 gconstpointer needle_hash) {
394 uint64_t
hash = *
reinterpret_cast<const uint64_t*
>(needle_hash);
395 return static_cast<const FlKeyboardPendingEvent*
>(pending)->
hash ==
hash;
396}
397
398
399
400
401
404 guint result_index;
406 self->pending_redispatches,
static_cast<const uint64_t*
>(&
hash),
408 if (found) {
409
410 g_ptr_array_remove_index_fast(
self->pending_redispatches, result_index);
412 } else {
414 }
415}
416
417
419 gpointer user_data_ptr) {
420 g_return_if_fail(FL_IS_KEYBOARD_MANAGER_USER_DATA(user_data_ptr));
422 FL_KEYBOARD_MANAGER_USER_DATA(user_data_ptr);
424 g_return_if_fail(
self->view_delegate !=
nullptr);
425
426 guint result_index = -1;
430 g_return_if_fail(found);
431 FlKeyboardPendingEvent* pending = FL_KEYBOARD_PENDING_EVENT(
432 g_ptr_array_index(
self->pending_responds, result_index));
433 g_return_if_fail(pending != nullptr);
434 g_return_if_fail(pending->unreplied > 0);
435 pending->unreplied -= 1;
436 pending->any_handled = pending->any_handled || handled;
437
438 if (pending->unreplied == 0) {
439 g_object_unref(user_data_ptr);
440 gpointer removed =
441 g_ptr_array_remove_index_fast(
self->pending_responds, result_index);
442 g_return_if_fail(removed == pending);
443 bool should_redispatch = !pending->any_handled &&
445 self->view_delegate, pending->event.get());
446 if (should_redispatch) {
447 g_ptr_array_add(
self->pending_redispatches, pending);
449 std::move(pending->event));
450 } else {
451 g_object_unref(pending);
452 }
453 }
454}
455
457 guint keycode,
458 gint group,
459 gint level) {
461 constexpr int kBmpMax = 0xD7FF;
463 return origin < kBmpMax ? origin : 0xFFFF;
464}
465
466
467
469 guint8
group =
event->group;
470 if (
self->derived_layout->find(group) !=
self->derived_layout->end()) {
471 return;
472 }
474 self->keycode_to_goals->end()) {
475 return;
476 }
477
478 DerivedGroupLayout& layout = (*self->derived_layout)[group];
479
480
481
482 std::map<uint64_t, const LayoutGoal*> remaining_mandatory_goals =
483 *self->logical_to_mandatory_goals;
484
485#ifdef DEBUG_PRINT_LAYOUT
486 std::string debug_layout_data;
487 for (uint16_t keycode = 0; keycode < 128; keycode += 1) {
488 std::vector<uint16_t> this_key_clues = {
491 };
492 debug_format_layout_data(debug_layout_data, keycode, this_key_clues[0],
493 this_key_clues[1]);
494 }
495#endif
496
497
498
499
500
502 uint16_t keycode = keycode_goal.keycode;
503 std::vector<uint16_t> this_key_clues = {
506 };
507
508
509
510
511
512
513
514
515 for (uint16_t clue : this_key_clues) {
516 auto matching_goal = remaining_mandatory_goals.find(clue);
517 if (matching_goal != remaining_mandatory_goals.end()) {
518
519 g_return_if_fail(layout[keycode] == 0);
520 layout[keycode] = clue;
521 remaining_mandatory_goals.erase(matching_goal);
522 break;
523 }
524 }
525 bool has_any_eascii =
526 is_eascii(this_key_clues[0]) || is_eascii(this_key_clues[1]);
527
528 if (layout[keycode] == 0 && !has_any_eascii) {
529 auto found_us_layout = self->keycode_to_goals->find(keycode);
530 if (found_us_layout !=
self->keycode_to_goals->end()) {
531 layout[keycode] = found_us_layout->second->logical_key;
532 }
533 }
534 }
535
536
537 for (const auto mandatory_goal_iter : remaining_mandatory_goals) {
538 const LayoutGoal* goal = mandatory_goal_iter.second;
540 }
541}
542
543
546
547 GHashTable* pressing_records =
549
550 g_hash_table_foreach(
551 pressing_records,
553 int64_t physical_key =
reinterpret_cast<int64_t
>(
key);
554 int64_t logical_key =
reinterpret_cast<int64_t
>(
value);
556
559 },
562}
563
564
569
571
572 g_autoptr(FlMethodResponse) response = nullptr;
575 } else {
577 }
578
579 g_autoptr(GError)
error =
nullptr;
581 g_warning(
"Failed to send method call response: %s",
error->message);
582 }
583}
584
586 FlBinaryMessenger* messenger,
587 FlKeyboardViewDelegate* view_delegate) {
588 g_return_val_if_fail(FL_IS_KEYBOARD_VIEW_DELEGATE(view_delegate), nullptr);
589
591 g_object_new(fl_keyboard_manager_get_type(), nullptr));
592
593 self->view_delegate = view_delegate;
595 G_OBJECT(view_delegate),
596 reinterpret_cast<gpointer*
>(&(
self->view_delegate)));
597
598
599 g_ptr_array_add(
600 self->responder_list,
603 void* callback_user_data, void* send_key_event_user_data) {
605 FL_KEYBOARD_MANAGER(send_key_event_user_data);
606 g_return_if_fail(
self->view_delegate !=
nullptr);
609 },
610 self)));
611 g_ptr_array_add(
self->responder_list,
614
616 self->view_delegate, [
self]() { self->derived_layout->clear(); });
617
618
620 self->channel =
623 self, nullptr);
624 return self;
625}
626
627
629 gpointer foreach_data_ptr) {
630 DispatchToResponderLoopContext* context =
631 reinterpret_cast<DispatchToResponderLoopContext*>(foreach_data_ptr);
632 FlKeyResponder* responder = FL_KEY_RESPONDER(responder_data);
635 context->user_data, context->specified_logical_key);
636}
637
640 g_return_val_if_fail(FL_IS_KEYBOARD_MANAGER(
self),
FALSE);
641 g_return_val_if_fail(
event !=
nullptr,
FALSE);
642 g_return_val_if_fail(
self->view_delegate !=
nullptr,
FALSE);
643
645
649 }
650
652 std::unique_ptr<FlKeyEvent>(
event), ++
self->last_sequence_id,
653 self->responder_list->len);
654
655 g_ptr_array_add(
self->pending_responds, pending);
658 DispatchToResponderLoopContext
data{
660 .specified_logical_key =
663 };
665
667}
668
670 g_return_val_if_fail(FL_IS_KEYBOARD_MANAGER(
self),
FALSE);
671 return self->pending_responds->len == 0 &&
672 self->pending_redispatches->len == 0;
673}
674
677 double event_time) {
678 g_return_if_fail(FL_IS_KEYBOARD_MANAGER(self));
679
680
681
682 FlKeyEmbedderResponder* responder =
683 FL_KEY_EMBEDDER_RESPONDER(g_ptr_array_index(
self->responder_list, 0));
685 event_time);
686}
687
689 g_return_val_if_fail(FL_IS_KEYBOARD_MANAGER(self), nullptr);
690
691
692
693 FlKeyEmbedderResponder* responder =
694 FL_KEY_EMBEDDER_RESPONDER(g_ptr_array_index(
self->responder_list, 0));
696}
static uint32_t hash(const SkShaderBase::GradientInfo &v)
static const size_t kBufferSize
void(* FlutterKeyEventCallback)(bool, void *)
FlKeyEvent uint64_t specified_logical_key
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
FlKeyChannelResponder * fl_key_channel_responder_new(FlBinaryMessenger *messenger, FlKeyChannelResponderMock *mock)
GHashTable * fl_key_embedder_responder_get_pressed_state(FlKeyEmbedderResponder *self)
FlKeyEmbedderResponder * fl_key_embedder_responder_new(EmbedderSendKeyEvent send_key_event, void *send_key_event_user_data)
void fl_key_embedder_responder_sync_modifiers_if_needed(FlKeyEmbedderResponder *responder, guint state, double event_time)
void fl_key_event_dispose(FlKeyEvent *event)
void fl_key_responder_handle_event(FlKeyResponder *self, FlKeyEvent *event, FlKeyResponderAsyncCallback callback, gpointer user_data, uint64_t specified_logical_key)
typedefG_BEGIN_DECLS struct _FlKeyboardManager FlKeyboardManager
gboolean fl_keyboard_manager_is_state_clear(FlKeyboardManager *self)
static void fl_keyboard_manager_class_init(FlKeyboardManagerClass *klass)
static void fl_keyboard_manager_dispose(GObject *object)
static FlKeyboardPendingEvent * fl_keyboard_pending_event_new(std::unique_ptr< FlKeyEvent > event, uint64_t sequence_id, size_t to_reply)
static void fl_keyboard_manager_user_data_init(FlKeyboardManagerUserData *self)
static uint64_t get_logical_key_from_layout(const FlKeyEvent *event, const DerivedLayout &layout)
G_DEFINE_TYPE(FlKeyboardManagerUserData, fl_keyboard_manager_user_data, G_TYPE_OBJECT) static void fl_keyboard_manager_user_data_dispose(GObject *object)
static uint64_t fl_keyboard_manager_get_event_hash(FlKeyEvent *event)
static void guarantee_layout(FlKeyboardManager *self, FlKeyEvent *event)
static FlKeyboardManagerUserData * fl_keyboard_manager_user_data_new(FlKeyboardManager *manager, uint64_t sequence_id)
gboolean fl_keyboard_manager_handle_event(FlKeyboardManager *self, FlKeyEvent *event)
GHashTable * fl_keyboard_manager_get_pressed_state(FlKeyboardManager *self)
static void fl_keyboard_manager_user_data_class_init(FlKeyboardManagerUserDataClass *klass)
static void fl_keyboard_manager_init(FlKeyboardManager *self)
static void method_call_handler(FlMethodChannel *channel, FlMethodCall *method_call, gpointer user_data)
static void dispatch_to_responder(gpointer responder_data, gpointer foreach_data_ptr)
static constexpr char kChannelName[]
FlMethodResponse * get_keyboard_state(FlKeyboardManager *self)
static void fl_keyboard_pending_event_class_init(FlKeyboardPendingEventClass *klass)
static gboolean g_ptr_array_find_with_equal_func1(GPtrArray *haystack, gconstpointer needle, GEqualFunc equal_func, guint *index_)
static void responder_handle_event_callback(bool handled, gpointer user_data_ptr)
static gboolean compare_pending_by_hash(gconstpointer pending, gconstpointer needle_hash)
static constexpr char kGetKeyboardStateMethod[]
static gboolean compare_pending_by_sequence_id(gconstpointer pending, gconstpointer needle_sequence_id)
static void fl_keyboard_pending_event_dispose(GObject *object)
FlKeyboardManager * fl_keyboard_manager_new(FlBinaryMessenger *messenger, FlKeyboardViewDelegate *view_delegate)
static bool fl_keyboard_manager_remove_redispatched(FlKeyboardManager *self, uint64_t hash)
static void fl_keyboard_pending_event_init(FlKeyboardPendingEvent *self)
void fl_keyboard_manager_sync_modifier_if_needed(FlKeyboardManager *self, guint state, double event_time)
static uint16_t convert_key_to_char(FlKeyboardViewDelegate *view_delegate, guint keycode, gint group, gint level)
GHashTable * fl_keyboard_view_delegate_get_keyboard_state(FlKeyboardViewDelegate *self)
void fl_keyboard_view_delegate_send_key_event(FlKeyboardViewDelegate *self, const FlutterKeyEvent *event, FlutterKeyEventCallback callback, void *user_data)
FlBinaryMessenger * fl_keyboard_view_delegate_get_messenger(FlKeyboardViewDelegate *self)
void fl_keyboard_view_delegate_subscribe_to_layout_change(FlKeyboardViewDelegate *self, KeyboardLayoutNotifier notifier)
guint fl_keyboard_view_delegate_lookup_key(FlKeyboardViewDelegate *self, const GdkKeymapKey *key)
gboolean fl_keyboard_view_delegate_text_filter_key_press(FlKeyboardViewDelegate *self, FlKeyEvent *event)
void fl_keyboard_view_delegate_redispatch_event(FlKeyboardViewDelegate *self, std::unique_ptr< FlKeyEvent > event)
G_MODULE_EXPORT const gchar * fl_method_call_get_name(FlMethodCall *self)
G_MODULE_EXPORT gboolean fl_method_call_respond(FlMethodCall *self, FlMethodResponse *response, GError **error)
G_MODULE_EXPORT FlMethodChannel * fl_method_channel_new(FlBinaryMessenger *messenger, const gchar *name, FlMethodCodec *codec)
G_MODULE_EXPORT void fl_method_channel_set_method_call_handler(FlMethodChannel *self, FlMethodChannelMethodCallHandler handler, gpointer user_data, GDestroyNotify destroy_notify)
G_BEGIN_DECLS G_MODULE_EXPORT FlMethodCall * method_call
G_MODULE_EXPORT FlMethodSuccessResponse * fl_method_success_response_new(FlValue *result)
G_MODULE_EXPORT FlMethodNotImplementedResponse * fl_method_not_implemented_response_new()
static const uint8_t buffer[]
const uint8_t uint32_t uint32_t GError ** error
G_MODULE_EXPORT FlStandardMethodCodec * fl_standard_method_codec_new()
G_MODULE_EXPORT FlValue * fl_value_new_map()
G_MODULE_EXPORT void fl_value_set_take(FlValue *self, FlValue *key, FlValue *value)
G_MODULE_EXPORT FlValue * fl_value_new_int(int64_t value)
typedefG_BEGIN_DECLS struct _FlValue FlValue
g_object_add_weak_pointer(G_OBJECT(self), reinterpret_cast< gpointer * >(&self->engine))
const std::vector< LayoutGoal > layout_goals
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
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
FlKeyboardManager * manager
GPtrArray * pending_responds
FlMethodChannel * channel
std::unique_ptr< DerivedLayout > derived_layout
FlKeyboardViewDelegate * view_delegate
GPtrArray * pending_redispatches
std::unique_ptr< std::map< uint64_t, const LayoutGoal * > > logical_to_mandatory_goals
std::unique_ptr< std::map< uint16_t, const LayoutGoal * > > keycode_to_goals
uint64_t last_sequence_id
GPtrArray * responder_list
std::unique_ptr< FlKeyEvent > event