Skip to content

Commit

Permalink
Latches break existig latches of the latching key's type modifiers
Browse files Browse the repository at this point in the history
Changed latching behavior so that latching a modifier or group now breaks existing modifier latches,
but only if the type of the key responsible for the latter latch
has the modifier of the pre-existing latch in its modifiers list.

For example, if a new latch is triggered by pressing a key of type `ALPHABETIC`,
existing `Shift` and `Lock` latches will now be broken, but other latches
will be preserved as before.

This ensures the correct behavior when combining sticky keys with
`ISO_Level5_Latch` or latched-group additional symbols layers.

Signed-off-by: Jules Bertholet <[email protected]>
  • Loading branch information
Jules-Bertholet committed Dec 21, 2024
1 parent 1600066 commit 801c873
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Changed latching behavior so that latching a modifier or group breaks existing modifier latches,
but only if the type of the key responsible for the latter latch
has the modifier of the pre-existing latch in its modifiers list.
27 changes: 24 additions & 3 deletions src/state.c
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ xkb_state_key_get_layout(struct xkb_state *state, xkb_keycode_t kc)

return XkbWrapGroupIntoRange(state->components.group, key->num_groups,
key->out_of_range_group_action,
key->out_of_range_group_number);
key->out_of_range_group_number);
}

static unsigned int
Expand Down Expand Up @@ -312,8 +312,9 @@ xkb_filter_group_lock_func(struct xkb_state *state,
return XKB_FILTER_CONTINUE;
}

/* Mod latches have additional break conditions not handled by this function */
static bool
xkb_action_breaks_latch(const union xkb_action *action, bool is_group_latch)
xkb_action_breaks_latch(const union xkb_action *action)
{
switch (action->type) {
case ACTION_TYPE_NONE:
Expand Down Expand Up @@ -568,11 +569,31 @@ xkb_filter_mod_latch_func(struct xkb_state *state,
}
else if (xkb_action_breaks_latch(&(actions[k]))) {
/* XXX: This may be totally broken, we might need to break the
* latch in the next run after this press? */
* latch in the next run after this press? */
state->components.latched_mods &= ~filter->action.mods.mods.mask;
filter->func = NULL;
return XKB_FILTER_CONTINUE;
}
else if (actions->type == ACTION_TYPE_GROUP_LATCH ||
actions->type == ACTION_TYPE_MOD_LATCH) {
/* We break latches only for mods that are part of the type's mod mask. */
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;

xkb_mod_mask_t filter_mod_mask = filter->action.mods.mods.mask;
xkb_mod_mask_t mods_to_unlatch_mask = filter_mod_mask & type_mod_mask;
xkb_mod_mask_t mods_to_keep_mask = filter_mod_mask & ~type_mod_mask;

state->components.latched_mods &= ~mods_to_unlatch_mask;
if (mods_to_keep_mask == 0) {
filter->func = NULL;
} else {
filter->action.mods.mods.mask = mods_to_keep_mask;
}

return XKB_FILTER_CONTINUE;
}
}
}
else if (direction == XKB_KEY_UP && key == filter->key) {
Expand Down
31 changes: 31 additions & 0 deletions test/data/symbols/latch
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
default partial alphanumeric_keys
xkb_symbols "base" {
name[Group1] = "Test latching behavior";

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

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

key <CAPS> { [ Caps_Lock ] };

key <LFSH> {
symbols[Group1] = [ Shift_L, Caps_Lock ],
actions[Group1] = [ LatchMods(modifiers=Shift), LockMods(modifiers=Lock) ]
};

key <LCTL> {
symbols[Group1] = [ Control_L ],
actions[Group1] = [ LatchMods(modifiers=Control) ]
};

key <LALT> {
symbols[Group1] = [ Alt_L ],
actions[Group1] = [ LatchMods(modifiers=Alt) ]
};

key <RTSH> {
symbols[Group1] = [ Shift_R, Shift_R, Shift_R, Shift_R, Shift_R ],
actions[Group1] = [ LatchMods(modifiers=Lock), LatchMods(modifiers=Lock), LatchMods(modifiers=Lock), LatchMods(modifiers=Lock), LatchMods(modifiers=Lock) ],
type[Group1]="CTRL+ALT"
};
};
74 changes: 74 additions & 0 deletions test/keyseq.c
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,79 @@ test_explicit_actions(struct xkb_context *ctx)
}
}

