Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
fl_key_embedder_responder.cc File Reference

Go to the source code of this file.

Classes

struct  _FlKeyEmbedderResponder
 

Functions

static uint64_t lookup_hash_table (GHashTable *table, uint64_t key)
 
static gboolean hash_table_find_equal_value (gpointer key, gpointer value, gpointer user_data)
 
static uint64_t reverse_lookup_hash_table (GHashTable *table, uint64_t value)
 
static uint64_t to_lower (uint64_t n)
 
static void fl_key_embedder_responder_dispose (GObject *object)
 
static void fl_key_embedder_responder_class_init (FlKeyEmbedderResponderClass *klass)
 
static void fl_key_embedder_responder_init (FlKeyEmbedderResponder *self)
 
FlKeyEmbedderResponder * fl_key_embedder_responder_new (FlEngine *engine)
 
static uint64_t apply_id_plane (uint64_t logical_id, uint64_t plane)
 
static uint64_t event_to_physical_key (FlKeyEvent *event)
 
static uint64_t event_to_logical_key (FlKeyEvent *event)
 
static uint64_t event_to_timestamp (FlKeyEvent *event)
 
static char * event_to_character (FlKeyEvent *event)
 
static void synthesize_simple_event (FlKeyEmbedderResponder *self, FlutterKeyEventType type, uint64_t physical, uint64_t logical, double timestamp)
 
static void update_pressing_state (FlKeyEmbedderResponder *self, uint64_t physical_key, uint64_t logical_key)
 
static void possibly_update_lock_bit (FlKeyEmbedderResponder *self, uint64_t logical_key, bool is_down)
 
static void update_mapping_record (FlKeyEmbedderResponder *self, uint64_t physical_key, uint64_t logical_key)
 
static void synchronize_pressed_states (FlKeyEmbedderResponder *self, guint state, double timestamp)
 
static int find_stage_by_record (bool is_down, bool is_enabled)
 
static int find_stage_by_self_event (int stage_by_record, bool is_down_event, bool is_state_on, bool reverse_state_logic)
 
static int find_stage_by_others_event (int stage_by_record, bool is_state_on)
 
static void update_caps_lock_state_logic_inferrence (FlKeyEmbedderResponder *self, bool is_down_event, bool enabled_by_state, int stage_by_record)
 
static void synchronize_lock_states (FlKeyEmbedderResponder *self, guint state, double timestamp, bool is_down, uint64_t event_logical_key)
 
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_handle_event_impl (FlKeyEmbedderResponder *responder, FlKeyEvent *event, uint64_t specified_logical_key, GTask *task)
 
