From 31a841ae121ea5aa4879ed431bd83746460486d9 Mon Sep 17 00:00:00 2001 From: Pierre Le Marre Date: Mon, 14 Oct 2024 16:05:35 +0200 Subject: [PATCH] state: support querying whether virtual modifiers are active MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 *overmatch* if some modifier mappings overlap. For example, the default “us” PC layout maps both “Alt” and “Meta” to the real modifier “Mod1”; thus “Mod1”, “Alt” and “Meta” modifiers will return the same result with these functions. --- .../+query-virtual-modifiers-state.bugfix.md | 9 + include/xkbcommon/xkbcommon.h | 36 ++ src/keymap.h | 4 +- src/state.c | 41 +- test/data/rules/evdev | 2 + test/data/symbols/overlapping_modifiers | 15 + test/state.c | 510 ++++++++++++++---- 7 files changed, 516 insertions(+), 101 deletions(-) create mode 100644 changes/api/+query-virtual-modifiers-state.bugfix.md create mode 100644 test/data/symbols/overlapping_modifiers diff --git a/changes/api/+query-virtual-modifiers-state.bugfix.md b/changes/api/+query-virtual-modifiers-state.bugfix.md new file mode 100644 index 00000000..f2b72fc1 --- /dev/null +++ b/changes/api/+query-virtual-modifiers-state.bugfix.md @@ -0,0 +1,9 @@ +The following functions now allow to query also *virtual* modifiers, so they work +with *any* modifiers (real *and* virtual): +- `xkb_state_mod_index_is_active` +- `xkb_state_mod_indices_are_active` +- `xkb_state_mod_name_is_active` +- `xkb_state_mod_names_are_active` + +Warning: they may overmatch in case there are overlappings virtual-to-real +modifiers mappings. diff --git a/include/xkbcommon/xkbcommon.h b/include/xkbcommon/xkbcommon.h index da70fcb8..097dcbe7 100644 --- a/include/xkbcommon/xkbcommon.h +++ b/include/xkbcommon/xkbcommon.h @@ -1706,10 +1706,19 @@ xkb_state_serialize_layout(struct xkb_state *state, /** * Test whether a modifier is active in a given keyboard state by name. * + * @warning For [virtual modifiers], this function may *overmatch* in case + * there are virtual modifiers with overlapping mappings to [real modifiers]. + * * @returns 1 if the modifier is active, 0 if it is not. If the modifier * name does not exist in the keymap, returns -1. * * @memberof xkb_state + * + * @since 0.1.0: Works only with *real* modifiers + * @since 1.8.0: Works also with *virtual* modifiers + * + * [virtual modifiers]: @ref virtual-modifier-def + * [real modifiers]: @ref real-modifier-def */ int xkb_state_mod_name_is_active(struct xkb_state *state, const char *name, @@ -1719,6 +1728,9 @@ xkb_state_mod_name_is_active(struct xkb_state *state, const char *name, * Test whether a set of modifiers are active in a given keyboard state by * name. * + * @warning For [virtual modifiers], this function may *overmatch* in case + * there are virtual modifiers with overlapping mappings to [real modifiers]. + * * @param state The keyboard state. * @param type The component of the state against which to match the * given modifiers. @@ -1731,6 +1743,12 @@ xkb_state_mod_name_is_active(struct xkb_state *state, const char *name, * the modifier names do not exist in the keymap, returns -1. * * @memberof xkb_state + * + * @since 0.1.0: Works only with *real* modifiers + * @since 1.8.0: Works also with *virtual* modifiers + * + * [virtual modifiers]: @ref virtual-modifier-def + * [real modifiers]: @ref real-modifier-def */ int xkb_state_mod_names_are_active(struct xkb_state *state, @@ -1741,10 +1759,19 @@ xkb_state_mod_names_are_active(struct xkb_state *state, /** * Test whether a modifier is active in a given keyboard state by index. * + * @warning For [virtual modifiers], this function may *overmatch* in case + * there are virtual modifiers with overlapping mappings to [real modifiers]. + * * @returns 1 if the modifier is active, 0 if it is not. If the modifier * index is invalid in the keymap, returns -1. * * @memberof xkb_state + * + * @since 0.1.0: Works only with *real* modifiers + * @since 1.8.0: Works also with *virtual* modifiers + * + * [virtual modifiers]: @ref virtual-modifier-def + * [real modifiers]: @ref real-modifier-def */ int xkb_state_mod_index_is_active(struct xkb_state *state, xkb_mod_index_t idx, @@ -1754,6 +1781,9 @@ xkb_state_mod_index_is_active(struct xkb_state *state, xkb_mod_index_t idx, * Test whether a set of modifiers are active in a given keyboard state by * index. * + * @warning For [virtual modifiers], this function may *overmatch* in case + * there are virtual modifiers with overlapping mappings to [real modifiers]. + * * @param state The keyboard state. * @param type The component of the state against which to match the * given modifiers. @@ -1766,6 +1796,12 @@ xkb_state_mod_index_is_active(struct xkb_state *state, xkb_mod_index_t idx, * the modifier indices are invalid in the keymap, returns -1. * * @memberof xkb_state + * + * @since 0.1.0: Works only with *real* modifiers + * @since 1.8.0: Works also with *virtual* modifiers + * + * [virtual modifiers]: @ref virtual-modifier-def + * [real modifiers]: @ref real-modifier-def */ int xkb_state_mod_indices_are_active(struct xkb_state *state, diff --git a/src/keymap.h b/src/keymap.h index 57cebaf5..218a389e 100644 --- a/src/keymap.h +++ b/src/keymap.h @@ -104,10 +104,10 @@ #define XKB_MAX_GROUPS 4 /* Don't allow more modifiers than we can hold in xkb_mod_mask_t. */ -#define XKB_MAX_MODS ((xkb_mod_index_t) (sizeof(xkb_mod_mask_t) * 8)) +#define XKB_MAX_MODS ((xkb_mod_index_t) (sizeof(xkb_mod_mask_t) * CHAR_BIT)) /* Don't allow more leds than we can hold in xkb_led_mask_t. */ -#define XKB_MAX_LEDS ((xkb_led_index_t) (sizeof(xkb_led_mask_t) * 8)) +#define XKB_MAX_LEDS ((xkb_led_index_t) (sizeof(xkb_led_mask_t) * CHAR_BIT)) /* Special value to handle modMap None {…} */ #define XKB_MOD_NONE 0xffffffffU diff --git a/src/state.c b/src/state.c index 103ba4dd..651b788b 100644 --- a/src/state.c +++ b/src/state.c @@ -1265,6 +1265,17 @@ mod_mask_get_effective(struct xkb_keymap *keymap, xkb_mod_mask_t mods) return mask; } +/* Get the mapping of a modifier */ +static inline xkb_mod_mask_t +mod_mapping(struct xkb_mod *mod, xkb_mod_index_t idx) +{ + /* + * We cannot use `mod->mapping` directly, because it is + * not set for real modifiers. + */ + return (mod->type & MOD_REAL) ? (1u << idx) : mod->mapping; +} + /** * Returns 1 if the given modifier is active with the specified type(s), 0 if * not, or -1 if the modifier is invalid. @@ -1274,10 +1285,16 @@ xkb_state_mod_index_is_active(struct xkb_state *state, xkb_mod_index_t idx, enum xkb_state_component type) { - if (idx >= xkb_keymap_num_mods(state->keymap)) + if (unlikely(idx >= xkb_keymap_num_mods(state->keymap))) return -1; - return !!(xkb_state_serialize_mods(state, type) & (1u << idx)); + xkb_mod_mask_t mapping = mod_mapping(&state->keymap->mods.mods[idx], idx); + if (!mapping) { + /* Modifier not mapped */ + return 0; + } + /* WARNING: this may overmatch for virtual modifiers */ + return !!((xkb_state_serialize_mods(state, type) & mapping) == mapping); } /** @@ -1321,17 +1338,22 @@ xkb_state_mod_indices_are_active(struct xkb_state *state, xkb_mod_index_t idx = va_arg(ap, xkb_mod_index_t); if (idx == XKB_MOD_INVALID) break; - if (idx >= num_mods) { + if (unlikely(idx >= num_mods)) { ret = -1; break; } - wanted |= (1u << idx); + wanted |= mod_mapping(&state->keymap->mods.mods[idx], idx); } va_end(ap); if (ret == -1) return ret; + if (!wanted) { + /* Modifiers not mapped */ + return 0; + } + return match_mod_masks(state, type, match, wanted); } @@ -1376,13 +1398,18 @@ xkb_state_mod_names_are_active(struct xkb_state *state, ret = -1; break; } - wanted |= (1u << idx); + wanted |= mod_mapping(&state->keymap->mods.mods[idx], idx); } va_end(ap); if (ret == -1) return ret; + if (!wanted) { + /* Modifiers not mapped */ + return 0; + } + return match_mod_masks(state, type, match, wanted); } @@ -1392,8 +1419,8 @@ xkb_state_mod_names_are_active(struct xkb_state *state, */ XKB_EXPORT int xkb_state_layout_index_is_active(struct xkb_state *state, - xkb_layout_index_t idx, - enum xkb_state_component type) + xkb_layout_index_t idx, + enum xkb_state_component type) { int ret = 0; diff --git a/test/data/rules/evdev b/test/data/rules/evdev index fab0fa80..ea8652dd 100644 --- a/test/data/rules/evdev +++ b/test/data/rules/evdev @@ -1157,6 +1157,8 @@ lv5:lwin_switch_lock_cancel = +level5(lwin_switch_lock_cancel) lv5:rwin_switch_lock_cancel = +level5(rwin_switch_lock_cancel) parens:swap_brackets = +parens(swap_brackets) + overlapping_modifiers:super_hyper = +overlapping_modifiers(super_hyper) + overlapping_modifiers:meta = +overlapping_modifiers(meta) ! option = compat diff --git a/test/data/symbols/overlapping_modifiers b/test/data/symbols/overlapping_modifiers new file mode 100644 index 00000000..a65faf87 --- /dev/null +++ b/test/data/symbols/overlapping_modifiers @@ -0,0 +1,15 @@ +partial modifier_keys +xkb_symbols "super_hyper" { + key { + type[1] = "TWO_LEVEL", + symbols[1] = [ Super_L, Hyper_L ] + }; + modifier_map Mod3 { }; +}; +xkb_symbols "meta" { + key { + type[1] = "ONE_LEVEL", + symbols[1] = [ Meta_L ] + }; + modifier_map Mod3 { }; +}; diff --git a/test/state.c b/test/state.c index c44f28ad..3a698d8e 100644 --- a/test/state.c +++ b/test/state.c @@ -36,6 +36,14 @@ * keycode set (where ESC is 9). */ #define EVDEV_OFFSET 8 +static inline xkb_mod_index_t +_xkb_keymap_mod_get_index(struct xkb_keymap *keymap, const char *name) +{ + xkb_mod_index_t mod = xkb_keymap_mod_get_index(keymap, name); + assert(mod != XKB_MOD_INVALID); + return mod; +} + static void print_state(struct xkb_state *state) { @@ -113,6 +121,11 @@ test_update_key(struct xkb_keymap *keymap) assert(state); + xkb_mod_index_t ctrl = _xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CTRL); + xkb_mod_index_t mod1 = _xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_MOD1); + xkb_mod_index_t alt = _xkb_keymap_mod_get_index(keymap, XKB_VMOD_NAME_ALT); + xkb_mod_index_t meta = _xkb_keymap_mod_get_index(keymap, XKB_VMOD_NAME_META); + /* LCtrl down */ xkb_state_update_key(state, KEY_LEFTCTRL + EVDEV_OFFSET, XKB_KEY_DOWN); fprintf(stderr, "dumping state for LCtrl down:\n"); @@ -126,31 +139,64 @@ 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, XKB_MOD_NAME_ALT, + assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_MOD1, + XKB_STATE_MODS_DEPRESSED) > 0); + assert(xkb_state_mod_name_is_active(state, XKB_VMOD_NAME_ALT, + XKB_STATE_MODS_DEPRESSED) > 0); + assert(xkb_state_mod_name_is_active(state, XKB_VMOD_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, - XKB_MOD_NAME_ALT, + XKB_MOD_NAME_MOD1, + XKB_VMOD_NAME_ALT, + XKB_VMOD_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, XKB_MOD_NAME_ALT), + ctrl, mod1, alt, meta, XKB_MOD_INVALID) > 0); assert(xkb_state_mod_names_are_active(state, XKB_STATE_MODS_DEPRESSED, XKB_STATE_MATCH_ALL, - XKB_MOD_NAME_ALT, + XKB_MOD_NAME_MOD1, + NULL) == 0); + assert(xkb_state_mod_names_are_active(state, XKB_STATE_MODS_DEPRESSED, + XKB_STATE_MATCH_ALL, + XKB_VMOD_NAME_ALT, NULL) == 0); + assert(xkb_state_mod_names_are_active(state, XKB_STATE_MODS_DEPRESSED, + XKB_STATE_MATCH_ALL, + XKB_VMOD_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, + XKB_MOD_NAME_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, + XKB_VMOD_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_VMOD_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), + XKB_MOD_NAME_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_VMOD_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_ALT, + XKB_VMOD_NAME_META, NULL) > 0); /* RAlt down */ @@ -159,22 +205,34 @@ 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_EFFECTIVE) == 0); - assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_ALT, + assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_MOD1, + XKB_STATE_MODS_DEPRESSED) > 0); + assert(xkb_state_mod_name_is_active(state, XKB_VMOD_NAME_ALT, + XKB_STATE_MODS_DEPRESSED) > 0); + assert(xkb_state_mod_name_is_active(state, XKB_VMOD_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, - XKB_MOD_NAME_ALT, + XKB_MOD_NAME_MOD1, + XKB_VMOD_NAME_ALT, + XKB_VMOD_NAME_META, NULL) > 0); assert(xkb_state_mod_names_are_active(state, XKB_STATE_MODS_LATCHED, XKB_STATE_MATCH_ANY, XKB_MOD_NAME_CTRL, - XKB_MOD_NAME_ALT, + XKB_MOD_NAME_MOD1, + XKB_VMOD_NAME_ALT, + XKB_VMOD_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, XKB_MOD_NAME_ALT, + assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_MOD1, + XKB_STATE_MODS_EFFECTIVE) == 0); + assert(xkb_state_mod_name_is_active(state, XKB_VMOD_NAME_ALT, + XKB_STATE_MODS_EFFECTIVE) == 0); + assert(xkb_state_mod_name_is_active(state, XKB_VMOD_NAME_META, XKB_STATE_MODS_EFFECTIVE) == 0); /* Caps locked */ @@ -199,7 +257,9 @@ test_update_key(struct xkb_keymap *keymap) print_state(state); assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_CAPS, XKB_STATE_MODS_LOCKED) > 0); - assert(xkb_state_mod_name_is_active(state, "Mod2", + assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_MOD2, + XKB_STATE_MODS_LOCKED) > 0); + assert(xkb_state_mod_name_is_active(state, XKB_VMOD_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); @@ -245,6 +305,11 @@ test_update_key(struct xkb_keymap *keymap) xkb_state_unref(state); } +struct test_active_mods_entry { + xkb_mod_mask_t state; + xkb_mod_mask_t active; +}; + static void test_serialisation(struct xkb_keymap *keymap) { @@ -253,19 +318,42 @@ test_serialisation(struct xkb_keymap *keymap) xkb_mod_mask_t latched_mods; xkb_mod_mask_t locked_mods; xkb_mod_mask_t effective_mods; - xkb_mod_index_t caps, shift, ctrl; xkb_layout_index_t base_group = 0; xkb_layout_index_t latched_group = 0; xkb_layout_index_t locked_group = 0; assert(state); - caps = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CAPS); - assert(caps != XKB_MOD_INVALID); - shift = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_SHIFT); - assert(shift != XKB_MOD_INVALID); - ctrl = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CTRL); - assert(ctrl != XKB_MOD_INVALID); + xkb_mod_index_t shiftIdx = _xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_SHIFT); + xkb_mod_index_t capsIdx = _xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CAPS); + xkb_mod_index_t ctrlIdx = _xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CTRL); + xkb_mod_index_t mod1Idx = _xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_MOD1); + xkb_mod_index_t mod2Idx = _xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_MOD2); + xkb_mod_index_t mod3Idx = _xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_MOD3); + xkb_mod_index_t mod4Idx = _xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_MOD4); + xkb_mod_index_t mod5Idx = _xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_MOD5); + xkb_mod_index_t altIdx = _xkb_keymap_mod_get_index(keymap, XKB_VMOD_NAME_ALT); + xkb_mod_index_t metaIdx = _xkb_keymap_mod_get_index(keymap, XKB_VMOD_NAME_META); + xkb_mod_index_t superIdx = _xkb_keymap_mod_get_index(keymap, XKB_VMOD_NAME_SUPER); + xkb_mod_index_t hyperIdx = _xkb_keymap_mod_get_index(keymap, XKB_VMOD_NAME_HYPER); + xkb_mod_index_t numIdx = _xkb_keymap_mod_get_index(keymap, XKB_VMOD_NAME_NUM); + xkb_mod_index_t level3Idx = _xkb_keymap_mod_get_index(keymap, XKB_VMOD_NAME_LEVEL3); + xkb_mod_index_t altGrIdx = _xkb_keymap_mod_get_index(keymap, "AltGr"); + xkb_mod_mask_t shift = (1u << shiftIdx); + xkb_mod_mask_t caps = (1u << capsIdx); + xkb_mod_mask_t ctrl = (1u << ctrlIdx); + xkb_mod_mask_t mod1 = (1u << mod1Idx); + xkb_mod_mask_t mod2 = (1u << mod2Idx); + xkb_mod_mask_t mod3 = (1u << mod3Idx); + xkb_mod_mask_t mod4 = (1u << mod4Idx); + xkb_mod_mask_t mod5 = (1u << mod5Idx); + xkb_mod_mask_t alt = (1u << altIdx); + xkb_mod_mask_t meta = (1u << metaIdx); + xkb_mod_mask_t super = (1u << superIdx); + xkb_mod_mask_t hyper = (1u << hyperIdx); + xkb_mod_mask_t num = (1u << numIdx); + xkb_mod_mask_t level3 = (1u << level3Idx); + xkb_mod_mask_t altGr = (1u << altGrIdx); xkb_state_update_key(state, KEY_CAPSLOCK + EVDEV_OFFSET, XKB_KEY_DOWN); xkb_state_update_key(state, KEY_CAPSLOCK + EVDEV_OFFSET, XKB_KEY_UP); @@ -274,26 +362,76 @@ test_serialisation(struct xkb_keymap *keymap) latched_mods = xkb_state_serialize_mods(state, XKB_STATE_MODS_LATCHED); assert(latched_mods == 0); locked_mods = xkb_state_serialize_mods(state, XKB_STATE_MODS_LOCKED); - assert(locked_mods == (1U << caps)); + assert(locked_mods == caps); effective_mods = xkb_state_serialize_mods(state, XKB_STATE_MODS_EFFECTIVE); assert(effective_mods == locked_mods); xkb_state_update_key(state, KEY_LEFTSHIFT + EVDEV_OFFSET, XKB_KEY_DOWN); base_mods = xkb_state_serialize_mods(state, XKB_STATE_MODS_DEPRESSED); - assert(base_mods == (1U << shift)); + assert(base_mods == shift); latched_mods = xkb_state_serialize_mods(state, XKB_STATE_MODS_LATCHED); assert(latched_mods == 0); locked_mods = xkb_state_serialize_mods(state, XKB_STATE_MODS_LOCKED); - assert(locked_mods == (1U << caps)); + assert(locked_mods == caps); effective_mods = xkb_state_serialize_mods(state, XKB_STATE_MODS_EFFECTIVE); assert(effective_mods == (base_mods | locked_mods)); - base_mods |= (1U << ctrl); + base_mods |= ctrl; xkb_state_update_mask(state, base_mods, latched_mods, locked_mods, base_group, latched_group, locked_group); - assert(xkb_state_mod_index_is_active(state, ctrl, XKB_STATE_MODS_DEPRESSED) > 0); - assert(xkb_state_mod_index_is_active(state, ctrl, XKB_STATE_MODS_EFFECTIVE) > 0); + assert(xkb_state_mod_index_is_active(state, ctrlIdx, XKB_STATE_MODS_DEPRESSED) > 0); + assert(xkb_state_mod_index_is_active(state, ctrlIdx, XKB_STATE_MODS_EFFECTIVE) > 0); + + const struct test_active_mods_entry test_data[] = { + { .state = 0, .active = 0 }, + { .state = shift, .active = shift }, + { .state = caps, .active = caps }, + { .state = ctrl, .active = ctrl }, + { .state = mod1, .active = mod1 | alt | meta }, + { .state = mod2, .active = mod2 | num }, + { .state = mod3, .active = mod3 }, + { .state = mod4, .active = mod4 | super | hyper }, + { .state = mod5, .active = mod5 | level3 | altGr }, + { .state = shift | mod1, .active = shift | mod1 | alt | meta }, + { .state = shift | mod2, .active = shift | mod2 | num }, + }; + + for (unsigned k = 0; k < ARRAY_SIZE(test_data); k++) { + const struct test_active_mods_entry *entry = &test_data[k]; +#define check_mods(keymap, state, entry, type) \ + for (xkb_mod_index_t idx = 0; idx < xkb_keymap_num_mods(keymap); idx++) { \ + xkb_mod_mask_t mask = 1u << idx; \ + bool expected = !!(mask & entry->active); \ + bool got = !!xkb_state_mod_index_is_active(state, idx, type); \ + fprintf(stderr, "#%u State 0x%x, mod: %u: expected %u, got: %u\n", \ + k, entry->state, idx, expected, got); \ + assert_printf(got == expected, \ + "xkb_state_mod_index_is_active, " STRINGIFY2(type) "\n"); \ + got = !!xkb_state_mod_index_is_active(state, idx, \ + XKB_STATE_MODS_EFFECTIVE); \ + assert_printf(got == expected, "xkb_state_mod_index_is_active, " \ + STRINGIFY2(XKB_STATE_MODS_EFFECTIVE) "\n"); \ + got = !!xkb_state_mod_indices_are_active( \ + state, type, \ + XKB_STATE_MATCH_ALL | XKB_STATE_MATCH_NON_EXCLUSIVE, \ + idx, XKB_MOD_INVALID); \ + assert_printf(got == expected, "xkb_state_mod_indices_are_active, " \ + STRINGIFY2(type) "\n"); \ + got = !!xkb_state_mod_indices_are_active( \ + state, XKB_STATE_MODS_EFFECTIVE, \ + XKB_STATE_MATCH_ALL | XKB_STATE_MATCH_NON_EXCLUSIVE, \ + idx, XKB_MOD_INVALID); \ + assert_printf(got == expected, "xkb_state_mod_indices_are_active, " \ + STRINGIFY2(XKB_STATE_MODS_EFFECTIVE) "\n"); \ + } + xkb_state_update_mask(state, entry->state, 0, 0, 0, 0, 0); + check_mods(keymap, state, entry, XKB_STATE_MODS_DEPRESSED); + xkb_state_update_mask(state, 0, entry->state, 0, 0, 0, 0); + check_mods(keymap, state, entry, XKB_STATE_MODS_LATCHED); + xkb_state_update_mask(state, 0, 0, entry->state, 0, 0, 0); + check_mods(keymap, state, entry, XKB_STATE_MODS_LOCKED); + } xkb_state_unref(state); } @@ -301,68 +439,70 @@ test_serialisation(struct xkb_keymap *keymap) 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; enum xkb_state_component changed; - + struct xkb_state *state = xkb_state_new(keymap); assert(state); - caps = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CAPS); - assert(caps != XKB_MOD_INVALID); - shift = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_SHIFT); - assert(shift != XKB_MOD_INVALID); - num = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_NUM); - assert(num != XKB_MOD_INVALID); - alt = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_ALT); - assert(alt != XKB_MOD_INVALID); - mod1 = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_MOD1); - assert(mod1 != XKB_MOD_INVALID); - mod2 = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_MOD2); - assert(mod2 != XKB_MOD_INVALID); - - changed = xkb_state_update_mask(state, 1 << caps, 0, 0, 0, 0, 0); + xkb_mod_index_t capsIdx = _xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CAPS); + xkb_mod_index_t shiftIdx = _xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_SHIFT); + xkb_mod_index_t mod1Idx = _xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_MOD1); + xkb_mod_index_t mod2Idx = _xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_MOD2); + xkb_mod_index_t altIdx = _xkb_keymap_mod_get_index(keymap, XKB_VMOD_NAME_ALT); + xkb_mod_index_t metaIdx = _xkb_keymap_mod_get_index(keymap, XKB_VMOD_NAME_META); + xkb_mod_index_t numIdx = _xkb_keymap_mod_get_index(keymap, XKB_VMOD_NAME_NUM); + xkb_mod_mask_t caps = (1u << capsIdx); + xkb_mod_mask_t shift = (1u << shiftIdx); + xkb_mod_mask_t mod1 = (1u << mod1Idx); + xkb_mod_mask_t mod2 = (1u << mod2Idx); + xkb_mod_mask_t alt = (1u << altIdx); + xkb_mod_mask_t meta = (1u << metaIdx); + xkb_mod_mask_t num = (1u << numIdx); + + changed = xkb_state_update_mask(state, caps, 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 << caps)); + assert(xkb_state_serialize_mods(state, XKB_STATE_MODS_EFFECTIVE) == caps); - changed = xkb_state_update_mask(state, (1 << caps), 0, (1 << shift), 0, 0, 0); + changed = xkb_state_update_mask(state, caps, 0, shift, 0, 0, 0); assert(changed == (XKB_STATE_MODS_LOCKED | XKB_STATE_MODS_EFFECTIVE | XKB_STATE_LEDS)); assert(xkb_state_serialize_mods(state, XKB_STATE_MODS_EFFECTIVE) == - ((1u << caps) | (1u << shift))); - assert(xkb_state_serialize_mods(state, XKB_STATE_MODS_DEPRESSED) == - (1u << caps)); + (caps | shift)); + assert(xkb_state_serialize_mods(state, XKB_STATE_MODS_DEPRESSED) == caps); assert(xkb_state_serialize_mods(state, XKB_STATE_MODS_LATCHED) == 0); - assert(xkb_state_serialize_mods(state, XKB_STATE_MODS_LOCKED) == - (1u << shift)); + assert(xkb_state_serialize_mods(state, XKB_STATE_MODS_LOCKED) == shift); changed = xkb_state_update_mask(state, 0, 0, 0, 0, 0, 0); assert(changed == (XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LOCKED | XKB_STATE_MODS_EFFECTIVE | XKB_STATE_LEDS)); assert(xkb_state_serialize_mods(state, XKB_STATE_MODS_EFFECTIVE) == 0); - changed = xkb_state_update_mask(state, (1 << alt), 0, 0, 0, 0, 0); + changed = xkb_state_update_mask(state, alt, 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 << alt) | (1u << mod1))); + (alt | mod1)); - changed = xkb_state_update_mask(state, 0, 0, (1 << num), 0, 0, 0); + changed = xkb_state_update_mask(state, 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) == + (meta | mod1)); + + changed = xkb_state_update_mask(state, 0, 0, num, 0, 0, 0); assert(changed == (XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LOCKED | XKB_STATE_MODS_EFFECTIVE | XKB_STATE_LEDS)); assert(xkb_state_serialize_mods(state, XKB_STATE_MODS_EFFECTIVE) == - ((1u << num) | (1u << mod2))); + (num | mod2)); xkb_state_update_mask(state, 0, 0, 0, 0, 0, 0); - changed = xkb_state_update_mask(state, (1 << mod2), 0, (1 << num), 0, 0, 0); + changed = xkb_state_update_mask(state, mod2, 0, num, 0, 0, 0); assert(changed == (XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LOCKED | XKB_STATE_MODS_EFFECTIVE | XKB_STATE_LEDS)); assert(xkb_state_serialize_mods(state, XKB_STATE_MODS_EFFECTIVE) == - ((1u << mod2) | (1u << num))); + (mod2 | num)); assert(xkb_state_serialize_mods(state, XKB_STATE_MODS_DEPRESSED) == - (1u << mod2)); + mod2); assert(xkb_state_serialize_mods(state, XKB_STATE_MODS_LOCKED) == - ((1u << num) | (1u << mod2))); + (num | mod2)); xkb_state_unref(state); } @@ -380,24 +520,15 @@ test_repeat(struct xkb_keymap *keymap) static void test_consume(struct xkb_keymap *keymap) { - struct xkb_state *state; - xkb_mod_index_t alt, shift, caps, ctrl, mod5; xkb_mod_mask_t mask; - - state = xkb_state_new(keymap); + xkb_mod_index_t shift = _xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_SHIFT); + xkb_mod_index_t caps = _xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CAPS); + xkb_mod_index_t ctrl = _xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CTRL); + xkb_mod_index_t mod1 = _xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_MOD1); + xkb_mod_index_t mod5 = _xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_MOD5); + struct xkb_state *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); - mod5 = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_MOD5); - assert(mod5 != XKB_MOD_INVALID); - /* Test remove_consumed() */ xkb_state_update_key(state, KEY_LEFTALT + EVDEV_OFFSET, XKB_KEY_DOWN); xkb_state_update_key(state, KEY_LEFTSHIFT + EVDEV_OFFSET, XKB_KEY_DOWN); @@ -407,10 +538,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); @@ -450,16 +581,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); @@ -479,7 +610,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); @@ -499,6 +630,206 @@ test_consume(struct xkb_keymap *keymap) xkb_state_unref(state); } +static void +test_overlapping_mods(struct xkb_context *context) +{ + struct xkb_keymap *keymap; + struct xkb_state *state; + + /* Super and Hyper are overlapping (full overlap) */ + keymap = test_compile_rules(context, "evdev", NULL, "us", NULL, + "overlapping_modifiers:super_hyper"); + assert(keymap); + xkb_mod_index_t mod1Idx = _xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_MOD1); + xkb_mod_index_t mod3Idx = _xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_MOD3); + xkb_mod_index_t mod4Idx = _xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_MOD4); + xkb_mod_index_t altIdx = _xkb_keymap_mod_get_index(keymap, XKB_VMOD_NAME_ALT); + xkb_mod_index_t metaIdx = _xkb_keymap_mod_get_index(keymap, XKB_VMOD_NAME_META); + xkb_mod_index_t superIdx = _xkb_keymap_mod_get_index(keymap, XKB_VMOD_NAME_SUPER); + xkb_mod_index_t hyperIdx = _xkb_keymap_mod_get_index(keymap, XKB_VMOD_NAME_HYPER); + xkb_mod_mask_t mod1 = (1u << mod1Idx); + xkb_mod_mask_t mod3 = (1u << mod3Idx); + xkb_mod_mask_t mod4 = (1u << mod4Idx); + xkb_mod_mask_t alt = (1u << altIdx); + xkb_mod_mask_t meta = (1u << metaIdx); + xkb_mod_mask_t super = (1u << superIdx); + xkb_mod_mask_t hyper = (1u << hyperIdx); + state = xkb_state_new(keymap); + assert(state); + + const struct test_active_mods_entry test_data1[] = { + { .state = 0, .active = 0 }, + { .state = mod1, .active = mod1 | alt | meta }, + { .state = mod3, .active = mod3 }, + { .state = mod4, .active = mod4 }, + { .state = alt, .active = mod1 | alt | meta }, + { .state = meta, .active = mod1 | alt | meta }, + { .state = super, .active = mod3 | mod4 | super | hyper }, + { .state = hyper, .active = mod3 | mod4 | super | hyper }, + { .state = mod3 | mod4, .active = mod3 | mod4 | super | hyper }, + }; + + for (unsigned k = 0; k < ARRAY_SIZE(test_data1); k++) { + const struct test_active_mods_entry *entry = &test_data1[k]; + xkb_state_update_mask(state, entry->state, 0, 0, 0, 0, 0); + check_mods(keymap, state, entry, XKB_STATE_MODS_DEPRESSED); + } + assert(xkb_state_mod_indices_are_active(state, XKB_STATE_MODS_EFFECTIVE, + XKB_STATE_MATCH_ANY, + mod3Idx, mod4Idx, superIdx, hyperIdx, + XKB_MOD_INVALID) > 0); + assert(xkb_state_mod_indices_are_active(state, XKB_STATE_MODS_EFFECTIVE, + XKB_STATE_MATCH_ALL, + mod3Idx, mod4Idx, superIdx, hyperIdx, + XKB_MOD_INVALID) > 0); + xkb_state_unref(state); + xkb_keymap_unref(keymap); + + /* Super and Hyper are overlapping (full overlap). + * Alt overlaps with Meta (incomplete overlap) */ + keymap = test_compile_rules(context, "evdev", NULL, "us", NULL, + "overlapping_modifiers:meta"); + assert(keymap); + altIdx = _xkb_keymap_mod_get_index(keymap, XKB_VMOD_NAME_ALT); + metaIdx = _xkb_keymap_mod_get_index(keymap, XKB_VMOD_NAME_META); + superIdx = _xkb_keymap_mod_get_index(keymap, XKB_VMOD_NAME_SUPER); + hyperIdx = _xkb_keymap_mod_get_index(keymap, XKB_VMOD_NAME_HYPER); + alt = (1u << altIdx); + meta = (1u << metaIdx); + super = (1u << superIdx); + hyper = (1u << hyperIdx); + state = xkb_state_new(keymap); + assert(state); + + const struct test_active_mods_entry test_data2[] = { + { .state = 0, .active = 0 }, + { .state = mod1, .active = mod1 | alt }, + { .state = mod3, .active = mod3 }, + { .state = mod4, .active = mod4 | hyper | super }, + { .state = alt, .active = mod1 | alt }, + { .state = meta, .active = mod1 | mod3 | alt | meta }, + { .state = super, .active = mod4 | hyper | super }, + { .state = hyper, .active = mod4 | hyper | super }, + { .state = mod1 | mod3, .active = mod1 | mod3 | alt | meta }, + { .state = mod1 | mod4, .active = mod1 | mod4 | alt | super | hyper }, + { .state = mod3 | mod4, .active = mod3 | mod4 | super | hyper }, + { .state = mod1 | mod3 | mod4, .active = mod1 | mod3 | mod4 | alt | meta | super | hyper }, + }; + + for (unsigned k = 0; k < ARRAY_SIZE(test_data2); k++) { + const struct test_active_mods_entry *entry = &test_data2[k]; + xkb_state_update_mask(state, entry->state, 0, 0, 0, 0, 0); + check_mods(keymap, state, entry, XKB_STATE_MODS_DEPRESSED); + } + assert(xkb_state_mod_indices_are_active(state, XKB_STATE_MODS_EFFECTIVE, + XKB_STATE_MATCH_ANY, + mod1Idx, mod3Idx, mod4Idx, altIdx, + metaIdx, superIdx, hyperIdx, + XKB_MOD_INVALID) > 0); + assert(xkb_state_mod_indices_are_active(state, XKB_STATE_MODS_EFFECTIVE, + XKB_STATE_MATCH_ALL, + mod1Idx, mod3Idx, mod4Idx, altIdx, + metaIdx, superIdx, hyperIdx, + XKB_MOD_INVALID) > 0); + xkb_state_update_mask(state, mod1, 0, 0, 0, 0, 0); + assert(xkb_state_mod_indices_are_active(state, XKB_STATE_MODS_EFFECTIVE, + XKB_STATE_MATCH_ANY, + mod1Idx, altIdx, + XKB_MOD_INVALID) > 0); + assert(xkb_state_mod_indices_are_active(state, XKB_STATE_MODS_EFFECTIVE, + XKB_STATE_MATCH_ALL, + mod1Idx, altIdx, + XKB_MOD_INVALID) > 0); + xkb_state_update_mask(state, mod1 | mod3, 0, 0, 0, 0, 0); + assert(xkb_state_mod_indices_are_active(state, XKB_STATE_MODS_EFFECTIVE, + XKB_STATE_MATCH_ANY, + mod1Idx, mod3Idx, altIdx, metaIdx, + XKB_MOD_INVALID) > 0); + assert(xkb_state_mod_indices_are_active(state, XKB_STATE_MODS_EFFECTIVE, + XKB_STATE_MATCH_ALL, + mod1Idx, mod3Idx, altIdx, metaIdx, + XKB_MOD_INVALID) > 0); + xkb_state_unref(state); + xkb_keymap_unref(keymap); + + /* Super and Hyper overlaps with Meta; Alt overlaps with Meta */ + keymap = test_compile_rules(context, "evdev", NULL, "us", NULL, + "overlapping_modifiers:super_hyper," + "overlapping_modifiers:meta"); + assert(keymap); + altIdx = _xkb_keymap_mod_get_index(keymap, XKB_VMOD_NAME_ALT); + metaIdx = _xkb_keymap_mod_get_index(keymap, XKB_VMOD_NAME_META); + superIdx = _xkb_keymap_mod_get_index(keymap, XKB_VMOD_NAME_SUPER); + hyperIdx = _xkb_keymap_mod_get_index(keymap, XKB_VMOD_NAME_HYPER); + alt = (1u << altIdx); + meta = (1u << metaIdx); + super = (1u << superIdx); + hyper = (1u << hyperIdx); + state = xkb_state_new(keymap); + assert(state); + + const struct test_active_mods_entry test_data3[] = { + { .state = 0, .active = 0 }, + { .state = mod1, .active = mod1 | alt }, + { .state = mod3, .active = mod3 }, + { .state = mod4, .active = mod4 }, + { .state = alt, .active = mod1 | alt }, + { .state = meta, .active = mod1 | mod3 | alt | meta }, + { .state = super, .active = mod3 | mod4 | super | hyper }, + { .state = hyper, .active = mod3 | mod4 | super | hyper }, + { .state = mod1 | mod3, .active = mod1 | mod3 | alt | meta }, + { .state = mod1 | mod3, .active = mod1 | mod3 | alt | meta }, + { .state = mod1 | mod4, .active = mod1 | mod4 | alt }, + { .state = mod3 | mod4, .active = mod3 | mod4 | super | hyper }, + { .state = mod1 | mod3 | mod4, .active = mod1 | mod3 | mod4 | alt | meta | super | hyper }, + }; + + for (unsigned k = 0; k < ARRAY_SIZE(test_data3); k++) { + const struct test_active_mods_entry *entry = &test_data3[k]; + xkb_state_update_mask(state, entry->state, 0, 0, 0, 0, 0); + check_mods(keymap, state, entry, XKB_STATE_MODS_DEPRESSED); + } + assert(xkb_state_mod_indices_are_active(state, XKB_STATE_MODS_EFFECTIVE, + XKB_STATE_MATCH_ANY, + mod1Idx, mod3Idx, mod4Idx, altIdx, + metaIdx, superIdx, hyperIdx, + XKB_MOD_INVALID) > 0); + assert(xkb_state_mod_indices_are_active(state, XKB_STATE_MODS_EFFECTIVE, + XKB_STATE_MATCH_ALL, + mod1Idx, mod3Idx, mod4Idx, altIdx, + metaIdx, superIdx, hyperIdx, + XKB_MOD_INVALID) > 0); + xkb_state_update_mask(state, mod1 | mod3, 0, 0, 0, 0, 0); + assert(xkb_state_mod_indices_are_active(state, XKB_STATE_MODS_EFFECTIVE, + XKB_STATE_MATCH_ANY, + mod1Idx, mod3Idx, altIdx, metaIdx, + XKB_MOD_INVALID) > 0); + assert(xkb_state_mod_indices_are_active(state, XKB_STATE_MODS_EFFECTIVE, + XKB_STATE_MATCH_ALL, + mod1Idx, mod3Idx, altIdx, metaIdx, + XKB_MOD_INVALID) > 0); + xkb_state_update_mask(state, mod1 | mod4, 0, 0, 0, 0, 0); + assert(xkb_state_mod_indices_are_active(state, XKB_STATE_MODS_EFFECTIVE, + XKB_STATE_MATCH_ANY, + mod1Idx, mod4Idx, altIdx, + XKB_MOD_INVALID) > 0); + assert(xkb_state_mod_indices_are_active(state, XKB_STATE_MODS_EFFECTIVE, + XKB_STATE_MATCH_ALL, + mod1Idx, mod4Idx, altIdx, + XKB_MOD_INVALID) > 0); + xkb_state_update_mask(state, mod3 | mod4, 0, 0, 0, 0, 0); + assert(xkb_state_mod_indices_are_active(state, XKB_STATE_MODS_EFFECTIVE, + XKB_STATE_MATCH_ANY, + mod3Idx, mod4Idx, superIdx, hyperIdx, + XKB_MOD_INVALID) > 0); + assert(xkb_state_mod_indices_are_active(state, XKB_STATE_MODS_EFFECTIVE, + XKB_STATE_MATCH_ALL, + mod3Idx, mod4Idx, superIdx, hyperIdx, + XKB_MOD_INVALID) > 0); + xkb_state_unref(state); + xkb_keymap_unref(keymap); +} + static void key_iter(struct xkb_keymap *keymap, xkb_keycode_t key, void *data) { @@ -524,20 +855,16 @@ test_range(struct xkb_keymap *keymap) static void test_caps_keysym_transformation(struct xkb_keymap *keymap) { - struct xkb_state *state = xkb_state_new(keymap); - xkb_mod_index_t caps, shift; int nsyms; xkb_keysym_t sym; const xkb_keysym_t *syms; - + xkb_mod_index_t shift = _xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_SHIFT); + xkb_mod_index_t caps = _xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CAPS); + struct xkb_state *state = xkb_state_new(keymap); assert(state); /* See xkb_state_key_get_one_sym() for what's this all about. */ - caps = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CAPS); - shift = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_SHIFT); - assert(caps != XKB_MOD_INVALID && shift != XKB_MOD_INVALID); - assert(xkb_state_key_get_layout(state, KEY_A + EVDEV_OFFSET) == 0); assert(xkb_state_key_get_layout(state, KEY_SEMICOLON + EVDEV_OFFSET) == 0); @@ -667,15 +994,12 @@ static void test_ctrl_string_transformation(struct xkb_keymap *keymap) { char buf[256]; + xkb_mod_index_t ctrl = _xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CTRL); struct xkb_state *state = xkb_state_new(keymap); - xkb_mod_index_t ctrl; - assert(state); /* See xkb_state_key_get_utf8() for what's this all about. */ - ctrl = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CTRL); - assert(ctrl != XKB_MOD_INVALID); /* First without. */ TEST_KEY(KEY_A, "a", 0x61); @@ -714,7 +1038,7 @@ main(void) { test_init(); - struct xkb_context *context = test_get_context(0); + struct xkb_context *context = test_get_context(CONTEXT_NO_FLAG); struct xkb_keymap *keymap; assert(context); @@ -724,7 +1048,8 @@ main(void) xkb_keymap_unref(NULL); xkb_state_unref(NULL); - keymap = test_compile_rules(context, "evdev", "pc104", "us,ru", NULL, "grp:menu_toggle"); + keymap = test_compile_rules(context, "evdev", "pc104", "us,ru", NULL, + "grp:menu_toggle"); assert(keymap); test_update_key(keymap); @@ -735,6 +1060,7 @@ main(void) test_range(keymap); test_get_utf8_utf32(keymap); test_ctrl_string_transformation(keymap); + test_overlapping_mods(context); xkb_keymap_unref(keymap); keymap = test_compile_rules(context, "evdev", NULL, "ch", "fr", NULL);