Skip to content

Commit

Permalink
More fixes to latchToLock/clearLocks unlatching
Browse files Browse the repository at this point in the history
  • Loading branch information
Jules-Bertholet committed Jan 7, 2025
1 parent 2c14c3a commit 924eee4
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 34 deletions.
79 changes: 47 additions & 32 deletions src/state.c
Original file line number Diff line number Diff line change
Expand Up @@ -256,14 +256,51 @@ enum xkb_filter_result {
? filter_->action.group.group - state_->components.base_group \
: filter_->action.group.group

enum xkb_key_latch_state {
NO_LATCH = 0,
LATCH_KEY_DOWN,
LATCH_PENDING,
_KEY_LATCH_STATE_NUM_ENTRIES
};

#define MAX_XKB_KEY_LATCH_STATE_LOG2 2
#if (_KEY_LATCH_STATE_NUM_ENTRIES > (1 << MAX_XKB_KEY_LATCH_STATE_LOG2)) || \
(-XKB_MAX_GROUPS) < (INT32_MIN >> MAX_XKB_KEY_LATCH_STATE_LOG2) || \
XKB_MAX_GROUPS > (INT32_MAX >> MAX_XKB_KEY_LATCH_STATE_LOG2)
#error "Cannot represent priv field of the group latch filter"
#endif

/* Hold the latch state *and* the group delta */
union group_latch_priv {
uint32_t priv;
struct {
/* The type is really: enum xkb_key_latch_state, but it is problematic
* on Windows, because it is interpreted as signed and leads to wrong
* negative values. */
unsigned int latch:MAX_XKB_KEY_LATCH_STATE_LOG2;
int32_t group_delta:(32 - MAX_XKB_KEY_LATCH_STATE_LOG2);
};
};

static void
xkb_break_all_latches(struct xkb_state *state) {
struct xkb_filter *iter;
struct xkb_filter *filter;

darray_foreach(iter, state->filters) {
if (iter->action.type == ACTION_TYPE_MOD_LATCH ||
iter->action.type == ACTION_TYPE_GROUP_LATCH) {
iter->func = NULL;
darray_foreach(filter, state->filters) {
if (filter->action.type == ACTION_TYPE_MOD_LATCH) {
if (filter->priv == LATCH_PENDING) {
filter->func = NULL;
} else {
filter->priv = NO_LATCH;
}
} else if (filter->action.type == ACTION_TYPE_GROUP_LATCH) {
union group_latch_priv priv = {.priv = filter->priv};
if (priv.latch == LATCH_PENDING) {
filter->func = NULL;
} else {
priv.latch = NO_LATCH;
filter->priv = priv.priv;
}
}
}
state->components.latched_mods = 0;
Expand Down Expand Up @@ -355,32 +392,6 @@ xkb_action_breaks_latch(const union xkb_action *action)
}
}

enum xkb_key_latch_state {
NO_LATCH = 0,
LATCH_KEY_DOWN,
LATCH_PENDING,
_KEY_LATCH_STATE_NUM_ENTRIES
};

#define MAX_XKB_KEY_LATCH_STATE_LOG2 2
#if (_KEY_LATCH_STATE_NUM_ENTRIES > (1 << MAX_XKB_KEY_LATCH_STATE_LOG2)) || \
(-XKB_MAX_GROUPS) < (INT32_MIN >> MAX_XKB_KEY_LATCH_STATE_LOG2) || \
XKB_MAX_GROUPS > (INT32_MAX >> MAX_XKB_KEY_LATCH_STATE_LOG2)
#error "Cannot represent priv field of the group latch filter"
#endif

/* Hold the latch state *and* the group delta */
union group_latch_priv {
uint32_t priv;
struct {
/* The type is really: enum xkb_key_latch_state, but it is problematic
* on Windows, because it is interpreted as signed and leads to wrong
* negative values. */
unsigned int latch:MAX_XKB_KEY_LATCH_STATE_LOG2;
int32_t group_delta:(32 - MAX_XKB_KEY_LATCH_STATE_LOG2);
};
};

static void
xkb_filter_group_latch_new(struct xkb_state *state, struct xkb_filter *filter)
{
Expand Down Expand Up @@ -622,7 +633,6 @@ xkb_filter_mod_latch_func(struct xkb_state *state,
if (entry) {
type_mod_mask &= ~entry->preserve.mask;
}

xkb_mod_mask_t filter_mod_mask = filter->action.mods.mods.mask;

if (filter_mod_mask & type_mod_mask) {
Expand All @@ -649,7 +659,12 @@ xkb_filter_mod_latch_func(struct xkb_state *state,
xkb_layout_index_t group = xkb_state_xkb_key_get_layout(state, key);
const struct xkb_key_type *type = key->groups[group].type;
xkb_mod_mask_t type_mod_mask = type->mods.mask;
const struct xkb_key_type_entry *entry = get_entry_for_mods(type, state->components.mods & type_mod_mask);
if (entry) {
type_mod_mask &= ~entry->preserve.mask;
}
xkb_mod_mask_t filter_mod_mask = filter->action.mods.mods.mask;

if (filter_mod_mask & type_mod_mask) {
latch = NO_LATCH;
break;
Expand Down
2 changes: 1 addition & 1 deletion test/data/symbols/latch
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ default partial alphanumeric_keys
xkb_symbols "base" {
name[Group1] = "Test latching behavior";

key <AE01> { [ 1, exclam, NoSymbol, NoSymbol, plus ], type[Group1]="CTRL+ALT"};
key <AE01> { [ 1, exclam, 3, 4, plus ], type[Group1]="CTRL+ALT"};

key <AD01> { [ q, Q ], type[Group1] = "ALPHABETIC" };

Expand Down
23 changes: 22 additions & 1 deletion test/keyseq.c
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,7 @@ test_latch_mod_cancel(struct xkb_context *context)
NEXT, KEY_Q , BOTH, XKB_KEY_Q , // Unlatch Lock, unlatch LevelFive
NEXT, KEY_Q , BOTH, XKB_KEY_q ,

// `latchToLock` locks and `clearLocks` unlocks break existing latches
// `latchToLock` locks and `clearLocks` unlocks break existing latches...

NEXT, KEY_LEFTSHIFT , BOTH, XKB_KEY_Shift_L , // Latch Shift
NEXT, KEY_RIGHTCTRL , BOTH, XKB_KEY_ISO_Level3_Latch, // Latch LevelThree
Expand All @@ -475,7 +475,28 @@ test_latch_mod_cancel(struct xkb_context *context)
NEXT, KEY_RIGHTCTRL , BOTH, XKB_KEY_ISO_Level3_Latch, // Unlock LevelThree, unlatch Shift
NEXT, KEY_A , BOTH, XKB_KEY_a ,

// ... but a latch key still sets while being held down
NEXT, KEY_LEFTSHIFT , DOWN, XKB_KEY_Shift_L , // Set Shift
NEXT, KEY_RIGHTCTRL , BOTH, XKB_KEY_ISO_Level3_Latch, // Latch LevelThree
NEXT, KEY_RIGHTCTRL , BOTH, XKB_KEY_ISO_Level3_Latch, // Lock LevelThree
NEXT, KEY_1 , BOTH, XKB_KEY_4 ,
NEXT, KEY_1 , BOTH, XKB_KEY_4 ,
NEXT, KEY_LEFTSHIFT , UP , XKB_KEY_Caps_Lock , // Unset Shift
NEXT, KEY_1 , BOTH, XKB_KEY_3 ,
NEXT, KEY_1 , BOTH, XKB_KEY_3 ,
NEXT, KEY_RIGHTCTRL , BOTH, XKB_KEY_ISO_Level3_Latch, // Unlock LevelThree
NEXT, KEY_1 , BOTH, XKB_KEY_1 ,

NEXT, KEY_RIGHTCTRL , BOTH, XKB_KEY_ISO_Level3_Latch, // Latch LevelThree
NEXT, KEY_LEFTSHIFT , DOWN, XKB_KEY_Shift_L , // Set Shift
NEXT, KEY_RIGHTCTRL , BOTH, XKB_KEY_ISO_Level3_Latch, // Lock LevelThree
NEXT, KEY_1 , BOTH, XKB_KEY_4 ,
NEXT, KEY_1 , BOTH, XKB_KEY_4 ,
NEXT, KEY_LEFTSHIFT , UP , XKB_KEY_Caps_Lock , // Unset Shift
NEXT, KEY_1 , BOTH, XKB_KEY_3 ,
NEXT, KEY_1 , BOTH, XKB_KEY_3 ,
NEXT, KEY_RIGHTCTRL , BOTH, XKB_KEY_ISO_Level3_Latch, // Unlock LevelThree
NEXT, KEY_1 , BOTH, XKB_KEY_1 ,

FINISH));

Expand Down

0 comments on commit 924eee4

Please sign in to comment.