void fl_key_embedder_responder_handle_event (FlKeyEmbedderResponder *self, FlKeyEvent *event, uint64_t specified_logical_key, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
 
gboolean fl_key_embedder_responder_handle_event_finish (FlKeyEmbedderResponder *self, GAsyncResult *result, gboolean *handled, GError **error)
 
void fl_key_embedder_responder_sync_modifiers_if_needed (FlKeyEmbedderResponder *self, guint state, double event_time)
 
GHashTable * fl_key_embedder_responder_get_pressed_state (FlKeyEmbedderResponder *self)
 

Variables

constexpr uint64_t kMicrosecondsPerMillisecond = 1000
 
static const FlutterKeyEvent kEmptyEvent
 

Function Documentation

◆ apply_id_plane()

static uint64_t apply_id_plane ( uint64_t  logical_id,
uint64_t  plane 
)
static

Definition at line 217 of file fl_key_embedder_responder.cc.

217 {
218 return (logical_id & kValueMask) | plane;
219}
const uint64_t kValueMask

References kValueMask.

Referenced by event_to_logical_key(), and event_to_physical_key().

◆ corrected_modifier_physical_key()

static uint64_t corrected_modifier_physical_key ( GHashTable *  modifier_bit_to_checked_keys,
uint64_t  physical_key_from_event,
uint64_t  logical_key 
)
static

Definition at line 603 of file fl_key_embedder_responder.cc.

606 {
607 // If no match is found, defaults to the physical key retrieved from the
608 // event.
609 uint64_t corrected_physical_key = physical_key_from_event;
610
611 // Check if the physical key is one of the known modifier physical key.
612 bool known_modifier_physical_key = false;
613 GHashTableIter iter;
614 g_hash_table_iter_init(&iter, modifier_bit_to_checked_keys);
615 gpointer value;
616 while (g_hash_table_iter_next(&iter, nullptr, &value)) {
617 FlKeyEmbedderCheckedKey* checked_key =
618 reinterpret_cast<FlKeyEmbedderCheckedKey*>(value);
619 if (checked_key->primary_physical_key == physical_key_from_event) {
620 known_modifier_physical_key = true;
621 }
622 }
623
624 // If the physical key matches a known modifier key, find the modifier
625 // physical key from the logical key.
626 if (known_modifier_physical_key) {
627 g_hash_table_iter_init(&iter, modifier_bit_to_checked_keys);
628 while (g_hash_table_iter_next(&iter, nullptr, &value)) {
629 FlKeyEmbedderCheckedKey* checked_key =
630 reinterpret_cast<FlKeyEmbedderCheckedKey*>(value);
631 if (checked_key->primary_logical_key == logical_key ||
632 checked_key->secondary_logical_key == logical_key) {
633 corrected_physical_key = checked_key->primary_physical_key;
634 }
635 }
636 }
637
638 return corrected_physical_key;
639}
int32_t value

References FlKeyEmbedderCheckedKey::primary_logical_key, FlKeyEmbedderCheckedKey::primary_physical_key, FlKeyEmbedderCheckedKey::secondary_logical_key, and value.

Referenced by fl_key_embedder_responder_handle_event_impl().

◆ event_to_character()

static char * event_to_character ( FlKeyEvent *  event)
static

Definition at line 250 of file fl_key_embedder_responder.cc.

250 {
251 gunichar unicodeChar = gdk_keyval_to_unicode(fl_key_event_get_keyval(event));
252 glong items_written;
253 gchar* result = g_ucs4_to_utf8(&unicodeChar, 1, NULL, &items_written, NULL);
254 if (items_written == 0) {
255 if (result != NULL) {
256 g_free(result);
257 }
258 return nullptr;
259 }
260 return result;
261}
guint fl_key_event_get_keyval(FlKeyEvent *self)

References fl_key_event_get_keyval().

Referenced by fl_key_embedder_responder_handle_event_impl().

◆ event_to_logical_key()

static uint64_t event_to_logical_key ( FlKeyEvent *  event)
static

Definition at line 229 of file fl_key_embedder_responder.cc.

229 {
230 guint keyval = fl_key_event_get_keyval(event);
231 auto found = gtk_keyval_to_logical_key_map.find(keyval);
232 if (found != gtk_keyval_to_logical_key_map.end()) {
233 return found->second;
234 }
235 // EASCII range
236 if (keyval < 256) {
237 return apply_id_plane(to_lower(keyval), kUnicodePlane);
238 }
239 // Auto-generate key
240 return apply_id_plane(keyval, kGtkPlane);
241}
static uint64_t apply_id_plane(uint64_t logical_id, uint64_t plane)
static uint64_t to_lower(uint64_t n)
const uint64_t kGtkPlane
std::map< uint64_t, uint64_t > gtk_keyval_to_logical_key_map
const uint64_t kUnicodePlane

References apply_id_plane(), fl_key_event_get_keyval(), gtk_keyval_to_logical_key_map, kGtkPlane, kUnicodePlane, and to_lower().

Referenced by fl_key_embedder_responder_handle_event_impl().

◆ event_to_physical_key()

static uint64_t event_to_physical_key ( FlKeyEvent *  event)
static

Definition at line 221 of file fl_key_embedder_responder.cc.

221 {
222 auto found = xkb_to_physical_key_map.find(fl_key_event_get_keycode(event));
223 if (found != xkb_to_physical_key_map.end()) {
224 return found->second;
225 }
227}
guint16 fl_key_event_get_keycode(FlKeyEvent *self)
std::map< uint64_t, uint64_t > xkb_to_physical_key_map

References apply_id_plane(), fl_key_event_get_keycode(), kGtkPlane, and xkb_to_physical_key_map.

Referenced by fl_key_embedder_responder_handle_event_impl().

◆ event_to_timestamp()

static uint64_t event_to_timestamp ( FlKeyEvent *  event)
static

Definition at line 243 of file fl_key_embedder_responder.cc.

243 {
245 static_cast<double>(fl_key_event_get_time(event));
246}
constexpr uint64_t kMicrosecondsPerMillisecond
guint32 fl_key_event_get_time(FlKeyEvent *self)

References fl_key_event_get_time(), and kMicrosecondsPerMillisecond.

Referenced by fl_key_embedder_responder_handle_event_impl().

◆ find_stage_by_others_event()

static int find_stage_by_others_event ( int  stage_by_record,
bool  is_state_on 
)
static

Definition at line 450 of file fl_key_embedder_responder.cc.

450 {
451 g_return_val_if_fail(stage_by_record >= 0 && stage_by_record < 4,
452 stage_by_record);
453 if (!is_state_on) {
454 return 0;
455 }
456 if (stage_by_record == 0) {
457 return 1;
458 }
459 return stage_by_record;
460}

Referenced by synchronize_lock_states().

◆ find_stage_by_record()

static int find_stage_by_record ( bool  is_down,
bool  is_enabled 
)
static

Definition at line 423 of file fl_key_embedder_responder.cc.

423 {
424 constexpr int stage_by_record_index[] = {
425 0, // is_down: 0, is_enabled: 0
426 2, // 0 1
427 3, // 1 0
428 1 // 1 1
429 };
430 return stage_by_record_index[(is_down << 1) + is_enabled];
431}
static gboolean is_enabled(FlutterSemanticsFlags flags)

References is_enabled().

Referenced by synchronize_lock_states().

◆ find_stage_by_self_event()

static int find_stage_by_self_event ( int  stage_by_record,
bool  is_down_event,
bool  is_state_on,
bool  reverse_state_logic 
)
static

Definition at line 435 of file fl_key_embedder_responder.cc.

438 {
439 if (!is_state_on) {
440 return reverse_state_logic ? 2 : 0;
441 }
442 if (is_down_event) {
443 return reverse_state_logic ? 0 : 2;
444 }
445 return stage_by_record;
446}

Referenced by synchronize_lock_states(), and update_caps_lock_state_logic_inferrence().

◆ fl_key_embedder_responder_class_init()

static void fl_key_embedder_responder_class_init ( FlKeyEmbedderResponderClass *  klass)
static

Definition at line 152 of file fl_key_embedder_responder.cc.

153 {
154 G_OBJECT_CLASS(klass)->dispose = fl_key_embedder_responder_dispose;
155}
static void fl_key_embedder_responder_dispose(GObject *object)

References fl_key_embedder_responder_dispose().

◆ fl_key_embedder_responder_dispose()

static void fl_key_embedder_responder_dispose ( GObject *  object)
static

Definition at line 163 of file fl_key_embedder_responder.cc.

163 {
164 FlKeyEmbedderResponder* self = FL_KEY_EMBEDDER_RESPONDER(object);
165
166 g_cancellable_cancel(self->cancellable);
167
168 g_weak_ref_clear(&self->engine);
169 g_clear_pointer(&self->pressing_records, g_hash_table_unref);
170 g_clear_pointer(&self->mapping_records, g_hash_table_unref);
171 g_clear_pointer(&self->modifier_bit_to_checked_keys, g_hash_table_unref);
172 g_clear_pointer(&self->lock_bit_to_checked_keys, g_hash_table_unref);
173 g_clear_pointer(&self->logical_key_to_lock_bit, g_hash_table_unref);
174 g_clear_object(&self->cancellable);
175
176 G_OBJECT_CLASS(fl_key_embedder_responder_parent_class)->dispose(object);
177}

References self.

Referenced by fl_key_embedder_responder_class_init().

◆ fl_key_embedder_responder_get_pressed_state()

GHashTable * fl_key_embedder_responder_get_pressed_state ( FlKeyEmbedderResponder *  responder)

fl_key_embedder_responder_get_pressed_state: @responder: the #FlKeyEmbedderResponder self.

Returns the keyboard pressed state. The hash table contains one entry per pressed keys, mapping from the logical key to the physical key.

Definition at line 782 of file fl_key_embedder_responder.cc.

783 {
784 return self->pressing_records;
785}

References self.

Referenced by fl_keyboard_manager_get_pressed_state().

◆ fl_key_embedder_responder_handle_event()

void fl_key_embedder_responder_handle_event ( FlKeyEmbedderResponder *  responder,
FlKeyEvent *  event,
uint64_t  specified_logical_key,
GCancellable *  cancellable,
GAsyncReadyCallback  callback,
gpointer  user_data 
)

fl_key_embedder_responder_handle_event: @responder: the #FlKeyEmbedderResponder self. @event: the event to be handled. Must not be null. The object is managed by callee and must not be assumed available after this function. @specified_logical_key: @cancellable: (allow-none): a #GCancellable or NULL. @callback: (scope async): a #GAsyncReadyCallback to call when the view is added. @user_data: (closure): user data to pass to @callback.

Let the responder handle an event, expecting the responder to report whether to handle the event.

Definition at line 736 of file fl_key_embedder_responder.cc.

741 {
742 g_autoptr(GTask) task = g_task_new(self, cancellable, callback, user_data);
743
744 self->sent_any_events = false;
746 specified_logical_key, task);
747 if (!self->sent_any_events) {
748 g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine));
749 if (engine != nullptr) {
750 fl_engine_send_key_event(engine, &kEmptyEvent, self->cancellable, nullptr,
751 nullptr);
752 }
753 }
754}
FlutterEngine engine
Definition main.cc:84
g_autoptr(FlEngine) engine
void fl_engine_send_key_event(FlEngine *self, const FlutterKeyEvent *event, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
static const FlutterKeyEvent kEmptyEvent
static void fl_key_embedder_responder_handle_event_impl(FlKeyEmbedderResponder *responder, FlKeyEvent *event, uint64_t specified_logical_key, GTask *task)
FlutterDesktopBinaryReply callback

References callback, engine, fl_engine_send_key_event(), fl_key_embedder_responder_handle_event_impl(), g_autoptr(), kEmptyEvent, self, and user_data.

Referenced by fl_keyboard_manager_handle_event(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), and TEST().

◆ fl_key_embedder_responder_handle_event_finish()

gboolean fl_key_embedder_responder_handle_event_finish ( FlKeyEmbedderResponder *  responder,
GAsyncResult *  result,
gboolean *  handled,
GError **  error 
)

fl_key_embedder_responder_handle_event_finish: @responder: an #FlKeyEmbedderResponder.

Returns
: a #GAsyncResult. @handled: location to write if this event was handled by the embedder. @error: (allow-none): #GError location to store the error occurring, or NULL to ignore. If error is not NULL, *error must be initialized (typically NULL, but an error from a previous call using GLib error handling is explicitly valid).

Completes request started with fl_key_embedder_responder_handle_event().

Returns TRUE on success.

Definition at line 756 of file fl_key_embedder_responder.cc.

760 {
761 g_return_val_if_fail(g_task_is_valid(result, self), FALSE);
762
763 g_autofree gboolean* return_value =
764 static_cast<gboolean*>(g_task_propagate_pointer(G_TASK(result), error));
765 if (return_value == nullptr) {
766 return FALSE;
767 }
768
769 *handled = *return_value;
770 return TRUE;
771}
return TRUE
const uint8_t uint32_t uint32_t GError ** error

References error, self, and TRUE.

Referenced by responder_handle_embedder_event_cb(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), and TEST().

◆ fl_key_embedder_responder_handle_event_impl()

static void fl_key_embedder_responder_handle_event_impl ( FlKeyEmbedderResponder *  responder,
FlKeyEvent *  event,
uint64_t  specified_logical_key,
GTask *  task 
)
static

Definition at line 641 of file fl_key_embedder_responder.cc.

645 {
646 FlKeyEmbedderResponder* self = FL_KEY_EMBEDDER_RESPONDER(responder);
647
648 const uint64_t logical_key = specified_logical_key != 0
649 ? specified_logical_key
650 : event_to_logical_key(event);
651 const uint64_t physical_key_from_event = event_to_physical_key(event);
652 const uint64_t physical_key = corrected_modifier_physical_key(
653 self->modifier_bit_to_checked_keys, physical_key_from_event, logical_key);
654 guint state = fl_key_event_get_state(event);
655 const double timestamp = event_to_timestamp(event);
656 const bool is_down_event = fl_key_event_get_is_press(event);
657
658 // Update lock mode states
659 synchronize_lock_states(self, state, timestamp, is_down_event, logical_key);
660
661 // Update pressing states
662 synchronize_pressed_states(self, state, timestamp);
663
664 // Construct the real event
665 const uint64_t last_logical_record =
666 lookup_hash_table(self->pressing_records, physical_key);
667
668 FlutterKeyEvent out_event;
669 out_event.struct_size = sizeof(out_event);
670 out_event.timestamp = timestamp;
671 out_event.physical = physical_key;
672 out_event.logical =
673 last_logical_record != 0 ? last_logical_record : logical_key;
674 out_event.character = nullptr;
675 out_event.synthesized = false;
676
677 g_autofree char* character_to_free = nullptr;
678 if (is_down_event) {
679 if (last_logical_record) {
680 // A key has been pressed that has the exact physical key as a currently
681 // pressed one. This can happen during repeated events.
683 } else {
684 out_event.type = kFlutterKeyEventTypeDown;
685 }
686 character_to_free = event_to_character(event); // Might be null
687 out_event.character = character_to_free;
688 } else { // is_down_event false
689 if (!last_logical_record) {
690 // The physical key has been released before. It might indicate a missed
691 // event due to loss of focus, or multiple keyboards pressed keys with the
692 // same physical key. Ignore the up event.
693 gboolean* return_value = g_new0(gboolean, 1);
694 *return_value = TRUE;
695 g_task_return_pointer(task, return_value, g_free);
696 return;
697 } else {
698 out_event.type = kFlutterKeyEventTypeUp;
699 }
700 }
701
702 if (out_event.type != kFlutterKeyEventTypeRepeat) {
703 update_pressing_state(self, physical_key, is_down_event ? logical_key : 0);
704 }
705 possibly_update_lock_bit(self, logical_key, is_down_event);
706 if (is_down_event) {
707 update_mapping_record(self, physical_key, logical_key);
708 }
709 self->sent_any_events = true;
710 g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine));
711 if (engine != nullptr) {
713 engine, &out_event, self->cancellable,
714 [](GObject* object, GAsyncResult* result, gpointer user_data) {
715 g_autoptr(GTask) task = G_TASK(user_data);
716
717 gboolean handled;
718 g_autoptr(GError) error = nullptr;
719 if (!fl_engine_send_key_event_finish(FL_ENGINE(object), result,
720 &handled, &error)) {
721 if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
722 return;
723 }
724 g_warning("Failed to handle key event: %s", error->message);
725 handled = FALSE;
726 }
727
728 gboolean* return_value = g_new0(gboolean, 1);
729 *return_value = handled;
730 g_task_return_pointer(task, return_value, g_free);
731 },
732 g_object_ref(task));
733 }
734}
@ kFlutterKeyEventTypeDown
Definition embedder.h:1386
@ kFlutterKeyEventTypeUp
Definition embedder.h:1385
@ kFlutterKeyEventTypeRepeat
Definition embedder.h:1387
static uint64_t event_to_logical_key(FlKeyEvent *event)
static void synchronize_pressed_states(FlKeyEmbedderResponder *self, guint state, double timestamp)
static uint64_t event_to_physical_key(FlKeyEvent *event)
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 update_mapping_record(FlKeyEmbedderResponder *self, uint64_t physical_key, uint64_t logical_key)
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 uint64_t event_to_timestamp(FlKeyEvent *event)
static void update_pressing_state(FlKeyEmbedderResponder *self, uint64_t physical_key, uint64_t logical_key)
static char * event_to_character(FlKeyEvent *event)
static void synchronize_lock_states(FlKeyEmbedderResponder *self, guint state, double timestamp, bool is_down, uint64_t event_logical_key)
gboolean fl_key_event_get_is_press(FlKeyEvent *self)
GdkModifierType fl_key_event_get_state(FlKeyEvent *self)
uint64_t logical
Definition embedder.h:1444
size_t struct_size
The size of this struct. Must be sizeof(FlutterKeyEvent).
Definition embedder.h:1422
uint64_t physical
Definition embedder.h:1436
FlutterKeyEventType type
The event kind.
Definition embedder.h:1428
const char * character
Definition embedder.h:1447

