Skip to content

Commit

Permalink
state: Fix empty level not breaking latches
Browse files Browse the repository at this point in the history
In essence empty levels are levels with just a `NoSymbol` keysym and
a `NoAction()`, which breaks latches.

Fixed regression introduced in fdf2c52.

Added tests also for the case where the keycode is unknown.
  • Loading branch information
wismill committed Jan 27, 2025
1 parent eb9111c commit d424f16
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 19 deletions.
44 changes: 25 additions & 19 deletions src/state.c
Original file line number Diff line number Diff line change
Expand Up @@ -176,27 +176,36 @@ xkb_state_key_get_layout(struct xkb_state *state, xkb_keycode_t kc)
key->out_of_range_group_number);
}

/* Empty action used for empty levels */
static const union xkb_action dummy_action = { .type = ACTION_TYPE_NONE };

static unsigned int
xkb_key_get_actions(struct xkb_state *state, const struct xkb_key *key,
const union xkb_action **actions)
{
xkb_layout_index_t layout;
xkb_level_index_t level;

layout = xkb_state_key_get_layout(state, key->keycode);
const xkb_layout_index_t layout =
xkb_state_key_get_layout(state, key->keycode);
if (layout == XKB_LAYOUT_INVALID)
goto err;

level = xkb_state_key_get_level(state, key->keycode, layout);
const xkb_level_index_t level =
xkb_state_key_get_level(state, key->keycode, layout);
if (level == XKB_LEVEL_INVALID)
goto err;

return xkb_keymap_key_get_actions_by_level(state->keymap, key->keycode,
layout, level, actions);
const unsigned int count =
xkb_keymap_key_get_actions_by_level(state->keymap, key->keycode,
layout, level, actions);
if (!count)
goto err;

return count;

err:
*actions = NULL;
return 0;
/* Use a dummy action if no corresponding level was found or if it is empty.
* This is required e.g. to handle latches properly. */
*actions = &dummy_action;
return 1;
}

