Commit a1f0595a683a167901a2f1d9f02b9b637bd762a6

Ran Benita 2014-08-18T20:27:07

state: make sure the mods are fully resolved after xkb_state_update_mask() Virtual modifiers can have "mappings" to real modifiers, e.g. NumLock may also set Mod2. In a normal turn of events, the various components (depressed, latched, locked, and consequently effective) include the mapped mods, because the masks are pre-resolved everywhere. However, xkb_state_update_mask() accepts arbitrary mod masks, which may not be resolved (if it comes from somewhere other than xkb_state_serialize_mods()). So let's always resolve them ourselves. Signed-off-by: Ran Benita <ran234@gmail.com>

diff --git a/src/state.c b/src/state.c
index 279a646..6613969 100644
--- a/src/state.c
+++ b/src/state.c
@@ -797,6 +797,27 @@ xkb_state_update_mask(struct xkb_state *state,
     state->components.latched_mods = latched_mods & mask;
     state->components.locked_mods = locked_mods & mask;
 
+    /* Make sure the mods are fully resolved - since we get arbitrary
+     * input, they might not be.
+     *
+     * It might seem more reasonable to do this only for components.mods
+     * in xkb_state_update_derived(), rather than for each component
+     * seperately.  That would allow to distinguish between "really"
+     * depressed mods (would be in MODS_DEPRESSED) and indirectly
+     * depressed to to a mapping (would only be in MODS_EFFECTIVE).
+     * However, the traditional behavior of xkb_state_update_key() is that
+     * if a vmod is depressed, its mappings are depressed with it; so we're
+     * expected to do the same here.  Also, LEDs (usually) look if a real
+     * mod is locked, not just effective; otherwise it won't be lit.
+     *
+     * We OR here because mod_mask_get_effective() drops vmods. */
+    state->components.base_mods |=
+        mod_mask_get_effective(state->keymap, state->components.base_mods);
+    state->components.latched_mods |=
+        mod_mask_get_effective(state->keymap, state->components.latched_mods);
+    state->components.locked_mods |=
+        mod_mask_get_effective(state->keymap, state->components.locked_mods);
+
     state->components.base_group = base_group;
     state->components.latched_group = latched_group;
     state->components.locked_group = locked_group;