From 13896624c20462df713971ea5687db86a57452f7 Mon Sep 17 00:00:00 2001 From: Ran Benita Date: Sat, 24 Nov 2012 13:37:29 +0200 Subject: [PATCH] state: support querying whether virtual modifiers are active This allows the user to query directly whether "NumLock", "Super", "Meta", "Alt" etc. are active, rather than resorting to the real modifiers or just guessing. This should help e.g. toolkits which have things like Meta in the modifier masks they report. Demo: $ sudo ./test/interactive keysyms [ Caps_Lock ] unicode [ ] group [ English (US) (0) ] mods [ ] leds [ ] keysyms [ A ] unicode [ A ] group [ English (US) (0) ] mods [ -Lock ] leds [ Caps Lock ] keysyms [ Num_Lock ] unicode [ ] group [ English (US) (0) ] mods [ Lock ] leds [ Caps Lock ] keysyms [ KP_1 ] unicode [ 1 ] group [ English (US) (0) ] mods [ Lock -Mod2 -NumLock ] leds [ Caps Lock Num Lock ] keysyms [ Shift_R ] unicode [ ] group [ English (US) (0) ] mods [ Lock Mod2 NumLock ] leds [ Caps Lock Num Lock ] keysyms [ a ] unicode [ a ] group [ English (US) (0) ] mods [ Shift Lock Mod2 NumLock ] leds [ Caps Lock Num Lock ] keysyms [ Meta_L ] unicode [ ] group [ English (US) (0) ] mods [ -Shift Lock Mod2 NumLock ] leds [ Caps Lock Num Lock ] keysyms [ Meta_L ] unicode [ ] group [ English (US) (0) ] mods [ -Shift Lock Mod2 NumLock ] leds [ Caps Lock Num Lock ] keysyms [ a ] unicode [ a ] group [ English (US) (0) ] mods [ Shift Lock Mod1 Mod2 NumLock Alt Meta ] leds [ Caps Lock Num Lock ] keysyms [ Super_L ] unicode [ ] group [ English (US) (0) ] mods [ Shift Lock Mod1 Mod2 NumLock Alt Meta ] leds [ Caps Lock Num Lock ] keysyms [ a ] unicode [ a ] group [ English (US) (0) ] mods [ Shift Lock Mod1 Mod2 Mod4 NumLock Alt Meta Super ] leds [ Caps Lock Num Lock ] keysyms [ Control_L ] unicode [ ] group [ English (US) (0) ] mods [ Shift Lock Mod1 Mod2 Mod4 NumLock Alt Meta Super ] leds [ Caps Lock Num Lock ] keysyms [ a ] unicode [ a ] group [ English (US) (0) ] mods [ Shift Lock Control Mod1 Mod2 Mod4 NumLock Alt Meta Super ] leds [ Caps Lock Num Lock ] Previously, NumLock, Alt, Meta, Super would not be here. To facilitate this support, we also add #defines for the names of the Meta, Super, Hyper and NumLock modifiers. These are set freely in xkeyboard-config, but are essentially treated as ABI there. Also, the standard explicitly recommends the names for NumLock, Alt and Meta: http://www.x.org/releases/X11R7.6/doc/libX11/specs/XKB/xkblib.html#conventions We also change the define of Alt from "Mod1" to "Alt"; this is more correct, and safe. "Mod1" continues to work as before. One case that needs special consideration are the xkb_state_mod_indices_are_active() and mod_names_are_active() functions. By default, they perform an exclusive match on the modifiers that are passed to them. With virtual modifiers in the mix, you often get unexpected modifiers as well, which break it. I'm not really sure have exclusive-by-default is a good idea, because it also breaks when the user just pressed Num Lock of Caps Lock. However, for now we just revert to the old behavior of real-mods-only for these functions, which should be fine in most cases. We can revisit this later, when something more clever comes to mind. *** To get the virtual modifiers in, we essentially change just two things: 1. When SetMods/LockMods(modifiers=modMapMods) is used, we also add the modifiers in the key's vmodmap (in addition the key's modmap). The vmodmap of a key is set by virtualMod fields in interprets, or directly in the 'key' statements in xkb_symbols. It essentially contains the virtual modifiers that are bound to this key. 2. We no longer mask out virtual modifiers from the effective modifier masks in types, actions and indicators. This means mostly that if a type specifies e.g. "map[NumLock+LevelThree] = Level4", the active modifier mask in the state will in fact be matched against the NumLock and LevelThree modifiers. Together with 1, this works out nicely, and our tests all pass. Signed-off-by: Ran Benita --- src/keymap.h | 2 +- src/state.c | 8 +++++--- src/x11/keymap.c | 6 +++--- src/xkbcomp/action.c | 4 ++-- src/xkbcomp/keymap-dump.c | 2 +- src/xkbcomp/keymap.c | 8 ++++---- test/state.c | 19 +++++++++++++------ xkbcommon/xkbcommon-names.h | 9 ++++++--- 8 files changed, 35 insertions(+), 23 deletions(-) diff --git a/src/keymap.h b/src/keymap.h index 1093e4723..c193b5902 100644 --- a/src/keymap.h +++ b/src/keymap.h @@ -142,7 +142,7 @@ enum xkb_action_flags { ACTION_LATCH_TO_LOCK = (1 << 1), ACTION_LOCK_NO_LOCK = (1 << 2), ACTION_LOCK_NO_UNLOCK = (1 << 3), - ACTION_MODS_LOOKUP_MODMAP = (1 << 4), + ACTION_MODS_LOOKUP_MODMAPS = (1 << 4), ACTION_ABSOLUTE_SWITCH = (1 << 5), ACTION_ABSOLUTE_X = (1 << 6), ACTION_ABSOLUTE_Y = (1 << 7), diff --git a/src/state.c b/src/state.c index 8845a4e9e..883283b64 100644 --- a/src/state.c +++ b/src/state.c @@ -1111,8 +1111,7 @@ mod_mask_get_effective(struct xkb_keymap *keymap, xkb_mod_mask_t mods) xkb_mod_index_t i; xkb_mod_mask_t mask; - /* The effective mask is only real mods for now. */ - mask = mods & MOD_REAL_MASK_ALL; + mask = mods; xkb_mods_enumerate(i, mod, &keymap->mods) if (mods & (1u << i)) @@ -1146,7 +1145,10 @@ match_mod_masks(struct xkb_state *state, enum xkb_state_match match, xkb_mod_mask_t wanted) { - xkb_mod_mask_t active = xkb_state_serialize_mods(state, type); + xkb_mod_mask_t active; + + active = xkb_state_serialize_mods(state, type) & MOD_REAL_MASK_ALL; + wanted = mod_mask_get_effective(state->keymap, wanted) & MOD_REAL_MASK_ALL; if (!(match & XKB_STATE_MATCH_NON_EXCLUSIVE) && (active & ~wanted)) return false; diff --git a/src/x11/keymap.c b/src/x11/keymap.c index 0e7a89096..3e1af2b44 100644 --- a/src/x11/keymap.c +++ b/src/x11/keymap.c @@ -145,7 +145,7 @@ translate_action(union xkb_action *action, const xcb_xkb_action_t *wire) if (wire->setmods.flags & XCB_XKB_SA_LATCH_TO_LOCK) action->mods.flags |= ACTION_LATCH_TO_LOCK; if (wire->setmods.flags & XCB_XKB_SA_USE_MOD_MAP_MODS) - action->mods.flags |= ACTION_MODS_LOOKUP_MODMAP; + action->mods.flags |= ACTION_MODS_LOOKUP_MODMAPS; break; case XCB_XKB_SA_TYPE_LATCH_MODS: @@ -161,7 +161,7 @@ translate_action(union xkb_action *action, const xcb_xkb_action_t *wire) if (wire->latchmods.flags & XCB_XKB_SA_LATCH_TO_LOCK) action->mods.flags |= ACTION_LATCH_TO_LOCK; if (wire->latchmods.flags & XCB_XKB_SA_USE_MOD_MAP_MODS) - action->mods.flags |= ACTION_MODS_LOOKUP_MODMAP; + action->mods.flags |= ACTION_MODS_LOOKUP_MODMAPS; break; case XCB_XKB_SA_TYPE_LOCK_MODS: @@ -177,7 +177,7 @@ translate_action(union xkb_action *action, const xcb_xkb_action_t *wire) if (wire->lockmods.flags & XCB_XKB_SA_ISO_LOCK_FLAG_NO_UNLOCK) action->mods.flags |= ACTION_LOCK_NO_UNLOCK; if (wire->lockmods.flags & XCB_XKB_SA_USE_MOD_MAP_MODS) - action->mods.flags |= ACTION_MODS_LOOKUP_MODMAP; + action->mods.flags |= ACTION_MODS_LOOKUP_MODMAPS; break; case XCB_XKB_SA_TYPE_SET_GROUP: diff --git a/src/xkbcomp/action.c b/src/xkbcomp/action.c index 5f1fd6553..bef7d5471 100644 --- a/src/xkbcomp/action.c +++ b/src/xkbcomp/action.c @@ -266,7 +266,7 @@ CheckModifierField(struct xkb_context *ctx, const struct xkb_mod_set *mods, if (valStr && (istreq(valStr, "usemodmapmods") || istreq(valStr, "modmapmods"))) { *mods_rtrn = 0; - *flags_inout |= ACTION_MODS_LOOKUP_MODMAP; + *flags_inout |= ACTION_MODS_LOOKUP_MODMAPS; return true; } } @@ -275,7 +275,7 @@ CheckModifierField(struct xkb_context *ctx, const struct xkb_mod_set *mods, return ReportMismatch(ctx, action, ACTION_FIELD_MODIFIERS, "modifier mask"); - *flags_inout &= ~ACTION_MODS_LOOKUP_MODMAP; + *flags_inout &= ~ACTION_MODS_LOOKUP_MODMAPS; return true; } diff --git a/src/xkbcomp/keymap-dump.c b/src/xkbcomp/keymap-dump.c index d05a41033..4ec67c0d4 100644 --- a/src/xkbcomp/keymap-dump.c +++ b/src/xkbcomp/keymap-dump.c @@ -307,7 +307,7 @@ write_action(struct xkb_keymap *keymap, struct buf *buf, case ACTION_TYPE_MOD_SET: case ACTION_TYPE_MOD_LATCH: case ACTION_TYPE_MOD_LOCK: - if (action->mods.flags & ACTION_MODS_LOOKUP_MODMAP) + if (action->mods.flags & ACTION_MODS_LOOKUP_MODMAPS) args = "modMapMods"; else args = ModMaskText(keymap->ctx, &keymap->mods, diff --git a/src/xkbcomp/keymap.c b/src/xkbcomp/keymap.c index 45098c24a..2ae14443c 100644 --- a/src/xkbcomp/keymap.c +++ b/src/xkbcomp/keymap.c @@ -37,14 +37,14 @@ ComputeEffectiveMask(struct xkb_keymap *keymap, struct xkb_mods *mods) static void UpdateActionMods(struct xkb_keymap *keymap, union xkb_action *act, - xkb_mod_mask_t modmap) + xkb_mod_mask_t modmaps) { switch (act->type) { case ACTION_TYPE_MOD_SET: case ACTION_TYPE_MOD_LATCH: case ACTION_TYPE_MOD_LOCK: - if (act->mods.flags & ACTION_MODS_LOOKUP_MODMAP) - act->mods.mods.mods = modmap; + if (act->mods.flags & ACTION_MODS_LOOKUP_MODMAPS) + act->mods.mods.mods = modmaps; ComputeEffectiveMask(keymap, &act->mods.mods); break; default: @@ -204,7 +204,7 @@ UpdateDerivedKeymapFields(struct xkb_keymap *keymap) for (i = 0; i < key->num_groups; i++) for (j = 0; j < XkbKeyNumLevels(key, i); j++) UpdateActionMods(keymap, &key->groups[i].levels[j].action, - key->modmap); + key->modmap | key->vmodmap); /* Update vmod -> led maps. */ xkb_leds_foreach(led, keymap) diff --git a/test/state.c b/test/state.c index 8ae718c18..da5749e6d 100644 --- a/test/state.c +++ b/test/state.c @@ -379,7 +379,7 @@ 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 alt, shift, caps, ctrl, mod1, mod5, level_three; xkb_mod_mask_t mask; state = xkb_state_new(keymap); @@ -393,8 +393,12 @@ test_consume(struct xkb_keymap *keymap) 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); + level_three = xkb_keymap_mod_get_index(keymap, "LevelThree"); + assert(level_three != XKB_MOD_INVALID); /* Test remove_consumed() */ xkb_state_update_key(state, KEY_LEFTALT + EVDEV_OFFSET, XKB_KEY_DOWN); @@ -405,10 +409,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 << alt) | (1U << shift))) == ((1U << alt) | (1U << shift))); mask = xkb_state_mod_mask_remove_consumed(state, KEY_EQUAL + EVDEV_OFFSET, mask); - assert(mask == (1U << alt)); + assert((mask & ((1U << alt) | (1U << shift))) == (1U << alt)); /* Test get_consumed_mods() */ mask = xkb_state_key_get_consumed_mods(state, KEY_EQUAL + EVDEV_OFFSET); @@ -447,16 +451,19 @@ test_consume(struct xkb_keymap *keymap) state = xkb_state_new(keymap); 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 << alt) | (1U << ctrl) | + (1U << mod1) | (1U << mod5) | (1U << level_three))); /* 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 << alt) | (1U << ctrl) | (1U << mod1) | + (1U << mod5) | (1U << level_three))); 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 << alt) | (1U << ctrl) | + (1U << mod1) | (1U << mod5) | (1U << level_three))); assert(state); diff --git a/xkbcommon/xkbcommon-names.h b/xkbcommon/xkbcommon-names.h index ecb551ff1..db5806b39 100644 --- a/xkbcommon/xkbcommon-names.h +++ b/xkbcommon/xkbcommon-names.h @@ -34,9 +34,12 @@ #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_NUM "NumLock" +#define XKB_MOD_NAME_LOGO "Super" +#define XKB_MOD_NAME_SUPER "Super" +#define XKB_MOD_NAME_HYPER "Hyper" +#define XKB_MOD_NAME_META "Meta" #define XKB_LED_NAME_CAPS "Caps Lock" #define XKB_LED_NAME_NUM "Num Lock"