References FlutterKeyEvent::character, corrected_modifier_physical_key(), engine, event_to_character(), event_to_logical_key(), event_to_physical_key(), event_to_timestamp(), fl_engine_send_key_event(), fl_key_event_get_is_press(), fl_key_event_get_state(), g_autoptr(), kFlutterKeyEventTypeDown, kFlutterKeyEventTypeRepeat, kFlutterKeyEventTypeUp, FlutterKeyEvent::logical, lookup_hash_table(), FlutterKeyEvent::physical, possibly_update_lock_bit(), self, FlutterKeyEvent::struct_size, synchronize_lock_states(), synchronize_pressed_states(), FlutterKeyEvent::synthesized, FlutterKeyEvent::timestamp, TRUE, FlutterKeyEvent::type, update_mapping_record(), update_pressing_state(), and user_data.

Referenced by fl_key_embedder_responder_handle_event().

◆ fl_key_embedder_responder_init()

static void fl_key_embedder_responder_init ( FlKeyEmbedderResponder *  self)
static

Definition at line 158 of file fl_key_embedder_responder.cc.

158 {
159 self->cancellable = g_cancellable_new();
160}

References self.

◆ fl_key_embedder_responder_new()

FlKeyEmbedderResponder * fl_key_embedder_responder_new ( FlEngine *  engine)

