Skip to content

Commit aab6425

Browse files
committed
actions: Add support for multiple actions per level
1 parent bf1b7af commit aab6425

File tree

12 files changed

+573
-230
lines changed

12 files changed

+573
-230
lines changed

src/keymap-priv.c

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ xkb_keymap_new(struct xkb_context *ctx,
7878
keymap->out_of_range_group_action = RANGE_WRAP;
7979
}
8080
log_err(ctx, 0, "xkb_keymap_new: flags: %d, out_of_range_group_action=%u\n", flags, keymap->out_of_range_group_action);
81+
8182
update_builtin_keymap_fields(keymap);
8283

8384
return keymap;
@@ -160,6 +161,20 @@ XkbLevelsSameSyms(const struct xkb_level *a, const struct xkb_level *b)
160161
return memcmp(a->s.syms, b->s.syms, sizeof(*a->s.syms) * a->num_syms) == 0;
161162
}
162163

164+
bool
165+
XkbLevelHasNoAction(const struct xkb_level *level)
166+
{
167+
if (level->num_syms == 0)
168+
return true;
169+
if (level->num_syms == 1)
170+
return level->a.action.type == ACTION_TYPE_NONE;
171+
for (unsigned int k = 0; k < level->num_syms; k++) {
172+
if (level->a.actions[k].type != ACTION_TYPE_NONE)
173+
return false;
174+
}
175+
return true;
176+
}
177+
163178
xkb_layout_index_t
164179
XkbWrapGroupIntoRange(int32_t group,
165180
xkb_layout_index_t num_groups,
@@ -196,3 +211,41 @@ XkbWrapGroupIntoRange(int32_t group,
196211
return group % num_groups;
197212
}
198213
}
214+
215+
unsigned int
216+
xkb_keymap_key_get_actions_by_level(struct xkb_keymap *keymap,
217+
xkb_keycode_t kc,
218+
xkb_layout_index_t layout,
219+
xkb_level_index_t level,
220+
const union xkb_action **actions)
221+
{
222+
const struct xkb_key *key = XkbKey(keymap, kc);
223+
unsigned int count;
224+
225+
if (!key)
226+
goto err;
227+
228+
layout = XkbWrapGroupIntoRange(layout, key->num_groups,
229+
key->out_of_range_group_action,
230+
key->out_of_range_group_number);
231+
if (layout == XKB_LAYOUT_INVALID)
232+
goto err;
233+
234+
if (level >= XkbKeyNumLevels(key, layout))
235+
goto err;
236+
237+
count = key->groups[layout].levels[level].num_syms;
238+
if (count == 0)
239+
goto err;
240+
241+
if (count == 1)
242+
*actions = &key->groups[layout].levels[level].a.action;
243+
else
244+
*actions = key->groups[layout].levels[level].a.actions;
245+
246+
return count;
247+
248+
err:
249+
*actions = NULL;
250+
return 0;
251+
}

src/keymap.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,10 @@ xkb_keymap_unref(struct xkb_keymap *keymap)
7575
for (unsigned i = 0; i < key->num_groups; i++) {
7676
if (key->groups[i].levels) {
7777
for (unsigned j = 0; j < XkbKeyNumLevels(key, i); j++)
78-
if (key->groups[i].levels[j].num_syms > 1)
78+
if (key->groups[i].levels[j].num_syms > 1) {
7979
free(key->groups[i].levels[j].s.syms);
80+
free(key->groups[i].levels[j].a.actions);
81+
}
8082
free(key->groups[i].levels);
8183
}
8284
}

src/keymap.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,12 +316,15 @@ enum xkb_explicit_components {
316316
};
317317

318318
struct xkb_level {
319-
union xkb_action action;
320319
unsigned int num_syms;
321320
union {
322321
xkb_keysym_t sym; /* num_syms == 1 */
323322
xkb_keysym_t *syms; /* num_syms > 1 */
324323
} s;
324+
union {
325+
union xkb_action action; /* num_syms == 1 */
326+
union xkb_action *actions; /* num_syms > 1 */
327+
} a;
325328
};
326329

