Skip to content

Commit

Permalink
state: support querying whether virtual modifiers are active
Browse files Browse the repository at this point in the history
Previously it was not possible to query the status of virtual
modifiers with the following functions:
- xkb_state_mod_index_is_active
- xkb_state_mod_indices_are_active
- xkb_state_mod_name_is_active
- xkb_state_mod_names_are_active

Note that it may over match if some modifier mappings overlap.
For example, the default “us” PC layout maps “Alt” and “Meta”
to the real modifier “Mod1”; thus “Mod1”, “Alt” and “Meta”
modifiers will return the same result with these functions.
  • Loading branch information
wismill committed Jun 30, 2023
1 parent fc25e0f commit 4a33adc
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 16 deletions.
10 changes: 7 additions & 3 deletions include/xkbcommon/xkbcommon-names.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,13 @@
#define XKB_MOD_NAME_SHIFT "Shift"
#define XKB_MOD_NAME_CAPS "Lock"
#define XKB_MOD_NAME_CTRL "Control"
#define XKB_MOD_NAME_ALT "Mod1"
#define XKB_MOD_NAME_NUM "Mod2"
#define XKB_MOD_NAME_LOGO "Mod4"
#define XKB_MOD_NAME_ALT "Alt"
#define XKB_MOD_NAME_META "Meta"
#define XKB_MOD_NAME_LOGO "Super"
#define XKB_MOD_NAME_GUI "Super"
#define XKB_MOD_NAME_SUPER "Super"
#define XKB_MOD_NAME_HYPER "Hyper"
#define XKB_MOD_NAME_NUM "NumLock"

#define XKB_LED_NAME_CAPS "Caps Lock"
#define XKB_LED_NAME_NUM "Num Lock"
Expand Down
5 changes: 5 additions & 0 deletions src/keymap.h
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,11 @@ XkbWrapGroupIntoRange(int32_t group,
enum xkb_range_exceed_type out_of_range_group_action,
xkb_layout_index_t out_of_range_group_number);

static inline bool
is_real_mod(struct xkb_keymap *keymap, xkb_mod_index_t mod) {
return keymap->mods.mods[mod].type & MOD_REAL;
}

xkb_mod_mask_t
mod_mask_get_effective(struct xkb_keymap *keymap, xkb_mod_mask_t mods);

Expand Down
17 changes: 14 additions & 3 deletions src/state.c
Original file line number Diff line number Diff line change
Expand Up @@ -1138,7 +1138,14 @@ xkb_state_mod_index_is_active(struct xkb_state *state,
if (idx >= xkb_keymap_num_mods(state->keymap))
return -1;

return !!(xkb_state_serialize_mods(state, type) & (1u << idx));
if (is_real_mod(state->keymap, idx)) {
return !!(xkb_state_serialize_mods(state, type) & (1u << idx));
} else {
/* WARNING: this may over matches */
return !!((xkb_state_serialize_mods(state, type) &
state->keymap->mods.mods[idx].mapping) ==
state->keymap->mods.mods[idx].mapping);
}
}

