Report which components of the state have changed
authorRan Benita <ran234@gmail.com>
Mon, 22 Oct 2012 19:00:57 +0000 (21:00 +0200)
committerRan Benita <ran234@gmail.com>
Mon, 22 Oct 2012 19:58:03 +0000 (21:58 +0200)
We add a return value to the xkb_state_update_key and
xkb_state_update_mask, which reports to the caller which of the state
components have changed as a result.

This restores the XKB functionality of the XkbStateNotify and
XkbIndicatorsStateNotify events. See:
http://www.x.org/releases/current/doc/kbproto/xkbproto.html#Events
It is quite useful in some situations. For example, it allows an
application to avoid doing some work if nothing of relevance in the
state has changed. Say, a keyboard layout applet. Also useful for
debugging.

The deltas themselves are not provided, because I can't see a use case.
If needed, it should be possible to add some API for that.

In xkbcommon, keymaps are immutable, so all of the other *Notify events
from XKB are irrelevant.

Signed-off-by: Ran Benita <ran234@gmail.com>
src/state.c
xkbcommon/xkbcommon.h

index 56a8667..c8e3147 100644 (file)
@@ -88,7 +88,11 @@ struct state_components {
 };
 
 struct xkb_state {
-    struct state_components cur;
+    /*
+     * Before updating the state, we keep a copy. This allows us to report
+     * which components of the state have changed.
+     */
+    struct state_components cur, prev;
 
     /*
      * At each event, we accumulate all the needed modifications to the base
@@ -96,6 +100,7 @@ struct xkb_state {
      */
     xkb_mod_mask_t set_mods;
     xkb_mod_mask_t clear_mods;
+
     /*
      * We mustn't clear a base modifier if there's another depressed key
      * which affects it, e.g. given this sequence
@@ -657,11 +662,39 @@ xkb_state_update_derived(struct xkb_state *state)
     xkb_state_led_update_all(state);
 }
 
+static enum xkb_state_component
+get_state_component_changes(const struct state_components *a,
+                            const struct state_components *b)
+{
+    xkb_mod_mask_t mask = 0;
+
+    if (a->group != b->group)
+        mask |= XKB_STATE_LAYOUT_EFFECTIVE;
+    if (a->base_group != b->base_group)
+        mask |= XKB_STATE_LAYOUT_DEPRESSED;
+    if (a->latched_group != b->latched_group)
+        mask |= XKB_STATE_LAYOUT_LATCHED;
+    if (a->locked_group != b->locked_group)
+        mask |= XKB_STATE_LAYOUT_LOCKED;
+    if (a->mods != b->mods)
+        mask |= XKB_STATE_MODS_EFFECTIVE;
+    if (a->base_mods != b->base_mods)
+        mask |= XKB_STATE_MODS_DEPRESSED;
+    if (a->latched_mods != b->latched_mods)
+        mask |= XKB_STATE_MODS_LATCHED;
+    if (a->locked_mods != b->locked_mods)
+        mask |= XKB_STATE_MODS_LOCKED;
+    if (a->leds != b->leds)
+        mask |= XKB_STATE_LEDS;
+
+    return mask;
+}
+
 /**
  * Given a particular key event, updates the state structure to reflect the
  * new modifiers.
  */
-XKB_EXPORT void
+XKB_EXPORT enum xkb_state_component
 xkb_state_update_key(struct xkb_state *state, xkb_keycode_t kc,
                      enum xkb_key_direction direction)
 {
@@ -670,7 +703,9 @@ xkb_state_update_key(struct xkb_state *state, xkb_keycode_t kc,
     const struct xkb_key *key = XkbKey(state->keymap, kc);
 
     if (!key)
-        return;
+        return 0;
+
+    state->prev = state->cur;
 
     state->set_mods = 0;
     state->clear_mods = 0;
@@ -697,6 +732,8 @@ xkb_state_update_key(struct xkb_state *state, xkb_keycode_t kc,
     }
 
     xkb_state_update_derived(state);
+
+    return get_state_component_changes(&state->prev, &state->cur);
 }
 
 /**
@@ -706,7 +743,7 @@ xkb_state_update_key(struct xkb_state *state, xkb_keycode_t kc,
  * lossy, and should only be used to update a slave state mirroring the
  * master, e.g. in a client/server window system.
  */
-XKB_EXPORT void
+XKB_EXPORT enum xkb_state_component
 xkb_state_update_mask(struct xkb_state *state,
                       xkb_mod_mask_t base_mods,
                       xkb_mod_mask_t latched_mods,
@@ -718,6 +755,8 @@ xkb_state_update_mask(struct xkb_state *state,
     xkb_mod_index_t num_mods;
     xkb_mod_index_t idx;
 
+    state->cur = state->prev;
+
     state->cur.base_mods = 0;
     state->cur.latched_mods = 0;
     state->cur.locked_mods = 0;
@@ -738,6 +777,8 @@ xkb_state_update_mask(struct xkb_state *state,
     state->cur.locked_group = locked_group;
 
     xkb_state_update_derived(state);
+
+    return get_state_component_changes(&state->prev, &state->cur);
 }
 
 /**
index 846b619..e9b324f 100644 (file)
@@ -965,14 +965,49 @@ enum xkb_key_direction {
 };
 
 /**
+ * Modifier and layout types for state objects.  This enum is bitmaskable,
+ * e.g. (XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED) is valid to
+ * exclude locked modifiers.
+ *
+ * In XKB, the DEPRESSED states are also known as 'base'.
+ */
+enum xkb_state_component {
+    /** Depressed modifiers, i.e. a key is physically holding them. */
+    XKB_STATE_MODS_DEPRESSED = (1 << 0),
+    /** Latched modifiers, i.e. will be unset after the next non-modifier
+     *  key press. */
+    XKB_STATE_MODS_LATCHED = (1 << 1),
+    /** Locked modifiers, i.e. will be unset after the key provoking the
+     *  lock has been pressed again. */
+    XKB_STATE_MODS_LOCKED = (1 << 2),
+    /** Effective modifiers, i.e. currently active and affect key
+     *  processing (derived from the other state components). */
+    XKB_STATE_MODS_EFFECTIVE = (1 << 3),
+    /** Depressed layout, i.e. a key is physically holding it. */
+    XKB_STATE_LAYOUT_DEPRESSED = (1 << 4),
+    /** Latched layout, i.e. will be unset after the next non-modifier
+     *  key press. */
+    XKB_STATE_LAYOUT_LATCHED = (1 << 5),
+    /** Locked layout, i.e. will be unset after the key provoking the lock
+     *  has been pressed again. */
+    XKB_STATE_LAYOUT_LOCKED = (1 << 6),
+    /** Effective layout, i.e. currently active and affects key processing
+     *  (derived from the other state components). */
+    XKB_STATE_LAYOUT_EFFECTIVE = (1 << 7),
+    /** LEDs (derived from the other state components). */
+    XKB_STATE_LEDS = (1 << 8),
+};
+
+/**
  * Update the keyboard state to reflect a given key being pressed or
  * released.
  *
- * @todo Explain.
+ * @returns A mask of state components that have changed as a result of
+ * the update.  If nothing in the state has changed, returns 0.
  *
  * @memberof xkb_state
  */
-void
+enum xkb_state_component
 xkb_state_update_key(struct xkb_state *state, xkb_keycode_t key,
                      enum xkb_key_direction direction);
 
@@ -1101,40 +1136,6 @@ xkb_keymap_key_get_syms_by_level(struct xkb_keymap *keymap,
                                  const xkb_keysym_t **syms_out);
 
 /**
- * Modifier and layout types for state objects.  This enum is bitmaskable,
- * e.g. (XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED) is valid to
- * exclude locked modifiers.
- *
- * In XKB, the DEPRESSED states are also known as 'base'.
- */
-enum xkb_state_component {
-    /** Depressed modifiers, i.e. a key is physically holding them. */
-    XKB_STATE_MODS_DEPRESSED = (1 << 0),
-    /** Latched modifiers, i.e. will be unset after the next non-modifier
-     *  key press. */
-    XKB_STATE_MODS_LATCHED = (1 << 1),
-    /** Locked modifiers, i.e. will be unset after the key provoking the
-     *  lock has been pressed again. */
-    XKB_STATE_MODS_LOCKED = (1 << 2),
-    /** Effective modifiers, i.e. currently active and affect key
-     *  processing (derived from the other state components). */
-    XKB_STATE_MODS_EFFECTIVE = (1 << 3),
-    /** Depressed layout, i.e. a key is physically holding it. */
-    XKB_STATE_LAYOUT_DEPRESSED = (1 << 4),
-    /** Latched layout, i.e. will be unset after the next non-modifier
-     *  key press. */
-    XKB_STATE_LAYOUT_LATCHED = (1 << 5),
-    /** Locked layout, i.e. will be unset after the key provoking the lock
-     *  has been pressed again. */
-    XKB_STATE_LAYOUT_LOCKED = (1 << 6),
-    /** Effective layout, i.e. currently active and affects key processing
-     *  (derived from the other state components). */
-    XKB_STATE_LAYOUT_EFFECTIVE = (1 << 7),
-    /** LEDs (derived from the other state components). */
-    XKB_STATE_LEDS = (1 << 8),
-};
-
-/**
  * Match flags for xkb_state_mod_indices_are_active and
  * xkb_state_mod_names_are_active, specifying how the conditions for a
  * successful match.  XKB_STATE_MATCH_NON_EXCLUSIVE is bitmaskable with
@@ -1167,11 +1168,16 @@ enum xkb_state_match {
  *
  * Please do not use this unless you fit the description above.
  *
+ * @returns A mask of state components that have changed as a result of
+ * the update.  If nothing in the state has changed, returns 0.
+ *
  * @memberof xkb_state
  */
-void
-xkb_state_update_mask(struct xkb_state *state, xkb_mod_mask_t base_mods,
-                      xkb_mod_mask_t latched_mods, xkb_mod_mask_t locked_mods,
+enum xkb_state_component
+xkb_state_update_mask(struct xkb_state *state,
+                      xkb_mod_mask_t base_mods,
+                      xkb_mod_mask_t latched_mods,
+                      xkb_mod_mask_t locked_mods,
                       xkb_layout_index_t base_layout,
                       xkb_layout_index_t latched_layout,
                       xkb_layout_index_t locked_layout);