static void
test_latch_mod_cancel(struct xkb_context *context)
{
struct xkb_keymap *keymap;

keymap = test_compile_rules(context, "evdev", "evdev", "latch", "", "");
assert(keymap);

assert(test_key_seq(keymap,
KEY_Q, BOTH, XKB_KEY_q,
NEXT, KEY_1, BOTH, XKB_KEY_1,

// Basic latch/unlatch

NEXT, KEY_LEFTSHIFT , BOTH, XKB_KEY_Shift_L, // Latch Shift
NEXT, KEY_Q , BOTH, XKB_KEY_Q , // Unlatch Shift
NEXT, KEY_Q , BOTH, XKB_KEY_q ,

NEXT, KEY_LEFTSHIFT , BOTH, XKB_KEY_Shift_L, // Latch Shift
NEXT, KEY_1 , BOTH, XKB_KEY_exclam , // Unlatch Shift
NEXT, KEY_1 , BOTH, XKB_KEY_1 ,

// Lock/unlock cancels latch

NEXT, KEY_LEFTSHIFT , BOTH, XKB_KEY_Shift_L , // Latch Shift
NEXT, KEY_LEFTSHIFT , BOTH, XKB_KEY_Caps_Lock, // Lock Caps, unlatch Shift
NEXT, KEY_Q , BOTH, XKB_KEY_Q ,
NEXT, KEY_1 , BOTH, XKB_KEY_1 ,
NEXT, KEY_LEFTSHIFT , BOTH, XKB_KEY_Shift_L , // Latch Shift
NEXT, KEY_1 , BOTH, XKB_KEY_exclam , // Unlatch Shift
NEXT, KEY_1 , BOTH, XKB_KEY_1 ,
NEXT, KEY_LEFTSHIFT , BOTH, XKB_KEY_Shift_L , // Latch Shift
NEXT, KEY_Q , BOTH, XKB_KEY_q , // Unlatch Shift
NEXT, KEY_Q , BOTH, XKB_KEY_Q ,
NEXT, KEY_LEFTSHIFT , BOTH, XKB_KEY_Shift_L , // Latch Shift
NEXT, KEY_LEFTSHIFT , BOTH, XKB_KEY_Caps_Lock, // Unlock Caps, unlatch Shift
NEXT, KEY_Q , BOTH, XKB_KEY_q ,

// Double latch/unlatch

NEXT, KEY_LEFTCTRL , BOTH, XKB_KEY_Control_L, // Latch Control
NEXT, KEY_LEFTALT , BOTH, XKB_KEY_Alt_L , // Latch Alt
NEXT, KEY_1 , BOTH, XKB_KEY_plus , // Unlatch Control, Unlatch Alt

NEXT, KEY_RIGHTSHIFT, BOTH, XKB_KEY_Shift_R , // Latch Lock
NEXT, KEY_LEFTCTRL , BOTH, XKB_KEY_Control_L, // Latch Control
NEXT, KEY_LEFTALT , BOTH, XKB_KEY_Alt_L , // Latch Alt
NEXT, KEY_1 , BOTH, XKB_KEY_plus , // Unlatch Control, Unlatch Lock, Unlatch Alt
NEXT, KEY_Q , BOTH, XKB_KEY_q ,

NEXT, KEY_LEFTALT , BOTH, XKB_KEY_Alt_L , // Latch Alt
NEXT, KEY_RIGHTSHIFT, BOTH, XKB_KEY_Shift_R , // Latch Lock, unlatch Alt
NEXT, KEY_LEFTCTRL , BOTH, XKB_KEY_Control_L, // Latch Control
NEXT, KEY_1 , BOTH, XKB_KEY_1 , // Unlatch Control, Unlatch Lock
NEXT, KEY_Q , BOTH, XKB_KEY_q ,

NEXT, KEY_LEFTALT , BOTH, XKB_KEY_Alt_L , // Latch Alt
NEXT, KEY_LEFTCTRL , BOTH, XKB_KEY_Control_L, // Latch Control
NEXT, KEY_RIGHTSHIFT, BOTH, XKB_KEY_Shift_R , // Latch Lock, Unlatch Control, Unlatch Alt
NEXT, KEY_1 , BOTH, XKB_KEY_1 , // Unlatch Lock
NEXT, KEY_Q , BOTH, XKB_KEY_q ,

NEXT, KEY_LEFTALT , BOTH, XKB_KEY_Alt_L , // Latch Alt
NEXT, KEY_LEFTCTRL , BOTH, XKB_KEY_Control_L, // Latch Control
NEXT, KEY_RIGHTSHIFT, BOTH, XKB_KEY_Shift_R , // Latch Lock, Unlatch Control, Unlatch Alt
NEXT, KEY_Q , BOTH, XKB_KEY_Q , // Unlatch Lock
NEXT, KEY_Q , BOTH, XKB_KEY_q ,

FINISH));

xkb_keymap_unref(keymap);
}

int
main(void)
{
Expand All @@ -377,6 +450,7 @@ main(void)

test_group_latch(ctx);
test_explicit_actions(ctx);
test_latch_mod_cancel(ctx);

keymap = test_compile_rules(ctx, "evdev", "evdev",
"us,il,ru,de", ",,phonetic,neo",
Expand Down

0 comments on commit 801c873

Please sign in to comment.