5#include "flutter/shell/platform/linux/fl_key_embedder_responder.h"
10#include "flutter/shell/platform/embedder/embedder.h"
11#include "flutter/shell/platform/linux/fl_key_embedder_responder_private.h"
12#include "flutter/shell/platform/linux/key_mapping.h"
54 constexpr uint64_t lower_a = 0x61;
55 constexpr uint64_t upper_a = 0x41;
56 constexpr uint64_t upper_z = 0x5a;
58 constexpr uint64_t lower_a_grave = 0xe0;
59 constexpr uint64_t upper_a_grave = 0xc0;
60 constexpr uint64_t upper_thorn = 0xde;
61 constexpr uint64_t division = 0xf7;
64 if (n >= upper_a && n <= upper_z) {
65 return n - upper_a + lower_a;
69 if (n >= upper_a_grave && n <= upper_thorn && n != division) {
70 return n - upper_a_grave + lower_a_grave;
83#define FL_TYPE_EMBEDDER_USER_DATA fl_key_embedder_user_data_get_type()
85 fl_key_embedder_user_data,
87 KEY_EMBEDDER_USER_DATA,
97G_DEFINE_TYPE(FlKeyEmbedderUserData, fl_key_embedder_user_data, G_TYPE_OBJECT)
102 FlKeyEmbedderUserDataClass* klass) {
111 g_return_if_fail(FL_IS_KEY_EMBEDDER_USER_DATA(
object));
120 FlKeyEmbedderUserData*
self = FL_KEY_EMBEDDER_USER_DATA(
133 kStateLogicUndecided,
136} StateLogicInferrence;
201 FlKeyResponderInterface* iface);
204#define FL_TYPE_EMBEDDER_RESPONDER_USER_DATA \
205 fl_key_embedder_responder_get_type()
207 FlKeyEmbedderResponder,
208 fl_key_embedder_responder,
214 FlKeyResponder* responder,
221 FlKeyResponderInterface* iface) {
227 FlKeyEmbedderResponderClass* klass) {
236 FlKeyEmbedderResponder*
self = FL_KEY_EMBEDDER_RESPONDER(
object);
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);
244 G_OBJECT_CLASS(fl_key_embedder_responder_parent_class)->dispose(
object);
257 g_hash_table_insert(
table,
259 GUINT_TO_POINTER(lock_bit));
265 void* send_key_event_user_data) {
266 FlKeyEmbedderResponder*
self = FL_KEY_EMBEDDER_RESPONDER(
270 self->send_key_event_user_data = send_key_event_user_data;
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;
277 self->modifier_bit_to_checked_keys =
278 g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free);
281 self->lock_bit_to_checked_keys =
282 g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free);
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);
303 return found->second;
309 guint keyval =
event->keyval;
312 return found->second;
329 gunichar unicodeChar = gdk_keyval_to_unicode(
event->
keyval);
331 gchar*
result = g_ucs4_to_utf8(&unicodeChar, 1, NULL, &items_written, NULL);
332 if (items_written == 0) {
344 g_autoptr(FlKeyEmbedderUserData)
data = FL_KEY_EMBEDDER_USER_DATA(
user_data);
346 g_return_if_fail(
data->callback !=
nullptr);
348 data->callback(handled,
data->user_data);
365 self->sent_any_events =
true;
366 self->send_key_event(&out_event,
nullptr,
nullptr,
367 self->send_key_event_user_data);
375 FlKeyEmbedderResponder*
self;
377 uint64_t event_logical_key;
380} SyncStateLoopContext;
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;
399 uint64_t physical_key,
400 uint64_t logical_key) {
401 if (logical_key != 0) {
404 g_hash_table_insert(
self->pressing_records,
410 g_hash_table_remove(
self->pressing_records,
420 uint64_t logical_key,
425 const guint mode_bit = GPOINTER_TO_UINT(g_hash_table_lookup(
428 self->lock_records ^= mode_bit;
433 uint64_t physical_key,
434 uint64_t logical_key) {
446 SyncStateLoopContext* context =
447 reinterpret_cast<SyncStateLoopContext*
>(
user_data);
451 const guint modifier_bit = GPOINTER_TO_INT(
key);
452 FlKeyEmbedderResponder*
self = context->self;
461 const uint64_t logical_keys[] = {
467 const bool any_pressed_by_state = (context->state & modifier_bit) != 0;
469 bool any_pressed_by_record =
false;
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;
485 any_pressed_by_record =
486 any_pressed_by_record || this_key_pressed_before_event;
488 if (this_key_pressed_before_event && !any_pressed_by_state) {
489 const uint64_t recorded_physical_key =
493 g_return_if_fail(recorded_physical_key != 0);
495 const uint64_t recorded_logical_key =
498 recorded_physical_key, recorded_logical_key,
505 if (any_pressed_by_state && !any_pressed_by_record) {
507 const uint64_t recorded_physical_key =
514 const uint64_t physical_key = recorded_physical_key != 0
515 ? recorded_physical_key
517 if (recorded_physical_key == 0) {
521 logical_key, context->timestamp);
529 constexpr int stage_by_record_index[] = {
535 return stage_by_record_index[(is_down << 1) +
is_enabled];
543 bool reverse_state_logic) {
545 return reverse_state_logic ? 2 : 0;
548 return reverse_state_logic ? 0 : 2;
550 return stage_by_record;
556 g_return_val_if_fail(stage_by_record >= 0 && stage_by_record < 4,
561 if (stage_by_record == 0) {
564 return stage_by_record;
583 FlKeyEmbedderResponder*
self,
585 bool enabled_by_state,
586 int stage_by_record) {
587 if (
self->caps_lock_state_logic_inferrence != kStateLogicUndecided) {
590 if (!is_down_event) {
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;
599 self->caps_lock_state_logic_inferrence = kStateLogicNormal;
612 SyncStateLoopContext* context =
613 reinterpret_cast<SyncStateLoopContext*
>(
user_data);
617 guint modifier_bit = GPOINTER_TO_INT(
key);
618 FlKeyEmbedderResponder*
self = context->self;
621 const uint64_t recorded_physical_key =
630 const uint64_t physical_key = recorded_physical_key != 0
631 ? recorded_physical_key
653 const uint64_t pressed_logical_key =
654 recorded_physical_key == 0
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);
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);
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)
682 constexpr int kNumStages = 4;
683 const int destination_stage = stage_by_event >= stage_by_record
685 : stage_by_event + kNumStages;
687 g_return_if_fail(stage_by_record <= destination_stage);
688 if (stage_by_record == destination_stage) {
691 for (
int current_stage = stage_by_record; current_stage < destination_stage;
692 current_stage += 1) {
693 if (current_stage == 9) {
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) {
719 ModifierLogicalToPhysicalContext* context =
720 reinterpret_cast<ModifierLogicalToPhysicalContext*
>(
user_data);
725 context->known_modifier_physical_key =
true;
736 ModifierLogicalToPhysicalContext* context =
737 reinterpret_cast<ModifierLogicalToPhysicalContext*
>(
user_data);
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;
757 logical_to_physical_context.corrected_physical_key = physical_key_from_event;
760 g_hash_table_foreach(modifier_bit_to_checked_keys,
762 &logical_to_physical_context);
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);
772 return logical_to_physical_context.corrected_physical_key;
776 FlKeyResponder* responder,
781 FlKeyEmbedderResponder*
self = FL_KEY_EMBEDDER_RESPONDER(responder);
783 g_return_if_fail(
event !=
nullptr);
784 g_return_if_fail(
callback !=
nullptr);
791 self->modifier_bit_to_checked_keys, physical_key_from_event, logical_key);
793 const bool is_down_event =
event->is_press;
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;
803 g_hash_table_foreach(
self->lock_bit_to_checked_keys,
807 g_hash_table_foreach(
self->modifier_bit_to_checked_keys,
809 &sync_state_context);
812 const uint64_t last_logical_record =
820 last_logical_record != 0 ? last_logical_record : logical_key;
824 g_autofree
char* character_to_free =
nullptr;
826 if (last_logical_record) {
836 if (!last_logical_record) {
854 FlKeyEmbedderUserData* response_data =
856 self->sent_any_events =
true;
858 self->send_key_event_user_data);
863 FlKeyResponder* responder,
868 FlKeyEmbedderResponder*
self = FL_KEY_EMBEDDER_RESPONDER(responder);
869 self->sent_any_events =
false;
872 if (!
self->sent_any_events) {
874 self->send_key_event_user_data);
879 FlKeyEmbedderResponder* responder,
884 SyncStateLoopContext sync_state_context;
885 sync_state_context.self = responder;
886 sync_state_context.state =
state;
887 sync_state_context.timestamp = timestamp;
890 g_hash_table_foreach(responder->modifier_bit_to_checked_keys,
892 &sync_state_context);
896 FlKeyEmbedderResponder*
self) {
897 return self->pressing_records;
@ kFlutterKeyEventTypeDown
@ kFlutterKeyEventTypeRepeat
G_DEFINE_TYPE(FlBasicMessageChannelResponseHandle, fl_basic_message_channel_response_handle, G_TYPE_OBJECT) static void fl_basic_message_channel_response_handle_dispose(GObject *object)
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
G_DEFINE_TYPE_WITH_CODE(FlKeyEmbedderResponder, fl_key_embedder_responder, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE(FL_TYPE_KEY_RESPONDER, fl_key_embedder_responder_iface_init)) static void fl_key_embedder_responder_handle_event(FlKeyResponder *responder
static gboolean hash_table_find_equal_value(gpointer key, gpointer value, gpointer user_data)
static void fl_key_embedder_responder_iface_init(FlKeyResponderInterface *iface)
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)
G_DECLARE_FINAL_TYPE(FlKeyEmbedderUserData, fl_key_embedder_user_data, FL, KEY_EMBEDDER_USER_DATA, GObject)
static void update_mapping_record(FlKeyEmbedderResponder *self, uint64_t physical_key, uint64_t logical_key)
static char * event_to_character(const FlKeyEvent *event)
static void fl_key_embedder_user_data_dispose(GObject *object)
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 void fl_key_embedder_user_data_class_init(FlKeyEmbedderUserDataClass *klass)
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)
#define FL_TYPE_EMBEDDER_USER_DATA
constexpr uint64_t kMicrosecondsPerMillisecond
static void fl_key_embedder_user_data_init(FlKeyEmbedderUserData *self)
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)
#define FL_TYPE_KEY_RESPONDER
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)
uint64_t gpointer_to_uint64(gpointer pointer)
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.
GHashTable * logical_key_to_lock_bit
GHashTable * mapping_records
GHashTable * modifier_bit_to_checked_keys
EmbedderSendKeyEvent send_key_event
GHashTable * pressing_records
GHashTable * lock_bit_to_checked_keys
StateLogicInferrence caps_lock_state_logic_inferrence
void * send_key_event_user_data
FlKeyResponderAsyncCallback callback
std::shared_ptr< const fml::Mapping > data