Add multiple modifier state matching API
authorDaniel Stone <daniel@fooishbar.org>
Wed, 9 May 2012 00:06:10 +0000 (01:06 +0100)
committerDaniel Stone <daniel@fooishbar.org>
Wed, 9 May 2012 00:06:10 +0000 (01:06 +0100)
Two new calls allow users to test the exact modifier state, including
verifying that no other modifiers but the ones you wanted are down.

Signed-off-by: Daniel Stone <daniel@fooishbar.org>
include/xkbcommon/xkbcommon.h
src/state.c
test/state.c

index 0527143..dac14ec 100644 (file)
@@ -489,6 +489,22 @@ enum xkb_state_component {
 };
 
 /**
+ * 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
+ * the other modes.
+ */
+enum xkb_state_match {
+    /** Returns true if any of the modifiers are active. */
+    XKB_STATE_MATCH_ANY = (1 << 0),
+    /** Returns true if all of the modifiers are active. */
+    XKB_STATE_MATCH_ALL = (1 << 1),
+    /** Makes matching non-exclusive, i.e. will not return false if a
+     *  modifier not specified in the arguments is active. */
+    XKB_STATE_MATCH_NON_EXCLUSIVE = (1 << 16),
+};
+
+/**
  * Updates a state object from a set of explicit masks.  This entrypoint is
  * really only for window systems and the like, where a master process
  * holds an xkb_state, then serialises it over a wire protocol, and clients
@@ -537,13 +553,25 @@ xkb_state_serialise_group(struct xkb_state *state,
 /**
  * Returns 1 if the modifier specified by 'name' is active in the manner
  * specified by 'type', 0 if it is unset, or -1 if the modifier does not
- * exist in the current map.
+ * exist in the map.
  */
 int
 xkb_state_mod_name_is_active(struct xkb_state *state, const char *name,
                              enum xkb_state_component type);
 
 /**
+ * Returns 1 if the modifiers specified by the varargs (treated as
+ * NULL-terminated pointers to strings) are active in the manner
+ * specified by 'match', 0 otherwise, or -1 if any of the modifiers
+ * do not exist in the map.
+ */
+int
+xkb_state_mod_names_are_active(struct xkb_state *state,
+                               enum xkb_state_component type,
+                               enum xkb_state_match match,
+                               ...);
+
+/**
  * Returns 1 if the modifier specified by 'idx' is active in the manner
  * specified by 'type', 0 if it is unset, or -1 if the modifier does not
  * exist in the current map.
@@ -553,6 +581,18 @@ xkb_state_mod_index_is_active(struct xkb_state *state, xkb_mod_index_t idx,
                               enum xkb_state_component type);
 
 /**
+ * Returns 1 if the modifiers specified by the varargs (treated as
+ * xkb_mod_index_t, terminated with XKB_MOD_INVALID) are active in the manner
+ * specified by 'match' and 'type', 0 otherwise, or -1 if the modifier does not
+ * exist in the current map.
+ */
+int
+xkb_state_mod_indices_are_active(struct xkb_state *state,
+                                 enum xkb_state_component type,
+                                 enum xkb_state_match match,
+                                 ...);
+
+/**
  * Returns 1 if the group specified by 'name' is active in the manner
  * specified by 'type', 0 if it is unset, or -1 if the group does not
  * exist in the current map.
index 8bfe30d..5d731db 100644 (file)
@@ -59,6 +59,7 @@ THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
 #include <assert.h>
+#include <stdarg.h>
 
 #include "xkb-priv.h"
 
@@ -684,6 +685,59 @@ xkb_state_mod_index_is_active(struct xkb_state *state,
 }
 
 /**
+ * Helper function for xkb_state_mod_indices_are_active and
+ * xkb_state_mod_names_are_active.
+ */
+static int
+match_mod_masks(struct xkb_state *state, enum xkb_state_match match,
+                uint32_t wanted)
+{
+    uint32_t active = xkb_state_serialise_mods(state, XKB_STATE_EFFECTIVE);
+
+    if (!(match & XKB_STATE_MATCH_NON_EXCLUSIVE) && (active & ~wanted))
+        return 0;
+
+    if (match & XKB_STATE_MATCH_ANY)
+        return !!(active & wanted);
+    else
+        return (active & wanted) == wanted;
+
+    return 0;
+}
+
+/**
+ * Returns 1 if the modifiers are active with the specified type(s), 0 if
+ * not, or -1 if any of the modifiers are invalid.
+ */
+_X_EXPORT int
+xkb_state_mod_indices_are_active(struct xkb_state *state,
+                                 enum xkb_state_component type,
+                                 enum xkb_state_match match,
+                                 ...)
+{
+    va_list ap;
+    xkb_mod_index_t idx = 0;
+    uint32_t wanted = 0;
+    int ret = 0;
+
+    va_start(ap, match);
+    while (1) {
+        idx = va_arg(ap, xkb_mod_index_t);
+        if (idx == XKB_MOD_INVALID || idx >= xkb_map_num_mods(state->xkb)) {
+            ret = -1;
+            break;
+        }
+        wanted |= (1 << idx);
+    }
+    va_end(ap);
+
+    if (ret == -1)
+        return ret;
+
+    return match_mod_masks(state, match, wanted);
+}
+
+/**
  * Returns 1 if the given modifier is active with the specified type(s), 0 if
  * not, or -1 if the modifier is invalid.
  */