327330
struct xkb_group {
@@ -476,6 +479,9 @@ XkbModNameToIndex(const struct xkb_mod_set *mods, xkb_atom_t name,
476479
bool
477480
XkbLevelsSameSyms(const struct xkb_level *a, const struct xkb_level *b);
478481

482+
bool
483+
XkbLevelHasNoAction(const struct xkb_level *level);
484+
479485
xkb_layout_index_t
480486
XkbWrapGroupIntoRange(int32_t group,
481487
xkb_layout_index_t num_groups,
@@ -485,6 +491,13 @@ XkbWrapGroupIntoRange(int32_t group,
485491
xkb_mod_mask_t
486492
mod_mask_get_effective(struct xkb_keymap *keymap, xkb_mod_mask_t mods);
487493

494+
unsigned int
495+
xkb_keymap_key_get_actions_by_level(struct xkb_keymap *keymap,
496+
xkb_keycode_t kc,
497+
xkb_layout_index_t layout,
498+
xkb_level_index_t level,
499+
const union xkb_action **actions);
500+
488501
struct xkb_keymap_format_ops {
489502
bool (*keymap_new_from_names)(struct xkb_keymap *keymap,
490503
const struct xkb_rule_names *names);

src/state.c

Lines changed: 97 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -176,23 +176,27 @@ xkb_state_key_get_layout(struct xkb_state *state, xkb_keycode_t kc)
176176
key->out_of_range_group_number);
177177
}
178178

179-
static const union xkb_action *
180-
xkb_key_get_action(struct xkb_state *state, const struct xkb_key *key)
179+
static unsigned int
180+
xkb_key_get_actions(struct xkb_state *state, const struct xkb_key *key,
181+
const union xkb_action **actions)
181182
{
182-
static const union xkb_action dummy = { .type = ACTION_TYPE_NONE };
183-
184183
xkb_layout_index_t layout;
185184
xkb_level_index_t level;
186185

187186
layout = xkb_state_key_get_layout(state, key->keycode);
188187
if (layout == XKB_LAYOUT_INVALID)
189-
return &dummy;
188+
goto err;
190189

191190
level = xkb_state_key_get_level(state, key->keycode, layout);
192191
if (level == XKB_LEVEL_INVALID)
193-
return &dummy;
192+
goto err;
194193

195-
return &key->groups[layout].levels[level].action;
194+
return xkb_keymap_key_get_actions_by_level(state->keymap, key->keycode,
195+
layout, level, actions);
196+
197+
err:
198+
*actions = NULL;
199+
return 0;
196200
}
197201

198202
static struct xkb_filter *
@@ -377,34 +381,37 @@ xkb_filter_group_latch_func(struct xkb_state *state,
377381
* keypress, then either break the latch if any random key is pressed,
378382
* or promote it to a lock or plain base set if it's the same
379383
* group delta & flags. */
380-
const union xkb_action *action = xkb_key_get_action(state, key);
381-
if (action->type == ACTION_TYPE_GROUP_LATCH &&
382-
action->group.group == filter->action.group.group &&
383-
action->group.flags == filter->action.group.flags) {
384-
filter->action = *action;
385-
if (filter->action.group.flags & ACTION_LATCH_TO_LOCK &&
386-
filter->action.group.group != 0) {
387-
/* Promote to lock */
388-
filter->action.type = ACTION_TYPE_GROUP_LOCK;
389-
filter->func = xkb_filter_group_lock_func;
390-
xkb_filter_group_lock_new(state, filter);
384+
const union xkb_action *actions = NULL;
385+
unsigned int count = xkb_key_get_actions(state, key, &actions);
386+
for (unsigned int k = 0; k < count; k++) {
387+
if (actions[k].type == ACTION_TYPE_GROUP_LATCH &&
388+
actions[k].group.group == filter->action.group.group &&
389+
actions[k].group.flags == filter->action.group.flags) {
390+
filter->action = actions[k];
391+
if (filter->action.group.flags & ACTION_LATCH_TO_LOCK &&
392+
filter->action.group.group != 0) {
393+
/* Promote to lock */
394+
filter->action.type = ACTION_TYPE_GROUP_LOCK;
395+
filter->func = xkb_filter_group_lock_func;
396+
xkb_filter_group_lock_new(state, filter);
397+
}
398+
else {
399+
/* Degrade to plain set */
400+
filter->action.type = ACTION_TYPE_GROUP_SET;
401+
filter->func = xkb_filter_group_set_func;
402+
xkb_filter_group_set_new(state, filter);
403+
}
404+
filter->key = key;
405+
state->components.latched_group -= priv.group_delta;
406+
/* XXX beep beep! */
407+
return XKB_FILTER_CONSUME;
391408
}
392-
else {
393-
/* Degrade to plain set */
394-
filter->action.type = ACTION_TYPE_GROUP_SET;
395-
filter->func = xkb_filter_group_set_func;
396-
xkb_filter_group_set_new(state, filter);
409+
else if (xkb_action_breaks_latch(&(actions[k]))) {
410+
/* Breaks the latch */
411+
state->components.latched_group = 0;
412+
filter->func = NULL;
413+
return XKB_FILTER_CONTINUE;
397414
}
398-
filter->key = key;
399-
state->components.latched_group -= priv.group_delta;
400-
/* XXX beep beep! */
401-
return XKB_FILTER_CONSUME;
402-
}
403-
else if (xkb_action_breaks_latch(action)) {
404-
/* Breaks the latch */
405-
state->components.latched_group = 0;
406-
filter->func = NULL;
407-
return XKB_FILTER_CONTINUE;
408415
}
409416
}
410417
else if (direction == XKB_KEY_UP && key == filter->key) {
@@ -533,32 +540,35 @@ xkb_filter_mod_latch_func(struct xkb_state *state,
533540
* keypress, then either break the latch if any random key is pressed,
534541
* or promote it to a lock or plain base set if it's the same
535542
* modifier. */
536-
const union xkb_action *action = xkb_key_get_action(state, key);
537-
if (action->type == ACTION_TYPE_MOD_LATCH &&
538-
action->mods.flags == filter->action.mods.flags &&
539-
action->mods.mods.mask == filter->action.mods.mods.mask) {
540-
filter->action = *action;
541-
if (filter->action.mods.flags & ACTION_LATCH_TO_LOCK) {
542-
filter->action.type = ACTION_TYPE_MOD_LOCK;
543-
filter->func = xkb_filter_mod_lock_func;
544-
state->components.locked_mods |= filter->action.mods.mods.mask;
543+
const union xkb_action *actions = NULL;
544+
unsigned int count = xkb_key_get_actions(state, key, &actions);
545+
for (unsigned int k = 0; k < count; k++) {
546+
if (actions[k].type == ACTION_TYPE_MOD_LATCH &&
547+
actions[k].mods.flags == filter->action.mods.flags &&
548+
actions[k].mods.mods.mask == filter->action.mods.mods.mask) {
549+
filter->action = actions[k];
550+
if (filter->action.mods.flags & ACTION_LATCH_TO_LOCK) {
551+
filter->action.type = ACTION_TYPE_MOD_LOCK;
552+
filter->func = xkb_filter_mod_lock_func;
553+
state->components.locked_mods |= filter->action.mods.mods.mask;
554+
}
555+
else {
556+
filter->action.type = ACTION_TYPE_MOD_SET;
557+
filter->func = xkb_filter_mod_set_func;
558+
state->set_mods = filter->action.mods.mods.mask;
559+
}
560+
filter->key = key;
561+
state->components.latched_mods &= ~filter->action.mods.mods.mask;
562+
/* XXX beep beep! */
563+
return XKB_FILTER_CONSUME;
545564
}
546-
else {
547-
filter->action.type = ACTION_TYPE_MOD_SET;
548-
filter->func = xkb_filter_mod_set_func;
549-
state->set_mods = filter->action.mods.mods.mask;
565+
else if (xkb_action_breaks_latch(&(actions[k]))) {
566+
/* XXX: This may be totally broken, we might need to break the
567+
* latch in the next run after this press? */
568+
state->components.latched_mods &= ~filter->action.mods.mods.mask;
569+
filter->func = NULL;
570+
return XKB_FILTER_CONTINUE;
550571
}
551-
filter->key = key;
552-
state->components.latched_mods &= ~filter->action.mods.mods.mask;
553-
/* XXX beep beep! */
554-
return XKB_FILTER_CONSUME;
555-
}
556-
else if (xkb_action_breaks_latch(action)) {
557-
/* XXX: This may be totally broken, we might need to break the
558-
* latch in the next run after this press? */
559-
state->components.latched_mods &= ~filter->action.mods.mods.mask;
560-
filter->func = NULL;
561-
return XKB_FILTER_CONTINUE;
562572
}
563573
}
564574
else if (direction == XKB_KEY_UP && key == filter->key) {
@@ -631,7 +641,8 @@ xkb_filter_apply_all(struct xkb_state *state,
631641
enum xkb_key_direction direction)
632642
{
633643
struct xkb_filter *filter;
634-
const union xkb_action *action;
644+
const union xkb_action *actions = NULL;
645+
unsigned int count;
635646
bool consumed;
636647

637648
/* First run through all the currently active filters and see if any of
@@ -648,28 +659,38 @@ xkb_filter_apply_all(struct xkb_state *state,
648659
return;
649660

650661
/* No filter consumed this event, so proceed with the key action */
651-
action = xkb_key_get_action(state, key);
652-
653-
/*
654-
* It's possible for the keymap to set action->type explicitly, like so:
655-
* interpret XF86_Next_VMode {
656-
* action = Private(type=0x86, data="+VMode");
657-
* };
658-
* We don't handle those.
659-
*/
660-
if (action->type >= _ACTION_TYPE_NUM_ENTRIES)
661-
return;
662+
count = xkb_key_get_actions(state, key, &actions);
663+
664+
for (unsigned int k = 0; k < count; k++) {
665+
/* FIXME: remove debug */
666+
if (count > 1) {
667+
log_vrb(
668+
state->keymap->ctx, 0, 0,
669+
"xkb_filter_apply_all: key: %u, index: %u, action type: %d\n",
670+
key->keycode, k, actions[k].type
671+
);
672+
}
673+
/*
674+
* It's possible for the keymap to set action->type explicitly, like so:
675+
* interpret XF86_Next_VMode {
676+
* action = Private(type=0x86, data="+VMode");
677+
* };
678+
* We don't handle those.
679+
*/
680+
if (actions[k].type >= _ACTION_TYPE_NUM_ENTRIES)
681+
return;
662682

663683
/* Return if no corresponding action */
664-
if (!filter_action_funcs[action->type].new)
665-
return;
684+
if (!filter_action_funcs[actions[k].type].new)
685+
return;
666686

667687
/* Add a new filter and run the corresponding initial action */
668-
filter = xkb_filter_new(state);
669-
filter->key = key;
670-
filter->func = filter_action_funcs[action->type].func;
671-
filter->action = *action;
672-
filter_action_funcs[action->type].new(state, filter);
688+
filter = xkb_filter_new(state);
689+
filter->key = key;
690+
filter->func = filter_action_funcs[actions[k].type].func;
691+
filter->action = actions[k];
692+
filter_action_funcs[actions[k].type].new(state, filter);
693+
}
673694
}
674695

675696
XKB_EXPORT struct xkb_state *

src/x11/keymap.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -529,7 +529,7 @@ get_actions(struct xkb_keymap *keymap, xcb_connection_t *conn,
529529
xcb_xkb_action_t *wire_action = acts_iter.data;
530530

531531
if (level < key->groups[group].type->num_levels) {
532-
union xkb_action *action = &key->groups[group].levels[level].action;
532+
union xkb_action *action = &key->groups[group].levels[level].a.action;
533533

534534
translate_action(action, wire_action);
535535
}

0 commit comments

Comments
 (0)