Skip to content

Commit

Permalink
state: support querying whether virtual modifiers are active
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
bluetech committed Jun 9, 2016
1 parent 0dd610f commit 1389662
Show file tree
Hide file tree
Showing 8 changed files with 35 additions and 23 deletions.
2 changes: 1 addition & 1 deletion src/keymap.h
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
8 changes: 5 additions & 3 deletions src/state.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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;
Expand Down
6 changes: 3 additions & 3 deletions src/x11/keymap.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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:
Expand All @@ -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:
Expand Down
4 changes: 2 additions & 2 deletions src/xkbcomp/action.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand All @@ -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;
}

Expand Down
2 changes: 1 addition & 1 deletion src/xkbcomp/keymap-dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
8 changes: 4 additions & 4 deletions src/xkbcomp/keymap.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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)
Expand Down
19 changes: 13 additions & 6 deletions test/state.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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);

Expand Down
9 changes: 6 additions & 3 deletions xkbcommon/xkbcommon-names.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down

0 comments on commit 1389662

Please sign in to comment.