FlKeyEmbedderResponder:

A #FlKeyResponder that handles events by sending the converted events through the embedder API.

This class communicates with the HardwareKeyboard API in the framework. fl_key_embedder_responder_new: @engine: The #FlEngine, whose the embedder API will be used to send the event.

Creates a new #FlKeyEmbedderResponder.

Returns: a new #FlKeyEmbedderResponder.

Definition at line 180 of file fl_key_embedder_responder.cc.

180 {
181 FlKeyEmbedderResponder* self = FL_KEY_EMBEDDER_RESPONDER(
182 g_object_new(fl_key_embedder_responder_get_type(), nullptr));
183
184 g_weak_ref_init(&self->engine, engine);
185
186 self->pressing_records = g_hash_table_new(g_direct_hash, g_direct_equal);
187 self->mapping_records = g_hash_table_new(g_direct_hash, g_direct_equal);
188 self->lock_records = 0;
189 self->caps_lock_state_logic_inferrence = STATE_LOGIC_INFERRENCE_UNDECIDED;
190
191 self->modifier_bit_to_checked_keys =
192 g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free);
193 initialize_modifier_bit_to_checked_keys(self->modifier_bit_to_checked_keys);
194
195 self->lock_bit_to_checked_keys =
196 g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free);
197 initialize_lock_bit_to_checked_keys(self->lock_bit_to_checked_keys);
198
199 // Associate a logical key with its corresponding modifier bit.
200 self->logical_key_to_lock_bit =
201 g_hash_table_new(g_direct_hash, g_direct_equal);
202 GHashTableIter iter;
203 g_hash_table_iter_init(&iter, self->lock_bit_to_checked_keys);
204 gpointer key, value;
205 while (g_hash_table_iter_next(&iter, &key, &value)) {
206 guint lock_bit = GPOINTER_TO_UINT(key);
207 FlKeyEmbedderCheckedKey* checked_key =
208 reinterpret_cast<FlKeyEmbedderCheckedKey*>(value);
209 g_hash_table_insert(self->logical_key_to_lock_bit,
211 GUINT_TO_POINTER(lock_bit));
212 }
213
214 return self;
215}
void initialize_modifier_bit_to_checked_keys(GHashTable *table)
void initialize_lock_bit_to_checked_keys(GHashTable *table)
gpointer uint64_to_gpointer(uint64_t number)
g_hash_table_insert(self->handlers, g_strdup(channel), handler_new(handler, user_data, destroy_notify))

