221 {
223}
224
225
227 FlKeyEmbedderResponderClass* klass) {
229}
230
231
233
234
236 FlKeyEmbedderResponder* self = FL_KEY_EMBEDDER_RESPONDER(object);
237
238 g_clear_pointer(&
self->pressing_records, g_hash_table_unref);
239 g_clear_pointer(&
self->mapping_records, g_hash_table_unref);
240 g_clear_pointer(&
self->modifier_bit_to_checked_keys, g_hash_table_unref);
241 g_clear_pointer(&
self->lock_bit_to_checked_keys, g_hash_table_unref);
242 g_clear_pointer(&
self->logical_key_to_lock_bit, g_hash_table_unref);
243
244 G_OBJECT_CLASS(fl_key_embedder_responder_parent_class)->dispose(object);
245}
246
247
248
249
250
252 gpointer value,
257 g_hash_table_insert(
table,
259 GUINT_TO_POINTER(lock_bit));
260}
261
262
265 void* send_key_event_user_data) {
266 FlKeyEmbedderResponder* self = FL_KEY_EMBEDDER_RESPONDER(
268
270 self->send_key_event_user_data = send_key_event_user_data;
271
272 self->pressing_records = g_hash_table_new(g_direct_hash, g_direct_equal);
273 self->mapping_records = g_hash_table_new(g_direct_hash, g_direct_equal);
274 self->lock_records = 0;
275 self->caps_lock_state_logic_inferrence = kStateLogicUndecided;
276
277 self->modifier_bit_to_checked_keys =
278 g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free);
280
281 self->lock_bit_to_checked_keys =
282 g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free);
284
285 self->logical_key_to_lock_bit =
286 g_hash_table_new(g_direct_hash, g_direct_equal);
287 g_hash_table_foreach(
self->lock_bit_to_checked_keys,
289 self->logical_key_to_lock_bit);
290
291 return self;
292}
293
294
295
296static uint64_t
apply_id_plane(uint64_t logical_id, uint64_t plane) {
298}
299
303 return found->second;
304 }
306}
307
309 guint keyval = event->keyval;
312 return found->second;
313 }
314
315 if (keyval < 256) {
317 }
318
320}
321
324}
325
326
327
329 gunichar unicodeChar = gdk_keyval_to_unicode(
event->
keyval);
330 glong items_written;
331 gchar*
result = g_ucs4_to_utf8(&unicodeChar, 1, NULL, &items_written, NULL);
332 if (items_written == 0) {
335 }
336 return nullptr;
337 }
339}
340
341
342
344 g_autoptr(FlKeyEmbedderUserData)
data = FL_KEY_EMBEDDER_USER_DATA(
user_data);
345
346 g_return_if_fail(
data->callback !=
nullptr);
347
348 data->callback(handled,
data->user_data);
349}
350
351
354 uint64_t physical,
355 uint64_t logical,
356 double timestamp) {
365 self->sent_any_events = true;
366 self->send_key_event(&out_event, nullptr, nullptr,
367 self->send_key_event_user_data);
368}
369
370namespace {
371
372
373
374typedef struct {
375 FlKeyEmbedderResponder* self;
377 uint64_t event_logical_key;
378 bool is_down;
379 double timestamp;
380} SyncStateLoopContext;
381
382
383
384typedef struct {
385 bool known_modifier_physical_key;
386 uint64_t logical_key;
387 uint64_t physical_key_from_event;
388 uint64_t corrected_physical_key;
389} ModifierLogicalToPhysicalContext;
390
391}
392
393
394
395
396
397
399 uint64_t physical_key,
400 uint64_t logical_key) {
401 if (logical_key != 0) {
403 0);
404 g_hash_table_insert(
self->pressing_records,
407 } else {
409 0);
410 g_hash_table_remove(
self->pressing_records,
412 }
413}
414
415
416
417
418
420 uint64_t logical_key,
421 bool is_down) {
422 if (!is_down) {
423 return;
424 }
425 const guint mode_bit = GPOINTER_TO_UINT(g_hash_table_lookup(
427 if (mode_bit != 0) {
428 self->lock_records ^= mode_bit;
429 }
430}
431
433 uint64_t physical_key,
434 uint64_t logical_key) {
437}
438
439
440
441
442
444 gpointer value,
446 SyncStateLoopContext* context =
447 reinterpret_cast<SyncStateLoopContext*
>(
user_data);
450
451 const guint modifier_bit = GPOINTER_TO_INT(
key);
452 FlKeyEmbedderResponder* self = context->self;
453
454
455
456
457
458
459
460
461 const uint64_t logical_keys[] = {
464 };
466
467 const bool any_pressed_by_state = (context->state & modifier_bit) != 0;
468
469 bool any_pressed_by_record = false;
470
471
472
473
474
475
476
477
478 for (guint logical_key_idx = 0; logical_key_idx <
length; logical_key_idx++) {
479 const uint64_t logical_key = logical_keys[logical_key_idx];
480 g_return_if_fail(logical_key != 0);
481 const uint64_t pressing_physical_key =
483 const bool this_key_pressed_before_event = pressing_physical_key != 0;
484
485 any_pressed_by_record =
486 any_pressed_by_record || this_key_pressed_before_event;
487
488 if (this_key_pressed_before_event && !any_pressed_by_state) {
489 const uint64_t recorded_physical_key =
491
492
493 g_return_if_fail(recorded_physical_key != 0);
494
495 const uint64_t recorded_logical_key =
498 recorded_physical_key, recorded_logical_key,
499 context->timestamp);
501 }
502 }
503
504
505 if (any_pressed_by_state && !any_pressed_by_record) {
507 const uint64_t recorded_physical_key =
509
510
511
512
513
514 const uint64_t physical_key = recorded_physical_key != 0
515 ? recorded_physical_key
517 if (recorded_physical_key == 0) {
519 }
521 logical_key, context->timestamp);
523 }
524}
525
526
527
529 constexpr int stage_by_record_index[] = {
530 0,
531 2,
532 3,
533 1
534 };
535 return stage_by_record_index[(is_down << 1) +
is_enabled];
536}
537
538
539
541 bool is_down_event,
542 bool is_state_on,
543 bool reverse_state_logic) {
544 if (!is_state_on) {
545 return reverse_state_logic ? 2 : 0;
546 }
547 if (is_down_event) {
548 return reverse_state_logic ? 0 : 2;
549 }
550 return stage_by_record;
551}
552
553
554
556 g_return_val_if_fail(stage_by_record >= 0 && stage_by_record < 4,
557 stage_by_record);
558 if (!is_state_on) {
559 return 0;
560 }
561 if (stage_by_record == 0) {
562 return 1;
563 }
564 return stage_by_record;
565}
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
583 FlKeyEmbedderResponder* self,
584 bool is_down_event,
585 bool enabled_by_state,
586 int stage_by_record) {
587 if (
self->caps_lock_state_logic_inferrence != kStateLogicUndecided) {
588 return;
589 }
590 if (!is_down_event) {
591 return;
592 }
594 stage_by_record, is_down_event, enabled_by_state, false);
595 if ((stage_by_event == 0 && stage_by_record == 2) ||
596 (stage_by_event == 2 && stage_by_record == 0)) {
597 self->caps_lock_state_logic_inferrence = kStateLogicReversed;
598 } else {
599 self->caps_lock_state_logic_inferrence = kStateLogicNormal;
600 }
601}
602
603
604
605
606
607
608
610 gpointer value,
612 SyncStateLoopContext* context =
613 reinterpret_cast<SyncStateLoopContext*
>(
user_data);
616
617 guint modifier_bit = GPOINTER_TO_INT(
key);
618 FlKeyEmbedderResponder* self = context->self;
619
621 const uint64_t recorded_physical_key =
623
624
625
626
627
628
629
630 const uint64_t physical_key = recorded_physical_key != 0
631 ? recorded_physical_key
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653 const uint64_t pressed_logical_key =
654 recorded_physical_key == 0
655 ? 0
657
658 g_return_if_fail(pressed_logical_key == 0 ||
659 pressed_logical_key == logical_key);
661 pressed_logical_key != 0, (
self->lock_records & modifier_bit) != 0);
662
663 const bool enabled_by_state = (context->state & modifier_bit) != 0;
664 const bool this_key_is_event_key = logical_key == context->event_logical_key;
665 if (this_key_is_event_key && checked_key->
is_caps_lock) {
667 enabled_by_state, stage_by_record);
668 g_return_if_fail(
self->caps_lock_state_logic_inferrence !=
669 kStateLogicUndecided);
670 }
671 const bool reverse_state_logic =
673 self->caps_lock_state_logic_inferrence == kStateLogicReversed;
674 const int stage_by_event =
675 this_key_is_event_key
677 enabled_by_state, reverse_state_logic)
679
680
681
682 constexpr int kNumStages = 4;
683 const int destination_stage = stage_by_event >= stage_by_record
684 ? stage_by_event
685 : stage_by_event + kNumStages;
686
687 g_return_if_fail(stage_by_record <= destination_stage);
688 if (stage_by_record == destination_stage) {
689 return;
690 }
691 for (int current_stage = stage_by_record; current_stage < destination_stage;
692 current_stage += 1) {
693 if (current_stage == 9) {
694 return;
695 }
696
697 const int standard_current_stage = current_stage % kNumStages;
698 const bool is_down_event =
699 standard_current_stage == 0 || standard_current_stage == 2;
700 if (is_down_event && recorded_physical_key == 0) {
702 }
708 context->timestamp);
709 }
710}
711
712
713
714
715
717 gpointer value,
719 ModifierLogicalToPhysicalContext* context =
720 reinterpret_cast<ModifierLogicalToPhysicalContext*
>(
user_data);
723
725 context->known_modifier_physical_key = true;
726 }
727}
728
729
730
731
732
734 gpointer value,
736 ModifierLogicalToPhysicalContext* context =
737 reinterpret_cast<ModifierLogicalToPhysicalContext*
>(
user_data);
740
744 }
745}
746
748 GHashTable* modifier_bit_to_checked_keys,
749 uint64_t physical_key_from_event,
750 uint64_t logical_key) {
751 ModifierLogicalToPhysicalContext logical_to_physical_context;
752 logical_to_physical_context.known_modifier_physical_key = false;
753 logical_to_physical_context.physical_key_from_event = physical_key_from_event;
754 logical_to_physical_context.logical_key = logical_key;
755
756
757 logical_to_physical_context.corrected_physical_key = physical_key_from_event;
758
759
760 g_hash_table_foreach(modifier_bit_to_checked_keys,
762 &logical_to_physical_context);
763
764
765
766 if (logical_to_physical_context.known_modifier_physical_key) {
767 g_hash_table_foreach(modifier_bit_to_checked_keys,
769 &logical_to_physical_context);
770 }
771
772 return logical_to_physical_context.corrected_physical_key;
773}
774
776 FlKeyResponder* responder,
781 FlKeyEmbedderResponder* self = FL_KEY_EMBEDDER_RESPONDER(responder);
782
783 g_return_if_fail(
event !=
nullptr);
784 g_return_if_fail(
callback !=
nullptr);
785
791 self->modifier_bit_to_checked_keys, physical_key_from_event, logical_key);
793 const bool is_down_event = event->is_press;
794
795 SyncStateLoopContext sync_state_context;
796 sync_state_context.self = self;
797 sync_state_context.state = event->state;
798 sync_state_context.timestamp = timestamp;
799 sync_state_context.is_down = is_down_event;
800 sync_state_context.event_logical_key = logical_key;
801
802
803 g_hash_table_foreach(
self->lock_bit_to_checked_keys,
805
806
807 g_hash_table_foreach(
self->modifier_bit_to_checked_keys,
809 &sync_state_context);
810
811
812 const uint64_t last_logical_record =
814
820 last_logical_record != 0 ? last_logical_record : logical_key;
823
824 g_autofree char* character_to_free = nullptr;
825 if (is_down_event) {
826 if (last_logical_record) {
827
828
830 } else {
832 }
835 } else {
836 if (!last_logical_record) {
837
838
839
841 return;
842 } else {
844 }
845 }
846
849 }
851 if (is_down_event) {
853 }
854 FlKeyEmbedderUserData* response_data =
856 self->sent_any_events = true;
858 self->send_key_event_user_data);
859}
860
861
863 FlKeyResponder* responder,
868 FlKeyEmbedderResponder* self = FL_KEY_EMBEDDER_RESPONDER(responder);
869 self->sent_any_events = false;
872 if (!
self->sent_any_events) {
873 self->send_key_event(&
kEmptyEvent,
nullptr,
nullptr,
874 self->send_key_event_user_data);
875 }
876}
877
879 FlKeyEmbedderResponder* responder,
881 double event_time) {
883
884 SyncStateLoopContext sync_state_context;
885 sync_state_context.self = responder;
886 sync_state_context.state =
state;
887 sync_state_context.timestamp = timestamp;
888
889
890 g_hash_table_foreach(responder->modifier_bit_to_checked_keys,
892 &sync_state_context);
893}
894
896 FlKeyEmbedderResponder* self) {
897 return self->pressing_records;
898}
@ kFlutterKeyEventTypeDown
@ kFlutterKeyEventTypeRepeat
static void handle_response(bool handled, gpointer user_data)
static void find_physical_from_logical_loop_body(gpointer key, gpointer value, gpointer user_data)
static const FlutterKeyEvent kEmptyEvent
FlKeyEvent uint64_t specified_logical_key
#define FL_TYPE_EMBEDDER_RESPONDER_USER_DATA
GHashTable * fl_key_embedder_responder_get_pressed_state(FlKeyEmbedderResponder *self)
static uint64_t event_to_timestamp(const FlKeyEvent *event)
FlKeyEmbedderResponder * fl_key_embedder_responder_new(EmbedderSendKeyEvent send_key_event, void *send_key_event_user_data)
static void fl_key_embedder_responder_handle_event(FlKeyResponder *responder, FlKeyEvent *event, uint64_t specified_logical_key, FlKeyResponderAsyncCallback callback, gpointer user_data)
static void synchronize_pressed_states_loop_body(gpointer key, gpointer value, gpointer user_data)
static void fl_key_embedder_responder_dispose(GObject *object)
static void update_caps_lock_state_logic_inferrence(FlKeyEmbedderResponder *self, bool is_down_event, bool enabled_by_state, int stage_by_record)
static uint64_t apply_id_plane(uint64_t logical_id, uint64_t plane)
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
static void fl_key_embedder_responder_handle_event_impl(FlKeyResponder *responder, FlKeyEvent *event, uint64_t specified_logical_key, FlKeyResponderAsyncCallback callback, gpointer user_data)
static uint64_t corrected_modifier_physical_key(GHashTable *modifier_bit_to_checked_keys, uint64_t physical_key_from_event, uint64_t logical_key)
static void fl_key_embedder_responder_init(FlKeyEmbedderResponder *self)
static uint64_t event_to_logical_key(const FlKeyEvent *event)
static void synthesize_simple_event(FlKeyEmbedderResponder *self, FlutterKeyEventType type, uint64_t physical, uint64_t logical, double timestamp)
static void update_mapping_record(FlKeyEmbedderResponder *self, uint64_t physical_key, uint64_t logical_key)
static char * event_to_character(const FlKeyEvent *event)
static uint64_t lookup_hash_table(GHashTable *table, uint64_t key)
static void possibly_update_lock_bit(FlKeyEmbedderResponder *self, uint64_t logical_key, bool is_down)
static void update_pressing_state(FlKeyEmbedderResponder *self, uint64_t physical_key, uint64_t logical_key)
static void synchronize_lock_states_loop_body(gpointer key, gpointer value, gpointer user_data)
void fl_key_embedder_responder_sync_modifiers_if_needed(FlKeyEmbedderResponder *responder, guint state, double event_time)
static int find_stage_by_others_event(int stage_by_record, bool is_state_on)
static uint64_t to_lower(uint64_t n)
static int find_stage_by_self_event(int stage_by_record, bool is_down_event, bool is_state_on, bool reverse_state_logic)
static FlKeyEmbedderUserData * fl_key_embedder_user_data_new(FlKeyResponderAsyncCallback callback, gpointer user_data)
constexpr uint64_t kMicrosecondsPerMillisecond
static void fl_key_embedder_responder_class_init(FlKeyEmbedderResponderClass *klass)
static uint64_t reverse_lookup_hash_table(GHashTable *table, uint64_t value)
static void is_known_modifier_physical_key_loop_body(gpointer key, gpointer value, gpointer user_data)
static int find_stage_by_record(bool is_down, bool is_enabled)
FlKeyEvent uint64_t FlKeyResponderAsyncCallback gpointer user_data
static uint64_t event_to_physical_key(const FlKeyEvent *event)
static void initialize_logical_key_to_lock_bit_loop_body(gpointer lock_bit, gpointer value, gpointer user_data)
void(* EmbedderSendKeyEvent)(const FlutterKeyEvent *event, FlutterKeyEventCallback callback, void *callback_user_data, void *send_key_event_user_data)
void(* FlKeyResponderAsyncCallback)(bool handled, gpointer user_data)
static void send_key_event(FlTextInputPlugin *plugin, gint keyval, gint state=0)
const uint64_t kValueMask
const uint64_t kUnicodePlane
std::map< uint64_t, uint64_t > xkb_to_physical_key_map
void initialize_modifier_bit_to_checked_keys(GHashTable *table)
void initialize_lock_bit_to_checked_keys(GHashTable *table)
std::map< uint64_t, uint64_t > gtk_keyval_to_logical_key_map
gpointer uint64_to_gpointer(uint64_t number)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
static Target * is_enabled(Benchmark *bench, const Config &config)
uint64_t primary_physical_key
uint64_t primary_logical_key
uint64_t secondary_logical_key
size_t struct_size
The size of this struct. Must be sizeof(FlutterKeyEvent).
FlutterKeyEventType type
The event kind.