/**
Expand Down Expand Up @@ -1186,7 +1193,9 @@ xkb_state_mod_indices_are_active(struct xkb_state *state,
ret = -1;
break;
}
wanted |= (1u << idx);
wanted |= is_real_mod(state->keymap, idx)
? (1u << idx)
: state->keymap->mods.mods[idx].mapping;
}
va_end(ap);

Expand Down Expand Up @@ -1237,7 +1246,9 @@ xkb_state_mod_names_are_active(struct xkb_state *state,
ret = -1;
break;
}
wanted |= (1u << idx);
wanted |= is_real_mod(state->keymap, idx)
? (1u << idx)
: state->keymap->mods.mods[idx].mapping;
}
va_end(ap);

Expand Down
77 changes: 67 additions & 10 deletions test/state.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,56 +126,104 @@ test_update_key(struct xkb_keymap *keymap)
print_state(state);
assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CTRL,
XKB_STATE_MODS_DEPRESSED) > 0);
assert(xkb_state_mod_name_is_active(state, "Mod1",
XKB_STATE_MODS_DEPRESSED) > 0);
assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_ALT,
XKB_STATE_MODS_DEPRESSED) > 0);
assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_META,
XKB_STATE_MODS_DEPRESSED) > 0);
assert(xkb_state_mod_names_are_active(state, XKB_STATE_MODS_DEPRESSED,
XKB_STATE_MATCH_ALL,
XKB_MOD_NAME_CTRL,
"Mod1",
XKB_MOD_NAME_ALT,
XKB_MOD_NAME_META,
NULL) > 0);
assert(xkb_state_mod_indices_are_active(state, XKB_STATE_MODS_DEPRESSED,
XKB_STATE_MATCH_ALL,
xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CTRL),
xkb_keymap_mod_get_index(keymap, "Mod1"),
xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_ALT),
xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_META),
XKB_MOD_INVALID) > 0);
assert(xkb_state_mod_names_are_active(state, XKB_STATE_MODS_DEPRESSED,
XKB_STATE_MATCH_ALL,
"Mod1",
NULL) == 0);
assert(xkb_state_mod_names_are_active(state, XKB_STATE_MODS_DEPRESSED,
XKB_STATE_MATCH_ALL,
XKB_MOD_NAME_ALT,
NULL) == 0);
assert(xkb_state_mod_names_are_active(state, XKB_STATE_MODS_DEPRESSED,
XKB_STATE_MATCH_ALL,
XKB_MOD_NAME_META,
NULL) == 0);
assert(xkb_state_mod_names_are_active(state, XKB_STATE_MODS_DEPRESSED,
XKB_STATE_MATCH_ALL |
XKB_STATE_MATCH_NON_EXCLUSIVE,
"Mod1",
NULL) > 0);
assert(xkb_state_mod_names_are_active(state, XKB_STATE_MODS_DEPRESSED,
XKB_STATE_MATCH_ALL |
XKB_STATE_MATCH_NON_EXCLUSIVE,
XKB_MOD_NAME_ALT,
NULL) > 0);
assert(xkb_state_mod_names_are_active(state, XKB_STATE_MODS_DEPRESSED,
XKB_STATE_MATCH_ALL |
XKB_STATE_MATCH_NON_EXCLUSIVE,
XKB_MOD_NAME_META,
NULL) > 0);
assert(xkb_state_mod_names_are_active(state, XKB_STATE_MODS_DEPRESSED,
(XKB_STATE_MATCH_ANY |
XKB_STATE_MATCH_NON_EXCLUSIVE),
"Mod1",
NULL) > 0);
assert(xkb_state_mod_names_are_active(state, XKB_STATE_MODS_DEPRESSED,
(XKB_STATE_MATCH_ANY |
XKB_STATE_MATCH_NON_EXCLUSIVE),
XKB_MOD_NAME_ALT,
NULL) > 0);
assert(xkb_state_mod_names_are_active(state, XKB_STATE_MODS_DEPRESSED,
(XKB_STATE_MATCH_ANY |
XKB_STATE_MATCH_NON_EXCLUSIVE),
XKB_MOD_NAME_META,
NULL) > 0);

/* RAlt down */
xkb_state_update_key(state, KEY_LEFTCTRL + EVDEV_OFFSET, XKB_KEY_UP);
fprintf(stderr, "dumping state for RAlt down:\n");
print_state(state);
assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CTRL,
XKB_STATE_MODS_EFFECTIVE) == 0);
assert(xkb_state_mod_name_is_active(state, "Mod1",
XKB_STATE_MODS_DEPRESSED) > 0);
assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_ALT,
XKB_STATE_MODS_DEPRESSED) > 0);
assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_META,
XKB_STATE_MODS_DEPRESSED) > 0);
assert(xkb_state_mod_names_are_active(state, XKB_STATE_MODS_DEPRESSED,
XKB_STATE_MATCH_ANY,
XKB_MOD_NAME_CTRL,
"Mod1",
XKB_MOD_NAME_ALT,
XKB_MOD_NAME_META,
NULL) > 0);
assert(xkb_state_mod_names_are_active(state, XKB_STATE_MODS_LATCHED,
XKB_STATE_MATCH_ANY,
XKB_MOD_NAME_CTRL,
"Mod1",
XKB_MOD_NAME_ALT,
XKB_MOD_NAME_META,
NULL) == 0);

/* none down */
xkb_state_update_key(state, KEY_RIGHTALT + EVDEV_OFFSET, XKB_KEY_UP);
assert(xkb_state_mod_name_is_active(state, "Mod1",
XKB_STATE_MODS_EFFECTIVE) == 0);
assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_ALT,
XKB_STATE_MODS_EFFECTIVE) == 0);
assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_META,
XKB_STATE_MODS_EFFECTIVE) == 0);