References engine, g_hash_table_insert(), initialize_lock_bit_to_checked_keys(), initialize_modifier_bit_to_checked_keys(), key, FlKeyEmbedderCheckedKey::primary_logical_key, self, uint64_to_gpointer(), and value.

Referenced by fl_keyboard_manager_new(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), TEST(), and TEST().

◆ fl_key_embedder_responder_sync_modifiers_if_needed()

void fl_key_embedder_responder_sync_modifiers_if_needed ( FlKeyEmbedderResponder *  responder,
guint  state,
double  event_time 
)

fl_key_embedder_responder_sync_modifiers_if_needed: @responder: the #FlKeyEmbedderResponder self. @state: the state of the modifiers mask. @event_time: the time attribute of the incoming GDK event.

If needed, synthesize modifier keys up and down event by comparing their current pressing states with the given modifiers mask.

Definition at line 773 of file fl_key_embedder_responder.cc.

776 {
777 g_return_if_fail(FL_IS_KEY_EMBEDDER_RESPONDER(self));
779 event_time * kMicrosecondsPerMillisecond);
780}

References kMicrosecondsPerMillisecond, self, and synchronize_pressed_states().

Referenced by fl_keyboard_manager_sync_modifier_if_needed().

◆ hash_table_find_equal_value()

static gboolean hash_table_find_equal_value ( gpointer  key,
gpointer  value,
gpointer  user_data 
)
static

Definition at line 35 of file fl_key_embedder_responder.cc.

37 {
39}
uint64_t gpointer_to_uint64(gpointer pointer)

References gpointer_to_uint64(), user_data, and value.

Referenced by reverse_lookup_hash_table().

◆ lookup_hash_table()

static uint64_t lookup_hash_table ( GHashTable *  table,
uint64_t  key 
)
static

◆ possibly_update_lock_bit()

static void possibly_update_lock_bit ( FlKeyEmbedderResponder *  self,
uint64_t  logical_key,
bool  is_down 
)
static

Definition at line 311 of file fl_key_embedder_responder.cc.

313 {
314 if (!is_down) {
315 return;
316 }
317 const guint mode_bit = GPOINTER_TO_UINT(g_hash_table_lookup(
318 self->logical_key_to_lock_bit, uint64_to_gpointer(logical_key)));
319 if (mode_bit != 0) {
320 self->lock_records ^= mode_bit;
321 }
322}

References self, and uint64_to_gpointer().

Referenced by fl_key_embedder_responder_handle_event_impl(), and synchronize_lock_states().

