| Flutter Linux Embedder |

Classes | Functions | Variables
fl_key_embedder_responder.cc File Reference
`#include "flutter/shell/platform/linux/fl_key_embedder_responder.h"`
`#include <gtk/gtk.h>`
`#include <cinttypes>`
`#include "flutter/shell/platform/embedder/embedder.h"`
`#include "flutter/shell/platform/linux/fl_key_embedder_responder_private.h"`
`#include "flutter/shell/platform/linux/key_mapping.h"`

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 218 of file fl_key_embedder_responder.cc.

218 {
219 return (logical_id & kValueMask) | plane;
220 }
kValueMask
const uint64_t kValueMask
Definition: key_mapping.g.cc:514

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 604 of file fl_key_embedder_responder.cc.

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

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 251 of file fl_key_embedder_responder.cc.

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

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 230 of file fl_key_embedder_responder.cc.

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

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 222 of file fl_key_embedder_responder.cc.

222 {
223 auto found = xkb_to_physical_key_map.find(fl_key_event_get_keycode(event));
224 if (found != xkb_to_physical_key_map.end()) {
225 return found->second;
226 }
227 return apply_id_plane(fl_key_event_get_keycode(event), kGtkPlane);
228 }
fl_key_event_get_keycode
guint16 fl_key_event_get_keycode(FlKeyEvent *self)
Definition: fl_key_event.cc:89
xkb_to_physical_key_map
std::map< uint64_t, uint64_t > xkb_to_physical_key_map
Definition: key_mapping.g.cc:20

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 244 of file fl_key_embedder_responder.cc.

244 {
245 return kMicrosecondsPerMillisecond *
246 static_cast<double>(fl_key_event_get_time(event));
247 }
kMicrosecondsPerMillisecond
constexpr uint64_t kMicrosecondsPerMillisecond
Definition: fl_key_embedder_responder.cc:14
fl_key_event_get_time
guint32 fl_key_event_get_time(FlKeyEvent *self)
Definition: fl_key_event.cc:79

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 451 of file fl_key_embedder_responder.cc.

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

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 424 of file fl_key_embedder_responder.cc.

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

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 436 of file fl_key_embedder_responder.cc.

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

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 153 of file fl_key_embedder_responder.cc.

154 {
155 G_OBJECT_CLASS(klass)->dispose = fl_key_embedder_responder_dispose;
156 }
fl_key_embedder_responder_dispose
static void fl_key_embedder_responder_dispose(GObject *object)
Definition: fl_key_embedder_responder.cc:164

References fl_key_embedder_responder_dispose().

## ◆ fl_key_embedder_responder_dispose()

static void fl_key_embedder_responder_dispose | ( | GObject * | object | ) |
| static

Definition at line 164 of file fl_key_embedder_responder.cc.

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

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 783 of file fl_key_embedder_responder.cc.

784 {
785 return self->pressing_records;
786 }

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 737 of file fl_key_embedder_responder.cc.

742 {
743 g_autoptr(GTask) task = g_task_new(self, cancellable, callback, user_data);
744
745 self->sent_any_events = false;
746 fl_key_embedder_responder_handle_event_impl(self, event,
747 specified_logical_key, task);
748 if (!self->sent_any_events) {
749 g_autoptr(FlEngine) engine = FL_ENGINE(g_weak_ref_get(&self->engine));
750 if (engine != nullptr) {
751 fl_engine_send_key_event(engine, &kEmptyEvent, self->cancellable, nullptr,
752 nullptr);
753 }
754 }
755 }
g_autoptr
g_autoptr(FlEngine) engine
user_data
const char FlTextDirection FlAssertiveness gpointer user_data
Definition: fl_accessibility_handler.cc:24
fl_engine_send_key_event
void fl_engine_send_key_event(FlEngine *self, const FlutterKeyEvent *event, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
Definition: fl_engine.cc:1360
kEmptyEvent
static const FlutterKeyEvent kEmptyEvent
Definition: fl_key_embedder_responder.cc:16
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)
Definition: fl_key_embedder_responder.cc:642

References fl_engine_send_key_event(), fl_key_embedder_responder_handle_event_impl(), g_autoptr(), kEmptyEvent, and user_data.

Referenced by fl_keyboard_manager_handle_event(), 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 757 of file fl_key_embedder_responder.cc.

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

References error, and TRUE.

Referenced by responder_handle_embedder_event_cb(), 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 642 of file fl_key_embedder_responder.cc.

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

References corrected_modifier_physical_key(), 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(), lookup_hash_table(), possibly_update_lock_bit(), synchronize_lock_states(), synchronize_pressed_states(), TRUE, 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 159 of file fl_key_embedder_responder.cc.

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

