Simplify hash table iteration. (#162483)
Removes the need to use structures to keep state and keeps logic in the same function.
This commit is contained in:
parent
6ea438f296
commit
b68321a45d
@ -177,21 +177,6 @@ static void fl_key_embedder_responder_dispose(GObject* object) {
|
|||||||
G_OBJECT_CLASS(fl_key_embedder_responder_parent_class)->dispose(object);
|
G_OBJECT_CLASS(fl_key_embedder_responder_parent_class)->dispose(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill in #logical_key_to_lock_bit by associating a logical key with
|
|
||||||
// its corresponding modifier bit.
|
|
||||||
//
|
|
||||||
// This is used as the body of a loop over #lock_bit_to_checked_keys.
|
|
||||||
static void initialize_logical_key_to_lock_bit_loop_body(gpointer lock_bit,
|
|
||||||
gpointer value,
|
|
||||||
gpointer user_data) {
|
|
||||||
FlKeyEmbedderCheckedKey* checked_key =
|
|
||||||
reinterpret_cast<FlKeyEmbedderCheckedKey*>(value);
|
|
||||||
GHashTable* table = reinterpret_cast<GHashTable*>(user_data);
|
|
||||||
g_hash_table_insert(table,
|
|
||||||
uint64_to_gpointer(checked_key->primary_logical_key),
|
|
||||||
GUINT_TO_POINTER(lock_bit));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creates a new FlKeyEmbedderResponder instance.
|
// Creates a new FlKeyEmbedderResponder instance.
|
||||||
FlKeyEmbedderResponder* fl_key_embedder_responder_new(FlEngine* engine) {
|
FlKeyEmbedderResponder* fl_key_embedder_responder_new(FlEngine* engine) {
|
||||||
FlKeyEmbedderResponder* self = FL_KEY_EMBEDDER_RESPONDER(
|
FlKeyEmbedderResponder* self = FL_KEY_EMBEDDER_RESPONDER(
|
||||||
@ -212,11 +197,20 @@ FlKeyEmbedderResponder* fl_key_embedder_responder_new(FlEngine* engine) {
|
|||||||
g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free);
|
g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free);
|
||||||
initialize_lock_bit_to_checked_keys(self->lock_bit_to_checked_keys);
|
initialize_lock_bit_to_checked_keys(self->lock_bit_to_checked_keys);
|
||||||
|
|
||||||
|
// Associate a logical key with its corresponding modifier bit.
|
||||||
self->logical_key_to_lock_bit =
|
self->logical_key_to_lock_bit =
|
||||||
g_hash_table_new(g_direct_hash, g_direct_equal);
|
g_hash_table_new(g_direct_hash, g_direct_equal);
|
||||||
g_hash_table_foreach(self->lock_bit_to_checked_keys,
|
GHashTableIter iter;
|
||||||
initialize_logical_key_to_lock_bit_loop_body,
|
g_hash_table_iter_init(&iter, self->lock_bit_to_checked_keys);
|
||||||
self->logical_key_to_lock_bit);
|
gpointer key, value;
|
||||||
|
while (g_hash_table_iter_next(&iter, &key, &value)) {
|
||||||
|
guint lock_bit = GPOINTER_TO_UINT(key);
|
||||||
|
FlKeyEmbedderCheckedKey* checked_key =
|
||||||
|
reinterpret_cast<FlKeyEmbedderCheckedKey*>(value);
|
||||||
|
g_hash_table_insert(self->logical_key_to_lock_bit,
|
||||||
|
uint64_to_gpointer(checked_key->primary_logical_key),
|
||||||
|
GUINT_TO_POINTER(lock_bit));
|
||||||
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@ -289,29 +283,6 @@ static void synthesize_simple_event(FlKeyEmbedderResponder* self,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
// Context variables for the foreach call used to synchronize pressing states
|
|
||||||
// and lock states.
|
|
||||||
typedef struct {
|
|
||||||
FlKeyEmbedderResponder* self;
|
|
||||||
guint state;
|
|
||||||
uint64_t event_logical_key;
|
|
||||||
bool is_down;
|
|
||||||
double timestamp;
|
|
||||||
} SyncStateLoopContext;
|
|
||||||
|
|
||||||
// Context variables for the foreach call used to find the physical key from
|
|
||||||
// a modifier logical key.
|
|
||||||
typedef struct {
|
|
||||||
bool known_modifier_physical_key;
|
|
||||||
uint64_t logical_key;
|
|
||||||
uint64_t physical_key_from_event;
|
|
||||||
uint64_t corrected_physical_key;
|
|
||||||
} ModifierLogicalToPhysicalContext;
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
// Update the pressing record.
|
// Update the pressing record.
|
||||||
//
|
//
|
||||||
// If `logical_key` is 0, the record will be set as "released". Otherwise, the
|
// If `logical_key` is 0, the record will be set as "released". Otherwise, the
|
||||||
@ -360,44 +331,46 @@ static void update_mapping_record(FlKeyEmbedderResponder* self,
|
|||||||
|
|
||||||
// Synchronizes the pressing state of a key to its state from the event by
|
// Synchronizes the pressing state of a key to its state from the event by
|
||||||
// synthesizing events.
|
// synthesizing events.
|
||||||
//
|
static void synchronize_pressed_states(FlKeyEmbedderResponder* self,
|
||||||
// This is used as the body of a loop over #modifier_bit_to_checked_keys.
|
guint state,
|
||||||
static void synchronize_pressed_states_loop_body(gpointer key,
|
double timestamp) {
|
||||||
gpointer value,
|
GHashTableIter iter;
|
||||||
gpointer user_data) {
|
g_hash_table_iter_init(&iter, self->modifier_bit_to_checked_keys);
|
||||||
SyncStateLoopContext* context =
|
gpointer key, value;
|
||||||
reinterpret_cast<SyncStateLoopContext*>(user_data);
|
while (g_hash_table_iter_next(&iter, &key, &value)) {
|
||||||
|
guint modifier_bit = GPOINTER_TO_UINT(key);
|
||||||
FlKeyEmbedderCheckedKey* checked_key =
|
FlKeyEmbedderCheckedKey* checked_key =
|
||||||
reinterpret_cast<FlKeyEmbedderCheckedKey*>(value);
|
reinterpret_cast<FlKeyEmbedderCheckedKey*>(value);
|
||||||
|
|
||||||
const guint modifier_bit = GPOINTER_TO_INT(key);
|
|
||||||
FlKeyEmbedderResponder* self = context->self;
|
|
||||||
// Each TestKey contains up to two logical keys, typically the left modifier
|
// Each TestKey contains up to two logical keys, typically the left modifier
|
||||||
// and the right modifier, that correspond to the same modifier_bit. We'd
|
// and the right modifier, that correspond to the same modifier_bit. We'd
|
||||||
// like to infer whether to synthesize a down or up event for each key.
|
// like to infer whether to synthesize a down or up event for each key.
|
||||||
//
|
//
|
||||||
// The hard part is that, if we want to synthesize a down event, we don't know
|
// The hard part is that, if we want to synthesize a down event, we don't
|
||||||
// which physical key to use. Here we assume the keyboard layout do not change
|
// know which physical key to use. Here we assume the keyboard layout do not
|
||||||
// frequently and use the last physical-logical relationship, recorded in
|
// change frequently and use the last physical-logical relationship,
|
||||||
// #mapping_records.
|
// recorded in #mapping_records.
|
||||||
const uint64_t logical_keys[] = {
|
const uint64_t logical_keys[] = {
|
||||||
checked_key->primary_logical_key,
|
checked_key->primary_logical_key,
|
||||||
checked_key->secondary_logical_key,
|
checked_key->secondary_logical_key,
|
||||||
};
|
};
|
||||||
const guint length = checked_key->secondary_logical_key == 0 ? 1 : 2;
|
const guint length = checked_key->secondary_logical_key == 0 ? 1 : 2;
|
||||||
|
|
||||||
const bool any_pressed_by_state = (context->state & modifier_bit) != 0;
|
const bool any_pressed_by_state = (state & modifier_bit) != 0;
|
||||||
|
|
||||||
bool any_pressed_by_record = false;
|
bool any_pressed_by_record = false;
|
||||||
|
|
||||||
// Traverse each logical key of this modifier bit for 2 purposes:
|
// Traverse each logical key of this modifier bit for 2 purposes:
|
||||||
//
|
//
|
||||||
// 1. Perform the synthesization of release events: If the modifier bit is 0
|
// 1. Perform the synthesization of release events: If the modifier bit is
|
||||||
|
// 0
|
||||||
// and the key is pressed, synthesize a release event.
|
// and the key is pressed, synthesize a release event.
|
||||||
// 2. Prepare for the synthesization of press events: If the modifier bit is
|
// 2. Prepare for the synthesization of press events: If the modifier bit
|
||||||
// 1, and no keys are pressed (discovered here), synthesize a press event
|
// is
|
||||||
// later.
|
// 1, and no keys are pressed (discovered here), synthesize a press
|
||||||
for (guint logical_key_idx = 0; logical_key_idx < length; logical_key_idx++) {
|
// event later.
|
||||||
|
for (guint logical_key_idx = 0; logical_key_idx < length;
|
||||||
|
logical_key_idx++) {
|
||||||
const uint64_t logical_key = logical_keys[logical_key_idx];
|
const uint64_t logical_key = logical_keys[logical_key_idx];
|
||||||
g_return_if_fail(logical_key != 0);
|
g_return_if_fail(logical_key != 0);
|
||||||
const uint64_t pressing_physical_key =
|
const uint64_t pressing_physical_key =
|
||||||
@ -410,20 +383,20 @@ static void synchronize_pressed_states_loop_body(gpointer key,
|
|||||||
if (this_key_pressed_before_event && !any_pressed_by_state) {
|
if (this_key_pressed_before_event && !any_pressed_by_state) {
|
||||||
const uint64_t recorded_physical_key =
|
const uint64_t recorded_physical_key =
|
||||||
lookup_hash_table(self->mapping_records, logical_key);
|
lookup_hash_table(self->mapping_records, logical_key);
|
||||||
// Since this key has been pressed before, there must have been a recorded
|
// Since this key has been pressed before, there must have been a
|
||||||
// physical key.
|
// recorded physical key.
|
||||||
g_return_if_fail(recorded_physical_key != 0);
|
g_return_if_fail(recorded_physical_key != 0);
|
||||||
// In rare cases #recorded_logical_key is different from #logical_key.
|
// In rare cases #recorded_logical_key is different from #logical_key.
|
||||||
const uint64_t recorded_logical_key =
|
const uint64_t recorded_logical_key =
|
||||||
lookup_hash_table(self->pressing_records, recorded_physical_key);
|
lookup_hash_table(self->pressing_records, recorded_physical_key);
|
||||||
synthesize_simple_event(self, kFlutterKeyEventTypeUp,
|
synthesize_simple_event(self, kFlutterKeyEventTypeUp,
|
||||||
recorded_physical_key, recorded_logical_key,
|
recorded_physical_key, recorded_logical_key,
|
||||||
context->timestamp);
|
timestamp);
|
||||||
update_pressing_state(self, recorded_physical_key, 0);
|
update_pressing_state(self, recorded_physical_key, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If the modifier should be pressed, synthesize a down event for its primary
|
// If the modifier should be pressed, synthesize a down event for its
|
||||||
// key.
|
// primary key.
|
||||||
if (any_pressed_by_state && !any_pressed_by_record) {
|
if (any_pressed_by_state && !any_pressed_by_record) {
|
||||||
const uint64_t logical_key = checked_key->primary_logical_key;
|
const uint64_t logical_key = checked_key->primary_logical_key;
|
||||||
const uint64_t recorded_physical_key =
|
const uint64_t recorded_physical_key =
|
||||||
@ -431,8 +404,8 @@ static void synchronize_pressed_states_loop_body(gpointer key,
|
|||||||
// The physical key is derived from past mapping record if possible.
|
// The physical key is derived from past mapping record if possible.
|
||||||
//
|
//
|
||||||
// The event to be synthesized is a key down event. There might not have
|
// The event to be synthesized is a key down event. There might not have
|
||||||
// been a mapping record, in which case the hard-coded #primary_physical_key
|
// been a mapping record, in which case the hard-coded
|
||||||
// is used.
|
// #primary_physical_key is used.
|
||||||
const uint64_t physical_key = recorded_physical_key != 0
|
const uint64_t physical_key = recorded_physical_key != 0
|
||||||
? recorded_physical_key
|
? recorded_physical_key
|
||||||
: checked_key->primary_physical_key;
|
: checked_key->primary_physical_key;
|
||||||
@ -440,10 +413,11 @@ static void synchronize_pressed_states_loop_body(gpointer key,
|
|||||||
update_mapping_record(self, physical_key, logical_key);
|
update_mapping_record(self, physical_key, logical_key);
|
||||||
}
|
}
|
||||||
synthesize_simple_event(self, kFlutterKeyEventTypeDown, physical_key,
|
synthesize_simple_event(self, kFlutterKeyEventTypeDown, physical_key,
|
||||||
logical_key, context->timestamp);
|
logical_key, timestamp);
|
||||||
update_pressing_state(self, physical_key, logical_key);
|
update_pressing_state(self, physical_key, logical_key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Find the stage # by the current record, which should be the recorded stage
|
// Find the stage # by the current record, which should be the recorded stage
|
||||||
// before the event.
|
// before the event.
|
||||||
@ -490,7 +464,7 @@ static int find_stage_by_others_event(int stage_by_record, bool is_state_on) {
|
|||||||
//
|
//
|
||||||
// In most cases, when a lock key is pressed or released, its event has the
|
// In most cases, when a lock key is pressed or released, its event has the
|
||||||
// key's state as 0-1-1-1 for the 4 stages (as documented in
|
// key's state as 0-1-1-1 for the 4 stages (as documented in
|
||||||
// #synchronize_lock_states_loop_body) respectively. But in very rare cases it
|
// #synchronize_lock_states) respectively. But in very rare cases it
|
||||||
// produces 1-1-0-1, which we call "reversed state logic". This is observed
|
// produces 1-1-0-1, which we call "reversed state logic". This is observed
|
||||||
// when using Chrome Remote Desktop on macOS (likely a bug).
|
// when using Chrome Remote Desktop on macOS (likely a bug).
|
||||||
//
|
//
|
||||||
@ -526,20 +500,20 @@ static void update_caps_lock_state_logic_inferrence(
|
|||||||
// Synchronizes the lock state of a key to its state from the event by
|
// Synchronizes the lock state of a key to its state from the event by
|
||||||
// synthesizing events.
|
// synthesizing events.
|
||||||
//
|
//
|
||||||
// This is used as the body of a loop over #lock_bit_to_checked_keys.
|
|
||||||
//
|
|
||||||
// This function might modify #caps_lock_state_logic_inferrence.
|
// This function might modify #caps_lock_state_logic_inferrence.
|
||||||
static void synchronize_lock_states_loop_body(gpointer key,
|
static void synchronize_lock_states(FlKeyEmbedderResponder* self,
|
||||||
gpointer value,
|
guint state,
|
||||||
gpointer user_data) {
|
double timestamp,
|
||||||
SyncStateLoopContext* context =
|
bool is_down,
|
||||||
reinterpret_cast<SyncStateLoopContext*>(user_data);
|
uint64_t event_logical_key) {
|
||||||
|
GHashTableIter iter;
|
||||||
|
g_hash_table_iter_init(&iter, self->lock_bit_to_checked_keys);
|
||||||
|
gpointer key, value;
|
||||||
|
while (g_hash_table_iter_next(&iter, &key, &value)) {
|
||||||
|
guint modifier_bit = GPOINTER_TO_UINT(key);
|
||||||
FlKeyEmbedderCheckedKey* checked_key =
|
FlKeyEmbedderCheckedKey* checked_key =
|
||||||
reinterpret_cast<FlKeyEmbedderCheckedKey*>(value);
|
reinterpret_cast<FlKeyEmbedderCheckedKey*>(value);
|
||||||
|
|
||||||
guint modifier_bit = GPOINTER_TO_INT(key);
|
|
||||||
FlKeyEmbedderResponder* self = context->self;
|
|
||||||
|
|
||||||
const uint64_t logical_key = checked_key->primary_logical_key;
|
const uint64_t logical_key = checked_key->primary_logical_key;
|
||||||
const uint64_t recorded_physical_key =
|
const uint64_t recorded_physical_key =
|
||||||
lookup_hash_table(self->mapping_records, logical_key);
|
lookup_hash_table(self->mapping_records, logical_key);
|
||||||
@ -554,12 +528,12 @@ static void synchronize_lock_states_loop_body(gpointer key,
|
|||||||
? recorded_physical_key
|
? recorded_physical_key
|
||||||
: checked_key->primary_physical_key;
|
: checked_key->primary_physical_key;
|
||||||
|
|
||||||
// A lock mode key can be at any of a 4-stage cycle, depending on whether it's
|
// A lock mode key can be at any of a 4-stage cycle, depending on whether
|
||||||
// pressed and enabled. The following table lists the definition of each
|
// it's pressed and enabled. The following table lists the definition of
|
||||||
// stage (TruePressed and TrueEnabled), the event of the lock key between
|
// each stage (TruePressed and TrueEnabled), the event of the lock key
|
||||||
// every 2 stages (SelfType and SelfState), and the event of other keys at
|
// between every 2 stages (SelfType and SelfState), and the event of other
|
||||||
// each stage (OthersState). On certain platforms SelfState uses a reversed
|
// keys at each stage (OthersState). On certain platforms SelfState uses a
|
||||||
// rule for certain keys (SelfState(rvsd), as documented in
|
// reversed rule for certain keys (SelfState(rvsd), as documented in
|
||||||
// #update_caps_lock_state_logic_inferrence).
|
// #update_caps_lock_state_logic_inferrence).
|
||||||
//
|
//
|
||||||
// # [0] [1] [2] [3]
|
// # [0] [1] [2] [3]
|
||||||
@ -583,40 +557,34 @@ static void synchronize_lock_states_loop_body(gpointer key,
|
|||||||
const int stage_by_record = find_stage_by_record(
|
const int stage_by_record = find_stage_by_record(
|
||||||
pressed_logical_key != 0, (self->lock_records & modifier_bit) != 0);
|
pressed_logical_key != 0, (self->lock_records & modifier_bit) != 0);
|
||||||
|
|
||||||
const bool enabled_by_state = (context->state & modifier_bit) != 0;
|
const bool enabled_by_state = (state & modifier_bit) != 0;
|
||||||
const bool this_key_is_event_key = logical_key == context->event_logical_key;
|
const bool this_key_is_event_key = logical_key == event_logical_key;
|
||||||
if (this_key_is_event_key && checked_key->is_caps_lock) {
|
if (this_key_is_event_key && checked_key->is_caps_lock) {
|
||||||
update_caps_lock_state_logic_inferrence(self, context->is_down,
|
update_caps_lock_state_logic_inferrence(self, is_down, enabled_by_state,
|
||||||
enabled_by_state, stage_by_record);
|
stage_by_record);
|
||||||
g_return_if_fail(self->caps_lock_state_logic_inferrence !=
|
g_return_if_fail(self->caps_lock_state_logic_inferrence !=
|
||||||
STATE_LOGIC_INFERRENCE_UNDECIDED);
|
STATE_LOGIC_INFERRENCE_UNDECIDED);
|
||||||
}
|
}
|
||||||
const bool reverse_state_logic =
|
const bool reverse_state_logic =
|
||||||
checked_key->is_caps_lock &&
|
checked_key->is_caps_lock && self->caps_lock_state_logic_inferrence ==
|
||||||
self->caps_lock_state_logic_inferrence == STATE_LOGIC_INFERRENCE_REVERSED;
|
STATE_LOGIC_INFERRENCE_REVERSED;
|
||||||
const int stage_by_event =
|
const int stage_by_event =
|
||||||
this_key_is_event_key
|
this_key_is_event_key
|
||||||
? find_stage_by_self_event(stage_by_record, context->is_down,
|
? find_stage_by_self_event(stage_by_record, is_down,
|
||||||
enabled_by_state, reverse_state_logic)
|
enabled_by_state, reverse_state_logic)
|
||||||
: find_stage_by_others_event(stage_by_record, enabled_by_state);
|
: find_stage_by_others_event(stage_by_record, enabled_by_state);
|
||||||
|
|
||||||
// The destination stage is equal to stage_by_event but shifted cyclically to
|
// The destination stage is equal to stage_by_event but shifted cyclically
|
||||||
// be no less than stage_by_record.
|
// to be no less than stage_by_record.
|
||||||
constexpr int kNumStages = 4;
|
constexpr int kNumStages = 4;
|
||||||
const int destination_stage = stage_by_event >= stage_by_record
|
const int destination_stage = stage_by_event >= stage_by_record
|
||||||
? stage_by_event
|
? stage_by_event
|
||||||
: stage_by_event + kNumStages;
|
: stage_by_event + kNumStages;
|
||||||
|
|
||||||
g_return_if_fail(stage_by_record <= destination_stage);
|
g_return_if_fail(stage_by_record <= destination_stage);
|
||||||
if (stage_by_record == destination_stage) {
|
for (int current_stage = stage_by_record;
|
||||||
return;
|
current_stage < destination_stage && current_stage < 9;
|
||||||
}
|
|
||||||
for (int current_stage = stage_by_record; current_stage < destination_stage;
|
|
||||||
current_stage += 1) {
|
current_stage += 1) {
|
||||||
if (current_stage == 9) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const int standard_current_stage = current_stage % kNumStages;
|
const int standard_current_stage = current_stage % kNumStages;
|
||||||
const bool is_down_event =
|
const bool is_down_event =
|
||||||
standard_current_stage == 0 || standard_current_stage == 2;
|
standard_current_stage == 0 || standard_current_stage == 2;
|
||||||
@ -625,74 +593,50 @@ static void synchronize_lock_states_loop_body(gpointer key,
|
|||||||
}
|
}
|
||||||
FlutterKeyEventType type =
|
FlutterKeyEventType type =
|
||||||
is_down_event ? kFlutterKeyEventTypeDown : kFlutterKeyEventTypeUp;
|
is_down_event ? kFlutterKeyEventTypeDown : kFlutterKeyEventTypeUp;
|
||||||
update_pressing_state(self, physical_key, is_down_event ? logical_key : 0);
|
update_pressing_state(self, physical_key,
|
||||||
|
is_down_event ? logical_key : 0);
|
||||||
possibly_update_lock_bit(self, logical_key, is_down_event);
|
possibly_update_lock_bit(self, logical_key, is_down_event);
|
||||||
synthesize_simple_event(self, type, physical_key, logical_key,
|
synthesize_simple_event(self, type, physical_key, logical_key, timestamp);
|
||||||
context->timestamp);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find if a given physical key is the primary physical of one of the known
|
|
||||||
// modifier keys.
|
|
||||||
//
|
|
||||||
// This is used as the body of a loop over #modifier_bit_to_checked_keys.
|
|
||||||
static void is_known_modifier_physical_key_loop_body(gpointer key,
|
|
||||||
gpointer value,
|
|
||||||
gpointer user_data) {
|
|
||||||
ModifierLogicalToPhysicalContext* context =
|
|
||||||
reinterpret_cast<ModifierLogicalToPhysicalContext*>(user_data);
|
|
||||||
FlKeyEmbedderCheckedKey* checked_key =
|
|
||||||
reinterpret_cast<FlKeyEmbedderCheckedKey*>(value);
|
|
||||||
|
|
||||||
if (checked_key->primary_physical_key == context->physical_key_from_event) {
|
|
||||||
context->known_modifier_physical_key = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the primary physical key of a known modifier key which matches the
|
|
||||||
// given logical key.
|
|
||||||
//
|
|
||||||
// This is used as the body of a loop over #modifier_bit_to_checked_keys.
|
|
||||||
static void find_physical_from_logical_loop_body(gpointer key,
|
|
||||||
gpointer value,
|
|
||||||
gpointer user_data) {
|
|
||||||
ModifierLogicalToPhysicalContext* context =
|
|
||||||
reinterpret_cast<ModifierLogicalToPhysicalContext*>(user_data);
|
|
||||||
FlKeyEmbedderCheckedKey* checked_key =
|
|
||||||
reinterpret_cast<FlKeyEmbedderCheckedKey*>(value);
|
|
||||||
|
|
||||||
if (checked_key->primary_logical_key == context->logical_key ||
|
|
||||||
checked_key->secondary_logical_key == context->logical_key) {
|
|
||||||
context->corrected_physical_key = checked_key->primary_physical_key;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t corrected_modifier_physical_key(
|
static uint64_t corrected_modifier_physical_key(
|
||||||
GHashTable* modifier_bit_to_checked_keys,
|
GHashTable* modifier_bit_to_checked_keys,
|
||||||
uint64_t physical_key_from_event,
|
uint64_t physical_key_from_event,
|
||||||
uint64_t logical_key) {
|
uint64_t logical_key) {
|
||||||
ModifierLogicalToPhysicalContext logical_to_physical_context;
|
|
||||||
logical_to_physical_context.known_modifier_physical_key = false;
|
|
||||||
logical_to_physical_context.physical_key_from_event = physical_key_from_event;
|
|
||||||
logical_to_physical_context.logical_key = logical_key;
|
|
||||||
// If no match is found, defaults to the physical key retrieved from the
|
// If no match is found, defaults to the physical key retrieved from the
|
||||||
// event.
|
// event.
|
||||||
logical_to_physical_context.corrected_physical_key = physical_key_from_event;
|
uint64_t corrected_physical_key = physical_key_from_event;
|
||||||
|
|
||||||
// Check if the physical key is one of the known modifier physical key.
|
// Check if the physical key is one of the known modifier physical key.
|
||||||
g_hash_table_foreach(modifier_bit_to_checked_keys,
|
bool known_modifier_physical_key = false;
|
||||||
is_known_modifier_physical_key_loop_body,
|
GHashTableIter iter;
|
||||||
&logical_to_physical_context);
|
g_hash_table_iter_init(&iter, modifier_bit_to_checked_keys);
|
||||||
|
gpointer value;
|
||||||
|
while (g_hash_table_iter_next(&iter, nullptr, &value)) {
|
||||||
|
FlKeyEmbedderCheckedKey* checked_key =
|
||||||
|
reinterpret_cast<FlKeyEmbedderCheckedKey*>(value);
|
||||||
|
if (checked_key->primary_physical_key == physical_key_from_event) {
|
||||||
|
known_modifier_physical_key = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If the physical key matches a known modifier key, find the modifier
|
// If the physical key matches a known modifier key, find the modifier
|
||||||
// physical key from the logical key.
|
// physical key from the logical key.
|
||||||
if (logical_to_physical_context.known_modifier_physical_key) {
|
if (known_modifier_physical_key) {
|
||||||
g_hash_table_foreach(modifier_bit_to_checked_keys,
|
g_hash_table_iter_init(&iter, modifier_bit_to_checked_keys);
|
||||||
find_physical_from_logical_loop_body,
|
while (g_hash_table_iter_next(&iter, nullptr, &value)) {
|
||||||
&logical_to_physical_context);
|
FlKeyEmbedderCheckedKey* checked_key =
|
||||||
|
reinterpret_cast<FlKeyEmbedderCheckedKey*>(value);
|
||||||
|
if (checked_key->primary_logical_key == logical_key ||
|
||||||
|
checked_key->secondary_logical_key == logical_key) {
|
||||||
|
corrected_physical_key = checked_key->primary_physical_key;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return logical_to_physical_context.corrected_physical_key;
|
return corrected_physical_key;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fl_key_embedder_responder_handle_event_impl(
|
static void fl_key_embedder_responder_handle_event_impl(
|
||||||
@ -708,24 +652,15 @@ static void fl_key_embedder_responder_handle_event_impl(
|
|||||||
const uint64_t physical_key_from_event = event_to_physical_key(event);
|
const uint64_t physical_key_from_event = event_to_physical_key(event);
|
||||||
const uint64_t physical_key = corrected_modifier_physical_key(
|
const uint64_t physical_key = corrected_modifier_physical_key(
|
||||||
self->modifier_bit_to_checked_keys, physical_key_from_event, logical_key);
|
self->modifier_bit_to_checked_keys, physical_key_from_event, logical_key);
|
||||||
|
guint state = fl_key_event_get_state(event);
|
||||||
const double timestamp = event_to_timestamp(event);
|
const double timestamp = event_to_timestamp(event);
|
||||||
const bool is_down_event = fl_key_event_get_is_press(event);
|
const bool is_down_event = fl_key_event_get_is_press(event);
|
||||||
|
|
||||||
SyncStateLoopContext sync_state_context;
|
|
||||||
sync_state_context.self = self;
|
|
||||||
sync_state_context.state = fl_key_event_get_state(event);
|
|
||||||
sync_state_context.timestamp = timestamp;
|
|
||||||
sync_state_context.is_down = is_down_event;
|
|
||||||
sync_state_context.event_logical_key = logical_key;
|
|
||||||
|
|
||||||
// Update lock mode states
|
// Update lock mode states
|
||||||
g_hash_table_foreach(self->lock_bit_to_checked_keys,
|
synchronize_lock_states(self, state, timestamp, is_down_event, logical_key);
|
||||||
synchronize_lock_states_loop_body, &sync_state_context);
|
|
||||||
|
|
||||||
// Update pressing states
|
// Update pressing states
|
||||||
g_hash_table_foreach(self->modifier_bit_to_checked_keys,
|
synchronize_pressed_states(self, state, timestamp);
|
||||||
synchronize_pressed_states_loop_body,
|
|
||||||
&sync_state_context);
|
|
||||||
|
|
||||||
// Construct the real event
|
// Construct the real event
|
||||||
const uint64_t last_logical_record =
|
const uint64_t last_logical_record =
|
||||||
@ -841,18 +776,8 @@ void fl_key_embedder_responder_sync_modifiers_if_needed(
|
|||||||
guint state,
|
guint state,
|
||||||
double event_time) {
|
double event_time) {
|
||||||
g_return_if_fail(FL_IS_KEY_EMBEDDER_RESPONDER(self));
|
g_return_if_fail(FL_IS_KEY_EMBEDDER_RESPONDER(self));
|
||||||
|
synchronize_pressed_states(self, state,
|
||||||
const double timestamp = event_time * kMicrosecondsPerMillisecond;
|
event_time * kMicrosecondsPerMillisecond);
|
||||||
|
|
||||||
SyncStateLoopContext sync_state_context;
|
|
||||||
sync_state_context.self = self;
|
|
||||||
sync_state_context.state = state;
|
|
||||||
sync_state_context.timestamp = timestamp;
|
|
||||||
|
|
||||||
// Update pressing states.
|
|
||||||
g_hash_table_foreach(self->modifier_bit_to_checked_keys,
|
|
||||||
synchronize_pressed_states_loop_body,
|
|
||||||
&sync_state_context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GHashTable* fl_key_embedder_responder_get_pressed_state(
|
GHashTable* fl_key_embedder_responder_get_pressed_state(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user