◆ reverse_lookup_hash_table()

static uint64_t reverse_lookup_hash_table ( GHashTable *  table,
uint64_t  value 
)
static

Definition at line 47 of file fl_key_embedder_responder.cc.

47 {
48 return gpointer_to_uint64(g_hash_table_find(
50}
static gboolean hash_table_find_equal_value(gpointer key, gpointer value, gpointer user_data)

References gpointer_to_uint64(), hash_table_find_equal_value(), uint64_to_gpointer(), and value.

Referenced by synchronize_pressed_states().

◆ synchronize_lock_states()

static void synchronize_lock_states ( FlKeyEmbedderResponder *  self,
guint  state,
double  timestamp,
bool  is_down,
uint64_t  event_logical_key 
)
static

Definition at line 503 of file fl_key_embedder_responder.cc.

507 {
508 GHashTableIter iter;
509 g_hash_table_iter_init(&iter, self->lock_bit_to_checked_keys);
510 gpointer key, value;
511 while (g_hash_table_iter_next(&iter, &key, &value)) {
512 guint modifier_bit = GPOINTER_TO_UINT(key);
513 FlKeyEmbedderCheckedKey* checked_key =
514 reinterpret_cast<FlKeyEmbedderCheckedKey*>(value);
515
516 const uint64_t logical_key = checked_key->primary_logical_key;
517 const uint64_t recorded_physical_key =
518 lookup_hash_table(self->mapping_records, logical_key);
519 // The physical key is derived from past mapping record if possible.
520 //
521 // If the event to be synthesized is a key up event, then there must have
522 // been a key down event before, which has updated the mapping record.
523 // If the event to be synthesized is a key down event, then there might
524 // not have been a mapping record, in which case the hard-coded
525 // #primary_physical_key is used.
526 const uint64_t physical_key = recorded_physical_key != 0
527 ? recorded_physical_key
528 : checked_key->primary_physical_key;
529
530 // A lock mode key can be at any of a 4-stage cycle, depending on whether
531 // it's pressed and enabled. The following table lists the definition of
532 // each stage (TruePressed and TrueEnabled), the event of the lock key
533 // between every 2 stages (SelfType and SelfState), and the event of other
534 // keys at each stage (OthersState). On certain platforms SelfState uses a
535 // reversed rule for certain keys (SelfState(rvsd), as documented in
536 // #update_caps_lock_state_logic_inferrence).
537 //
538 // # [0] [1] [2] [3]
539 // TruePressed: Released Pressed Released Pressed
540 // TrueEnabled: Disabled Enabled Enabled Disabled
541 // SelfType: Down Up Down Up
542 // SelfState: 0 1 1 1
543 // SelfState(rvsd): 1 1 0 1
544 // OthersState: 0 1 1 1
545 //
546 // When the exact stage can't be derived, choose the stage that requires the
547 // minimal synthesization.
548
549 const uint64_t pressed_logical_key =
550 recorded_physical_key == 0
551 ? 0
552 : lookup_hash_table(self->pressing_records, recorded_physical_key);
553
554 g_return_if_fail(pressed_logical_key == 0 ||
555 pressed_logical_key == logical_key);
556 const int stage_by_record = find_stage_by_record(
557 pressed_logical_key != 0, (self->lock_records & modifier_bit) != 0);
558
559 const bool enabled_by_state = (state & modifier_bit) != 0;
560 const bool this_key_is_event_key = logical_key == event_logical_key;
561 if (this_key_is_event_key && checked_key->is_caps_lock) {
562 update_caps_lock_state_logic_inferrence(self, is_down, enabled_by_state,
563 stage_by_record);
564 g_return_if_fail(self->caps_lock_state_logic_inferrence !=
565 STATE_LOGIC_INFERRENCE_UNDECIDED);
566 }
567 const bool reverse_state_logic =
568 checked_key->is_caps_lock && self->caps_lock_state_logic_inferrence ==
569 STATE_LOGIC_INFERRENCE_REVERSED;
570 const int stage_by_event =
571 this_key_is_event_key
572 ? find_stage_by_self_event(stage_by_record, is_down,
573 enabled_by_state, reverse_state_logic)
574 : find_stage_by_others_event(stage_by_record, enabled_by_state);
575
576 // The destination stage is equal to stage_by_event but shifted cyclically
577 // to be no less than stage_by_record.
578 constexpr int kNumStages = 4;
579 const int destination_stage = stage_by_event >= stage_by_record
580 ? stage_by_event
581 : stage_by_event + kNumStages;
582
583 g_return_if_fail(stage_by_record <= destination_stage);
584 for (int current_stage = stage_by_record;
585 current_stage < destination_stage && current_stage < 9;
586 current_stage += 1) {
587 const int standard_current_stage = current_stage % kNumStages;
588 const bool is_down_event =
589 standard_current_stage == 0 || standard_current_stage == 2;
590 if (is_down_event && recorded_physical_key == 0) {
591 update_mapping_record(self, physical_key, logical_key);
592 }
595 update_pressing_state(self, physical_key,
596 is_down_event ? logical_key : 0);
597 possibly_update_lock_bit(self, logical_key, is_down_event);
598 synthesize_simple_event(self, type, physical_key, logical_key, timestamp);
599 }
600 }
601}
FlutterKeyEventType
Definition embedder.h:1384
static void update_caps_lock_state_logic_inferrence(FlKeyEmbedderResponder *self, bool is_down_event, bool enabled_by_state, int stage_by_record)
static void synthesize_simple_event(FlKeyEmbedderResponder *self, FlutterKeyEventType type, uint64_t physical, uint64_t logical, double timestamp)
static int find_stage_by_others_event(int stage_by_record, bool is_state_on)
static int find_stage_by_self_event(int stage_by_record, bool is_down_event, bool is_state_on, bool reverse_state_logic)
static int find_stage_by_record(bool is_down, bool is_enabled)
impeller::ShaderType type

References find_stage_by_others_event(), find_stage_by_record(), find_stage_by_self_event(), FlKeyEmbedderCheckedKey::is_caps_lock, key, kFlutterKeyEventTypeDown, kFlutterKeyEventTypeUp, lookup_hash_table(), possibly_update_lock_bit(), FlKeyEmbedderCheckedKey::primary_logical_key, FlKeyEmbedderCheckedKey::primary_physical_key, self, synthesize_simple_event(), type, update_caps_lock_state_logic_inferrence(), update_mapping_record(), update_pressing_state(), and value.

Referenced by fl_key_embedder_responder_handle_event_impl().

◆ synchronize_pressed_states()

static void synchronize_pressed_states ( FlKeyEmbedderResponder *  self,
guint  state,
double  timestamp 
)
static

Definition at line 333 of file fl_key_embedder_responder.cc.

335 {
336 GHashTableIter iter;
337 g_hash_table_iter_init(&iter, self->modifier_bit_to_checked_keys);
338 gpointer key, value;
339 while (g_hash_table_iter_next(&iter, &key, &value)) {
340 guint modifier_bit = GPOINTER_TO_UINT(key);
341 FlKeyEmbedderCheckedKey* checked_key =
342 reinterpret_cast<FlKeyEmbedderCheckedKey*>(value);
343
344 // Each TestKey contains up to two logical keys, typically the left modifier
345 // and the right modifier, that correspond to the same modifier_bit. We'd
346 // like to infer whether to synthesize a down or up event for each key.
347 //
348 // The hard part is that, if we want to synthesize a down event, we don't
349 // know which physical key to use. Here we assume the keyboard layout do not
350 // change frequently and use the last physical-logical relationship,
351 // recorded in #mapping_records.
352 const uint64_t logical_keys[] = {
353 checked_key->primary_logical_key,
354 checked_key->secondary_logical_key,
355 };
356 const guint length = checked_key->secondary_logical_key == 0 ? 1 : 2;
357
358 const bool any_pressed_by_state = (state & modifier_bit) != 0;
359
360 bool any_pressed_by_record = false;
361
362 // Traverse each logical key of this modifier bit for 2 purposes:
363 //
364 // 1. Perform the synthesization of release events: If the modifier bit is
365 // 0
366 // and the key is pressed, synthesize a release event.
367 // 2. Prepare for the synthesization of press events: If the modifier bit
368 // is
369 // 1, and no keys are pressed (discovered here), synthesize a press
370 // event later.
371 for (guint logical_key_idx = 0; logical_key_idx < length;
372 logical_key_idx++) {
373 const uint64_t logical_key = logical_keys[logical_key_idx];
374 g_return_if_fail(logical_key != 0);
375 const uint64_t pressing_physical_key =
376 reverse_lookup_hash_table(self->pressing_records, logical_key);
377 const bool this_key_pressed_before_event = pressing_physical_key != 0;
378
379 any_pressed_by_record =
380 any_pressed_by_record || this_key_pressed_before_event;
381
382 if (this_key_pressed_before_event && !any_pressed_by_state) {
383 const uint64_t recorded_physical_key =
384 lookup_hash_table(self->mapping_records, logical_key);
385 // Since this key has been pressed before, there must have been a
386 // recorded physical key.
387 g_return_if_fail(recorded_physical_key != 0);
388 // In rare cases #recorded_logical_key is different from #logical_key.
389 const uint64_t recorded_logical_key =
390 lookup_hash_table(self->pressing_records, recorded_physical_key);
392 recorded_physical_key, recorded_logical_key,
393 timestamp);
394 update_pressing_state(self, recorded_physical_key, 0);
395 }
396 }
397 // If the modifier should be pressed, synthesize a down event for its
398 // primary key.
399 if (any_pressed_by_state && !any_pressed_by_record) {
400 const uint64_t logical_key = checked_key->primary_logical_key;
401 const uint64_t recorded_physical_key =
402 lookup_hash_table(self->mapping_records, logical_key);
403 // The physical key is derived from past mapping record if possible.
404 //
405 // The event to be synthesized is a key down event. There might not have
406 // been a mapping record, in which case the hard-coded
407 // #primary_physical_key is used.
408 const uint64_t physical_key = recorded_physical_key != 0
409 ? recorded_physical_key
410 : checked_key->primary_physical_key;
411 if (recorded_physical_key == 0) {
412 update_mapping_record(self, physical_key, logical_key);
413 }
415 logical_key, timestamp);
416 update_pressing_state(self, physical_key, logical_key);
417 }
418 }
419}
static uint64_t reverse_lookup_hash_table(GHashTable *table, uint64_t value)
size_t length