## ◆ 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 181 of file fl_key_embedder_responder.cc.

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

References initialize_lock_bit_to_checked_keys(), initialize_modifier_bit_to_checked_keys(), FlKeyEmbedderCheckedKey::primary_logical_key, uint64_to_gpointer(), and value.

Referenced by fl_keyboard_manager_new(), 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 774 of file fl_key_embedder_responder.cc.

777 {
778 g_return_if_fail(FL_IS_KEY_EMBEDDER_RESPONDER(self));
779 synchronize_pressed_states(self, state,
780 event_time * kMicrosecondsPerMillisecond);
781 }

References kMicrosecondsPerMillisecond, 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 36 of file fl_key_embedder_responder.cc.

38 {
39 return gpointer_to_uint64(value) == gpointer_to_uint64(user_data);
40 }
gpointer_to_uint64
uint64_t gpointer_to_uint64(gpointer pointer)
Definition: key_mapping.h:13

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

Definition at line 31 of file fl_key_embedder_responder.cc.

31 {
32 return gpointer_to_uint64(
33 g_hash_table_lookup(table, uint64_to_gpointer(key)));
34 }

References gpointer_to_uint64(), and uint64_to_gpointer().

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

## ◆ possibly_update_lock_bit()

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

Definition at line 312 of file fl_key_embedder_responder.cc.

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

References 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 48 of file fl_key_embedder_responder.cc.

48 {
49 return gpointer_to_uint64(g_hash_table_find(
50 table, hash_table_find_equal_value, uint64_to_gpointer(value)));
51 }
hash_table_find_equal_value
static gboolean hash_table_find_equal_value(gpointer key, gpointer value, gpointer user_data)
Definition: fl_key_embedder_responder.cc:36

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 504 of file fl_key_embedder_responder.cc.

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

References find_stage_by_others_event(), find_stage_by_record(), find_stage_by_self_event(), FlKeyEmbedderCheckedKey::is_caps_lock, lookup_hash_table(), possibly_update_lock_bit(), FlKeyEmbedderCheckedKey::primary_logical_key, FlKeyEmbedderCheckedKey::primary_physical_key, 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 334 of file fl_key_embedder_responder.cc.

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

References length, lookup_hash_table(), FlKeyEmbedderCheckedKey::primary_logical_key, FlKeyEmbedderCheckedKey::primary_physical_key, reverse_lookup_hash_table(), FlKeyEmbedderCheckedKey::secondary_logical_key, 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 265 of file fl_key_embedder_responder.cc.

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

References fl_engine_send_key_event(), g_autoptr(), and type.

Referenced by synchronize_lock_states(), and synchronize_pressed_states().

## ◆ to_lower()

static uint64_t to_lower | ( | uint64_t | n | ) |
| static

Definition at line 53 of file fl_key_embedder_responder.cc.

53 {
54 constexpr uint64_t lower_a = 0x61;
55 constexpr uint64_t upper_a = 0x41;
56 constexpr uint64_t upper_z = 0x5a;
57
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;
62
63 // ASCII range.
64 if (n >= upper_a && n <= upper_z) {
65 return n - upper_a + lower_a;
66 }
67
68 // EASCII range.
69 if (n >= upper_a_grave && n <= upper_thorn && n != division) {
70 return n - upper_a_grave + lower_a_grave;
71 }
72
73 return n;
74 }

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 478 of file fl_key_embedder_responder.cc.

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

References find_stage_by_self_event().

Referenced by synchronize_lock_states().

## ◆ update_mapping_record()

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

Definition at line 325 of file fl_key_embedder_responder.cc.

327 {
328 g_hash_table_insert(self->mapping_records, uint64_to_gpointer(logical_key),
329 uint64_to_gpointer(physical_key));
330 }

References uint64_to_gpointer().

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

## ◆ update_pressing_state()

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

Definition at line 291 of file fl_key_embedder_responder.cc.

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

References lookup_hash_table(), 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,
.type = kFlutterKeyEventTypeDown,
.physical = 0,
.logical = 0,
.character = nullptr,
.synthesized = false,
}

Definition at line 16 of file fl_key_embedder_responder.cc.

Referenced by fl_key_embedder_responder_handle_event().

## ◆ kMicrosecondsPerMillisecond

constexpr uint64_t kMicrosecondsPerMillisecond = 1000
| constexpr

Definition at line 14 of file fl_key_embedder_responder.cc.

Referenced by event_to_timestamp(), and fl_key_embedder_responder_sync_modifiers_if_needed().