static struct xkb_filter *
Expand Down Expand Up @@ -379,7 +388,7 @@ xkb_filter_group_latch_func(struct xkb_state *state,
* or promote it to a lock if it's the same group delta & flags and
* latchToLock option is enabled. */
const union xkb_action *actions = NULL;
unsigned int count = xkb_key_get_actions(state, key, &actions);
const unsigned int count = xkb_key_get_actions(state, key, &actions);
for (unsigned int k = 0; k < count; k++) {
if (actions[k].type == ACTION_TYPE_GROUP_LATCH &&
actions[k].group.group == filter->action.group.group &&
Expand All @@ -398,7 +407,7 @@ xkb_filter_group_latch_func(struct xkb_state *state,
}
/* Do nothing if latchToLock option is not activated; if the
* latch is not broken by the following actions and the key is
* not consummed, then another latch filter will be created.
* not consumed, then another latch filter will be created.
*/
continue;
}
Expand Down Expand Up @@ -539,7 +548,7 @@ xkb_filter_mod_latch_func(struct xkb_state *state,
* or promote it to a lock or plain base set if it's the same
* modifier. */
const union xkb_action *actions = NULL;
unsigned int count = xkb_key_get_actions(state, key, &actions);
const unsigned int count = xkb_key_get_actions(state, key, &actions);
for (unsigned int k = 0; k < count; k++) {
if (actions[k].type == ACTION_TYPE_MOD_LATCH &&
actions[k].mods.flags == filter->action.mods.flags &&
Expand Down Expand Up @@ -638,14 +647,10 @@ xkb_filter_apply_all(struct xkb_state *state,
const struct xkb_key *key,
enum xkb_key_direction direction)
{
struct xkb_filter *filter;
const union xkb_action *actions = NULL;
unsigned int count;
bool consumed;

/* First run through all the currently active filters and see if any of
* them have consumed this event. */
consumed = false;
bool consumed = false;
struct xkb_filter *filter;
darray_foreach(filter, state->filters) {
if (!filter->func)
continue;
Expand All @@ -657,7 +662,8 @@ xkb_filter_apply_all(struct xkb_state *state,
return;

/* No filter consumed this event, so proceed with the key actions */
count = xkb_key_get_actions(state, key, &actions);
const union xkb_action *actions = NULL;
const unsigned int count = xkb_key_get_actions(state, key, &actions);

/*
* Process actions sequentially.
Expand Down
31 changes: 31 additions & 0 deletions test/keyseq.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,15 @@ test_group_latch(struct xkb_context *ctx)
KEY_COMPOSE, BOTH, XKB_KEY_ISO_Group_Latch, NEXT, \
KEY_H, BOTH, XKB_KEY_hebrew_yod, NEXT, \
KEY_H, BOTH, XKB_KEY_h, NEXT, \
/* Empty level breaks latches */ \
KEY_COMPOSE, BOTH, XKB_KEY_ISO_Group_Latch, NEXT, \
KEY_YEN, BOTH, XKB_KEY_NoSymbol, NEXT, \
KEY_H, BOTH, XKB_KEY_h, NEXT, \
/* Unknown key does not break latches */ \
KEY_COMPOSE, BOTH, XKB_KEY_ISO_Group_Latch, NEXT, \
UINT32_MAX, BOTH, XKB_KEY_NoSymbol, NEXT, \
KEY_H, BOTH, XKB_KEY_hebrew_yod, NEXT, \
KEY_H, BOTH, XKB_KEY_h, NEXT, \
/* Lock the second group */ \
KEY_SCROLLLOCK, BOTH, XKB_KEY_ISO_Next_Group, NEXT, \
KEY_H, BOTH, XKB_KEY_hebrew_yod, NEXT, \
Expand Down Expand Up @@ -317,6 +326,15 @@ test_group_latch(struct xkb_context *ctx)
KEY_COMPOSE, BOTH, XKB_KEY_ISO_Group_Latch, NEXT, \
KEY_H, BOTH, XKB_KEY_s, NEXT, \
KEY_H, BOTH, XKB_KEY_h, NEXT, \
/* Empty level breaks latches */ \
KEY_COMPOSE, BOTH, XKB_KEY_ISO_Group_Latch, NEXT, \
KEY_YEN, BOTH, XKB_KEY_NoSymbol, NEXT, \
KEY_H, BOTH, XKB_KEY_h, NEXT, \
/* Unknown key does not break latches */ \
KEY_COMPOSE, BOTH, XKB_KEY_ISO_Group_Latch, NEXT, \
UINT32_MAX, BOTH, XKB_KEY_NoSymbol, NEXT, \
KEY_H, BOTH, XKB_KEY_s, NEXT, \
KEY_H, BOTH, XKB_KEY_h, NEXT, \
/* Lock the second group */ \
KEY_SCROLLLOCK, BOTH, XKB_KEY_ISO_Next_Group, NEXT, \
KEY_H, BOTH, XKB_KEY_hebrew_yod, NEXT, \
Expand Down Expand Up @@ -470,6 +488,19 @@ test_mod_latch(struct xkb_context *context)
KEY_Q , BOTH, XKB_KEY_q , NEXT,
KEY_1 , BOTH, XKB_KEY_1 , NEXT,

/* Empty level */
KEY_LEFTSHIFT , DOWN, XKB_KEY_Shift_L , NEXT,
KEY_YEN , BOTH, XKB_KEY_NoSymbol, NEXT, /* Prevent latch */
KEY_LEFTSHIFT , UP, XKB_KEY_Shift_L , NEXT,
KEY_Q , BOTH, XKB_KEY_q , NEXT,

/* Unknown key */
KEY_LEFTSHIFT , DOWN, XKB_KEY_Shift_L , NEXT,
UINT32_MAX , BOTH, XKB_KEY_NoSymbol, NEXT, /* Does not prevent latch */
KEY_LEFTSHIFT , UP, XKB_KEY_Shift_L , NEXT,
KEY_1 , BOTH, XKB_KEY_exclam , NEXT,
KEY_Q , BOTH, XKB_KEY_q , NEXT,

KEY_LEFTSHIFT , DOWN, XKB_KEY_Shift_L, NEXT,
KEY_Q , BOTH, XKB_KEY_Q , NEXT, /* Prevent latch */
KEY_LEFTSHIFT , UP, XKB_KEY_Shift_L, NEXT,
Expand Down

0 comments on commit d424f16

Please sign in to comment.