References key, kFlutterKeyEventTypeDown, kFlutterKeyEventTypeUp, length, lookup_hash_table(), FlKeyEmbedderCheckedKey::primary_logical_key, FlKeyEmbedderCheckedKey::primary_physical_key, reverse_lookup_hash_table(), FlKeyEmbedderCheckedKey::secondary_logical_key, self, synthesize_simple_event(), update_mapping_record(), update_pressing_state(), and value.

Referenced by fl_key_embedder_responder_handle_event_impl(), and fl_key_embedder_responder_sync_modifiers_if_needed().

◆ synthesize_simple_event()

static void synthesize_simple_event ( FlKeyEmbedderResponder *  self,
FlutterKeyEventType  type,
uint64_t  physical,
uint64_t  logical,
double  timestamp 
)
static

Definition at line 264 of file fl_key_embedder_responder.cc.

268 {
269 FlutterKeyEvent out_event;
270 out_event.struct_size = sizeof(out_event);
271 out_event.timestamp = timestamp;
272 out_event.type = type;
273 out_event.physical = physical;
274 out_event.logical = logical;
275 out_event.character = nullptr;
276 out_event.synthesized = true;
277 self->sent_any_events = true;
278 g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine));
279 if (engine != nullptr) {
280 fl_engine_send_key_event(engine, &out_event, self->cancellable, nullptr,
281 nullptr);
282 }
283}