/* Caps locked */
xkb_state_update_key(state, KEY_CAPSLOCK + EVDEV_OFFSET, XKB_KEY_DOWN);
Expand All @@ -201,6 +249,8 @@ test_update_key(struct xkb_keymap *keymap)
XKB_STATE_MODS_LOCKED) > 0);
assert(xkb_state_mod_name_is_active(state, "Mod2",
XKB_STATE_MODS_LOCKED) > 0);
assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_NUM,
XKB_STATE_MODS_LOCKED) > 0);
num_syms = xkb_state_key_get_syms(state, KEY_KP1 + EVDEV_OFFSET, &syms);
assert(num_syms == 1 && syms[0] == XKB_KEY_KP_1);
assert(xkb_state_led_name_is_active(state, XKB_LED_NAME_NUM) > 0);
Expand Down Expand Up @@ -302,7 +352,7 @@ static void
test_update_mask_mods(struct xkb_keymap *keymap)
{
struct xkb_state *state = xkb_state_new(keymap);
xkb_mod_index_t caps, shift, num, alt, mod1, mod2;
xkb_mod_index_t caps, shift, num, alt, meta, mod1, mod2;
enum xkb_state_component changed;

assert(state);
Expand All @@ -315,6 +365,8 @@ test_update_mask_mods(struct xkb_keymap *keymap)
assert(num != XKB_MOD_INVALID);
alt = xkb_keymap_mod_get_index(keymap, "Alt");
assert(alt != XKB_MOD_INVALID);
meta = xkb_keymap_mod_get_index(keymap, "Meta");
assert(alt != XKB_MOD_INVALID);
mod1 = xkb_keymap_mod_get_index(keymap, "Mod1");
assert(mod1 != XKB_MOD_INVALID);
mod2 = xkb_keymap_mod_get_index(keymap, "Mod2");
Expand Down Expand Up @@ -346,6 +398,11 @@ test_update_mask_mods(struct xkb_keymap *keymap)
assert(xkb_state_serialize_mods(state, XKB_STATE_MODS_EFFECTIVE) ==
((1u << alt) | (1u << mod1)));

changed = xkb_state_update_mask(state, (1 << meta), 0, 0, 0, 0, 0);
assert(changed == (XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_EFFECTIVE));
assert(xkb_state_serialize_mods(state, XKB_STATE_MODS_EFFECTIVE) ==
((1u << meta) | (1u << mod1)));

changed = xkb_state_update_mask(state, 0, 0, (1 << num), 0, 0, 0);
assert(changed == (XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LOCKED |
XKB_STATE_MODS_EFFECTIVE | XKB_STATE_LEDS));
Expand Down Expand Up @@ -381,20 +438,20 @@ static void
test_consume(struct xkb_keymap *keymap)
{
struct xkb_state *state;
xkb_mod_index_t alt, shift, caps, ctrl, mod5;
xkb_mod_index_t shift, caps, ctrl, mod1, mod5;
xkb_mod_mask_t mask;

state = xkb_state_new(keymap);
assert(state);

alt = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_ALT);
assert(alt != XKB_MOD_INVALID);
shift = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_SHIFT);
assert(shift != XKB_MOD_INVALID);
caps = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CAPS);
assert(caps != XKB_MOD_INVALID);
ctrl = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CTRL);
assert(ctrl != XKB_MOD_INVALID);
mod1 = xkb_keymap_mod_get_index(keymap, "Mod1");
assert(mod1 != XKB_MOD_INVALID);
mod5 = xkb_keymap_mod_get_index(keymap, "Mod5");
assert(mod5 != XKB_MOD_INVALID);

Expand All @@ -407,10 +464,10 @@ test_consume(struct xkb_keymap *keymap)
print_state(state);

mask = xkb_state_serialize_mods(state, XKB_STATE_MODS_EFFECTIVE);
assert(mask == ((1U << alt) | (1U << shift)));
assert(mask == ((1U << mod1) | (1U << shift)));
mask = xkb_state_mod_mask_remove_consumed(state, KEY_EQUAL + EVDEV_OFFSET,
mask);
assert(mask == (1U << alt));
assert(mask == (1U << mod1));

/* Test get_consumed_mods() */
mask = xkb_state_key_get_consumed_mods(state, KEY_EQUAL + EVDEV_OFFSET);
Expand Down Expand Up @@ -450,16 +507,16 @@ test_consume(struct xkb_keymap *keymap)
assert(state);

mask = xkb_state_key_get_consumed_mods(state, KEY_F1 + EVDEV_OFFSET);
assert(mask == ((1U << shift) | (1U << alt) | (1U << ctrl) | (1U << mod5)));
assert(mask == ((1U << shift) | (1U << mod1) | (1U << ctrl) | (1U << mod5)));

/* Shift is preserved. */
xkb_state_update_key(state, KEY_LEFTSHIFT + EVDEV_OFFSET, XKB_KEY_DOWN);
mask = xkb_state_key_get_consumed_mods(state, KEY_F1 + EVDEV_OFFSET);
assert(mask == ((1U << alt) | (1U << ctrl) | (1U << mod5)));
assert(mask == ((1U << mod1) | (1U << ctrl) | (1U << mod5)));
xkb_state_update_key(state, KEY_LEFTSHIFT + EVDEV_OFFSET, XKB_KEY_UP);

mask = xkb_state_key_get_consumed_mods(state, KEY_F1 + EVDEV_OFFSET);
assert(mask == ((1U << shift) | (1U << alt) | (1U << ctrl) | (1U << mod5)));
assert(mask == ((1U << shift) | (1U << mod1) | (1U << ctrl) | (1U << mod5)));

xkb_state_unref(state);

Expand All @@ -479,7 +536,7 @@ test_consume(struct xkb_keymap *keymap)
xkb_state_update_key(state, KEY_LEFTALT + EVDEV_OFFSET, XKB_KEY_DOWN);
mask = xkb_state_key_get_consumed_mods2(state, KEY_F1 + EVDEV_OFFSET,
XKB_CONSUMED_MODE_GTK);
assert(mask == ((1U << alt) | (1U << ctrl)));
assert(mask == ((1U << mod1) | (1U << ctrl)));

xkb_state_unref(state);

Expand Down

0 comments on commit 4a33adc

Please sign in to comment.