@@ -700,6 +754,42 @@ xkb_state_mod_name_is_active(struct xkb_state *state, const char *name,
 }
 
 /**
+ * Returns 1 if the modifiers are active with the specified type(s), 0 if
+ * not, or -1 if any of the modifiers are invalid.
+ */
+_X_EXPORT int
+xkb_state_mod_names_are_active(struct xkb_state *state,
+                               enum xkb_state_component type,
+                               enum xkb_state_match match,
+                               ...)
+{
+    va_list ap;
+    xkb_mod_index_t idx = 0;
+    const char *str;
+    uint32_t wanted = 0;
+    int ret = 0;
+
+    va_start(ap, match);
+    while (1) {
+        str = va_arg(ap, const char *);
+        if (str == NULL)
+            break;
+        idx = xkb_map_mod_get_index(state->xkb, str);
+        if (idx == XKB_MOD_INVALID) {
+            ret = -1;
+            break;
+        }
+        wanted |= (1 << idx);
+    }
+    va_end(ap);
+
+    if (ret == -1)
+        return ret;
+
+    return match_mod_masks(state, match, wanted);
+}
+
+/**
  * Returns 1 if the given group is active with the specified type(s), 0 if
  * not, or -1 if the group is invalid.
  */
index c081ba6..d43d25e 100644 (file)
@@ -112,6 +112,20 @@ test_update_key(struct xkb_keymap *xkb)
                                         XKB_STATE_DEPRESSED));
     assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_ALT,
                                         XKB_STATE_DEPRESSED));
+    assert(xkb_state_mod_names_are_active(state, XKB_STATE_DEPRESSED,
+                                          XKB_STATE_MATCH_ALL,
+                                          XKB_MOD_NAME_CTRL,
+                                          XKB_MOD_NAME_ALT,
+                                          NULL));
+    assert(!xkb_state_mod_names_are_active(state, XKB_STATE_DEPRESSED,
+                                           XKB_STATE_MATCH_ALL,
+                                           XKB_MOD_NAME_ALT,
+                                           NULL));
+    assert(xkb_state_mod_names_are_active(state, XKB_STATE_DEPRESSED,
+                                          (XKB_STATE_MATCH_ANY |
+                                           XKB_STATE_MATCH_NON_EXCLUSIVE),
+                                          XKB_MOD_NAME_ALT,
+                                          NULL));
 
     /* RAlt down */
     xkb_state_update_key(state, KEY_LEFTCTRL + EVDEV_OFFSET, XKB_KEY_UP);
@@ -121,6 +135,11 @@ test_update_key(struct xkb_keymap *xkb)
                                          XKB_STATE_EFFECTIVE));
     assert(xkb_state_mod_name_is_active(state, XKB_MOD_NAME_ALT,
                                         XKB_STATE_DEPRESSED));
+    assert(xkb_state_mod_names_are_active(state, XKB_STATE_DEPRESSED,
+                                          XKB_STATE_MATCH_ANY,
+                                          XKB_MOD_NAME_CTRL,
+                                          XKB_MOD_NAME_ALT,
+                                          NULL));
 
     /* none down */
     xkb_state_update_key(state, KEY_RIGHTALT + EVDEV_OFFSET, XKB_KEY_UP);