References FlutterKeyEvent::character, engine, fl_engine_send_key_event(), g_autoptr(), FlutterKeyEvent::logical, FlutterKeyEvent::physical, self, FlutterKeyEvent::struct_size, FlutterKeyEvent::synthesized, FlutterKeyEvent::timestamp, type, and FlutterKeyEvent::type.

Referenced by synchronize_lock_states(), and synchronize_pressed_states().

◆ to_lower()

static uint64_t to_lower ( uint64_t  n)
static

Definition at line 52 of file fl_key_embedder_responder.cc.

52 {
53 constexpr uint64_t lower_a = 0x61;
54 constexpr uint64_t upper_a = 0x41;
55 constexpr uint64_t upper_z = 0x5a;
56
57 constexpr uint64_t lower_a_grave = 0xe0;
58 constexpr uint64_t upper_a_grave = 0xc0;
59 constexpr uint64_t upper_thorn = 0xde;
60 constexpr uint64_t division = 0xf7;
61
62 // ASCII range.
63 if (n >= upper_a && n <= upper_z) {
64 return n - upper_a + lower_a;
65 }
66
67 // EASCII range.
68 if (n >= upper_a_grave && n <= upper_thorn && n != division) {
69 return n - upper_a_grave + lower_a_grave;
70 }
71
72 return n;
73}

Referenced by event_to_logical_key().

◆ update_caps_lock_state_logic_inferrence()

static void update_caps_lock_state_logic_inferrence ( FlKeyEmbedderResponder *  self,
bool  is_down_event,
bool  enabled_by_state,
int  stage_by_record 
)
static

Definition at line 477 of file fl_key_embedder_responder.cc.

481 {
482 if (self->caps_lock_state_logic_inferrence !=
483 STATE_LOGIC_INFERRENCE_UNDECIDED) {
484 return;
485 }
486 if (!is_down_event) {
487 return;
488 }
489 const int stage_by_event = find_stage_by_self_event(
490 stage_by_record, is_down_event, enabled_by_state, false);
491 if ((stage_by_event == 0 && stage_by_record == 2) ||
492 (stage_by_event == 2 && stage_by_record == 0)) {
493 self->caps_lock_state_logic_inferrence = STATE_LOGIC_INFERRENCE_REVERSED;
494 } else {
495 self->caps_lock_state_logic_inferrence = STATE_LOGIC_INFERRENCE_NORMAL;
496 }
497}

References find_stage_by_self_event(), and self.

Referenced by synchronize_lock_states().

◆ update_mapping_record()

static void update_mapping_record ( FlKeyEmbedderResponder *  self,
uint64_t  physical_key,
uint64_t  logical_key 
)
static

◆ update_pressing_state()

static void update_pressing_state ( FlKeyEmbedderResponder *  self,
uint64_t  physical_key,
uint64_t  logical_key 
)
static

Definition at line 290 of file fl_key_embedder_responder.cc.

292 {
293 if (logical_key != 0) {
294 g_return_if_fail(lookup_hash_table(self->pressing_records, physical_key) ==
295 0);
296 g_hash_table_insert(self->pressing_records,
297 uint64_to_gpointer(physical_key),
298 uint64_to_gpointer(logical_key));
299 } else {
300 g_return_if_fail(lookup_hash_table(self->pressing_records, physical_key) !=
301 0);
302 g_hash_table_remove(self->pressing_records,
303 uint64_to_gpointer(physical_key));
304 }
305}

References g_hash_table_insert(), lookup_hash_table(), self, and uint64_to_gpointer().

Referenced by fl_key_embedder_responder_handle_event_impl(), synchronize_lock_states(), and synchronize_pressed_states().

Variable Documentation

◆ kEmptyEvent

const FlutterKeyEvent kEmptyEvent
static
Initial value:
{
.struct_size = sizeof(FlutterKeyEvent),
.timestamp = 0,
.physical = 0,
.logical = 0,
.character = nullptr,
.synthesized = false,
}

Definition at line 15 of file fl_key_embedder_responder.cc.

15 {
16 .struct_size = sizeof(FlutterKeyEvent),
17 .timestamp = 0,
19 .physical = 0,
20 .logical = 0,
21 .character = nullptr,
22 .synthesized = false,
23};

Referenced by fl_key_embedder_responder_handle_event().

◆ kMicrosecondsPerMillisecond

constexpr uint64_t kMicrosecondsPerMillisecond = 1000
constexpr