[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

libxkbcommon: Changes to 'upstream-unstable'



 .gitignore                  |    2 
 LICENSE                     |    2 
 Makefile.am                 |   36 ++
 NEWS                        |   25 +
 PACKAGING                   |    5 
 README.md                   |   17 +
 bench/bench.c               |    1 
 bench/bench.h               |    2 
 bench/compose.c             |    6 
 configure.ac                |   23 +
 doc/compat.md               |    4 
 doc/quick-guide.md          |    5 
 src/state.c                 |  124 +++++--
 src/utils.h                 |   13 
 src/xkbcomp/keymap-dump.c   |    2 
 test/.gitignore             |    1 
 test/common.c               |   29 +
 test/interactive-evdev.c    |   21 -
 test/interactive-wayland.c  |  693 ++++++++++++++++++++++++++++++++++++++++++++
 test/interactive-x11.c      |    7 
 test/state.c                |   34 ++
 test/symbols-leak-test.bash |    2 
 test/test.h                 |    9 
 xkbcommon.map               |    6 
 xkbcommon/xkbcommon.h       |   99 +++++-
 25 files changed, 1088 insertions(+), 80 deletions(-)

New commits:
commit d596f6e3ff2d1fde0491907fa9354e5cdf154ed1
Author: Ran Benita <ran234@gmail.com>
Date:   Fri Nov 11 20:02:41 2016 +0200

    Bump version to 0.7.0
    
    Signed-off-by: Ran Benita <ran234@gmail.com>

diff --git a/configure.ac b/configure.ac
index da201e1..fdab4ab 100644
--- a/configure.ac
+++ b/configure.ac
@@ -22,7 +22,7 @@ dnl Process this file with autoconf to create configure.
 
 # Initialize Autoconf
 AC_PREREQ([2.62])
-AC_INIT([libxkbcommon], [0.6.1],
+AC_INIT([libxkbcommon], [0.7.0],
         [https://bugs.freedesktop.org/enter_bug.cgi?product=libxkbcommon],
         [libxkbcommon], [http://xkbcommon.org])
 AC_CONFIG_SRCDIR([Makefile.am])

commit e7f73940b568b1e71df424e349402a02222f1954
Author: Ran Benita <ran234@gmail.com>
Date:   Fri Nov 11 20:00:26 2016 +0200

    Update NEWS
    
    Signed-off-by: Ran Benita <ran234@gmail.com>

diff --git a/NEWS b/NEWS
index 94506e5..27d5c29 100644
--- a/NEWS
+++ b/NEWS
@@ -1,7 +1,30 @@
+libxkbcommon 0.7.0 - 2016-11-11
+==================
+
+- Added support for different "modes" of calculating consumed modifiers.
+  The existing mode, based on the XKB standard, has proven to be
+  unintuitive in various shortcut implementations.
+
+  A new mode, based on the calculation used by the GTK toolkit, is added.
+  This mode is less eager to declare a modifier as consumed.
+
+- Added a new interactive demo program using the Wayland protocol.
+  See the PACKAGING file for the new (optional) test dependencies.
+
+- Fixed a compilation error on GNU Hurd.
+
+- New API:
+  enum xkb_consumed_mode
+  XKB_CONSUMED_MODE_XKB
+  XKB_CONSUMED_MODE_GTK
+  xkb_state_key_get_consumed_mods2
+  xkb_state_mod_index_is_consumed2
+
+
 libxkbcommon 0.6.1 - 2016-04-08
 ==================
 
-- Add LICENSE to distributed files in tarball releases.
+- Added LICENSE to distributed files in tarball releases.
 
 - Minor typo fix in xkb_keymap_get_as_string() documentation.
 

commit babc9e0c30918d3e12dea9e2e47b6c1c9c6cc1fb
Author: Ran Benita <ran234@gmail.com>
Date:   Sat Feb 27 22:31:16 2016 +0200

    state: add GTK consumed modifiers mode
    
    This is more or less what is implemented here:
    https://git.gnome.org/browse/gtk+/tree/gdk/x11/gdkkeys-x11.c?h=3.19.10#n1131
    
    The implementation here is more technically correct but should provide
    the same results.
    
    Try it out with ./test/interactive-evdev -g (modifiers prefixed with "-"
    are consumed).
    
    https://bugzilla.gnome.org/show_bug.cgi?id=754110
    https://github.com/xkbcommon/libxkbcommon/issues/17
    
    Signed-off-by: Ran Benita <ran234@gmail.com>

diff --git a/src/state.c b/src/state.c
index 6611d33..039115a 100644
--- a/src/state.c
+++ b/src/state.c
@@ -1340,6 +1340,30 @@ key_get_consumed(struct xkb_state *state, const struct xkb_key *key,
     case XKB_CONSUMED_MODE_XKB:
         consumed = type->mods.mask;
         break;
+
+    case XKB_CONSUMED_MODE_GTK: {
+        const struct xkb_key_type_entry *no_mods_entry;
+        xkb_level_index_t no_mods_leveli;
+        const struct xkb_level *no_mods_level, *level;
+
+        no_mods_entry = get_entry_for_mods(type, 0);
+        no_mods_leveli = no_mods_entry ? no_mods_entry->level : 0;
+        no_mods_level = &key->groups[group].levels[no_mods_leveli];
+
+        for (unsigned i = 0; i < type->num_entries; i++) {
+            const struct xkb_key_type_entry *entry = &type->entries[i];
+            if (!entry_is_active(entry))
+                continue;
+
+            level = &key->groups[group].levels[entry->level];
+            if (XkbLevelsSameSyms(level, no_mods_level))
+                continue;
+
+            if (entry == matching_entry || popcount(entry->mods.mask) == 1)
+                consumed |= entry->mods.mask & ~entry->preserve.mask;
+        }
+        break;
+    }
     }
 
     return consumed & ~preserve;
@@ -1386,6 +1410,7 @@ xkb_state_key_get_consumed_mods2(struct xkb_state *state, xkb_keycode_t kc,
 
     switch (mode) {
     case XKB_CONSUMED_MODE_XKB:
+    case XKB_CONSUMED_MODE_GTK:
         break;
     default:
         log_err_func(state->keymap->ctx,
diff --git a/test/interactive-evdev.c b/test/interactive-evdev.c
index 0ba3eab..4f12e67 100644
--- a/test/interactive-evdev.c
+++ b/test/interactive-evdev.c
@@ -48,6 +48,7 @@ static bool terminate;
 static int evdev_offset = 8;
 static bool report_state_changes;
 static bool with_compose;
+static enum xkb_consumed_mode consumed_mode = XKB_CONSUMED_MODE_XKB;
 
 #define NLONGS(n) (((n) + LONG_BIT - 1) / LONG_BIT)
 
@@ -261,7 +262,7 @@ process_event(struct keyboard *kbd, uint16_t type, uint16_t code, int32_t value)
 
     if (value != KEY_STATE_RELEASE)
         test_print_keycode_state(kbd->state, kbd->compose_state, keycode,
-                                 XKB_CONSUMED_MODE_XKB);
+                                 consumed_mode);
 
     if (with_compose) {
         status = xkb_compose_state_get_status(kbd->compose_state);
@@ -382,7 +383,7 @@ main(int argc, char *argv[])
 
     setlocale(LC_ALL, "");
 
-    while ((opt = getopt(argc, argv, "r:m:l:v:o:k:n:cd")) != -1) {
+    while ((opt = getopt(argc, argv, "r:m:l:v:o:k:n:cdg")) != -1) {
         switch (opt) {
         case 'r':
             rules = optarg;
@@ -416,6 +417,9 @@ main(int argc, char *argv[])
         case 'd':
             with_compose = true;
             break;
+        case 'g':
+            consumed_mode = XKB_CONSUMED_MODE_GTK;
+            break;
         case '?':
             fprintf(stderr, "   Usage: %s [-r <rules>] [-m <model>] "
                     "[-l <layout>] [-v <variant>] [-o <options>]\n",
@@ -424,7 +428,8 @@ main(int argc, char *argv[])
                     argv[0]);
             fprintf(stderr, "For both: -n <evdev keycode offset>\n"
                             "          -c (to report changes to the state)\n"
-                            "          -d (to enable compose)\n");
+                            "          -d (to enable compose)\n"
+                            "          -g (to use GTK consumed mode)\n");
             exit(2);
         }
     }
diff --git a/test/state.c b/test/state.c
index d774496..1f2c75d 100644
--- a/test/state.c
+++ b/test/state.c
@@ -460,6 +460,41 @@ test_consume(struct xkb_keymap *keymap)
     assert(mask == ((1U << shift) | (1U << alt) | (1U << ctrl) | (1U << mod5)));
 
     xkb_state_unref(state);
+
+    /* Test XKB_CONSUMED_MODE_GTK, CTRL+ALT */
+    state = xkb_state_new(keymap);
+    assert(state);
+
+    mask = xkb_state_key_get_consumed_mods2(state, KEY_F1 + EVDEV_OFFSET,
+                                            XKB_CONSUMED_MODE_GTK);
+    assert(mask == 0);
+
+    xkb_state_update_key(state, KEY_LEFTCTRL + EVDEV_OFFSET, XKB_KEY_DOWN);
+    mask = xkb_state_key_get_consumed_mods2(state, KEY_F1 + EVDEV_OFFSET,
+                                            XKB_CONSUMED_MODE_GTK);
+    assert(mask == 0);
+
+    xkb_state_update_key(state, KEY_LEFTALT + EVDEV_OFFSET, XKB_KEY_DOWN);
+    mask = xkb_state_key_get_consumed_mods2(state, KEY_F1 + EVDEV_OFFSET,
+                                            XKB_CONSUMED_MODE_GTK);
+    assert(mask == ((1U << alt) | (1U << ctrl)));
+
+    xkb_state_unref(state);
+
+    /* Test XKB_CONSUMED_MODE_GTK, Simple Shift */
+    state = xkb_state_new(keymap);
+    assert(state);
+
+    mask = xkb_state_key_get_consumed_mods2(state, KEY_A + EVDEV_OFFSET,
+                                            XKB_CONSUMED_MODE_GTK);
+    assert(mask == ((1U << shift) | (1U << caps)));
+
+    xkb_state_update_key(state, KEY_LEFTALT + EVDEV_OFFSET, XKB_KEY_DOWN);
+    mask = xkb_state_key_get_consumed_mods2(state, KEY_A + EVDEV_OFFSET,
+                                            XKB_CONSUMED_MODE_GTK);
+    assert(mask == ((1U << shift) | (1U << caps)));
+
+    xkb_state_unref(state);
 }
 
 static void
diff --git a/xkbcommon/xkbcommon.h b/xkbcommon/xkbcommon.h
index 30c0508..4902dc4 100644
--- a/xkbcommon/xkbcommon.h
+++ b/xkbcommon/xkbcommon.h
@@ -1687,7 +1687,22 @@ enum xkb_consumed_mode {
      * even though they are not active, since if they *were* active they would
      * have affected key translation.
      */
-    XKB_CONSUMED_MODE_XKB
+    XKB_CONSUMED_MODE_XKB,
+    /**
+     * This is the mode used by the GTK+ toolkit.
+     *
+     * The mode consists of the following two heuristics:
+     *
+     * - The active set of modifiers, excluding modifiers which do not affect
+     *   the key (as described above), are considered consumed, if they result
+     *   in different keysyms being produced than when no modifiers are active.
+     *
+     * - Additionally, a single modifier is considered consumed if, were it the
+     *   only active modifier affecting the key (as described above), it would
+     *   result in different keysyms being produced than when no modifiers are
+     *   active.
+     */
+    XKB_CONSUMED_MODE_GTK
 };
 
 /**

commit a0a41332cc3811370b4f9d46528b7a590846e289
Author: Ran Benita <ran234@gmail.com>
Date:   Sat Feb 27 19:06:14 2016 +0200

    state: allow different modes for calculating consumed modifiers
    
    The current functions dealing with consumed modifiers use the
    traditional XKB definition of consumed modifiers (see description in the
    added documentation). However, for several users of the library (e.g.
    GTK) this definition is unsuitable or too eager. This is exacerbated by
    some less-than-ideal xkeyboard-config type definitions (CTRL+ALT seems
    to cause most grief...).
    
    So, because we
    - want to enable alternative interpretations, but
    - don't want to expose too much internal details, and
    - want to keep things simple for all library users,
    we add a high-level "mode" parameter which selects the desired
    interpretation. New ones can be added as long as they make some sense.
    
    All of the old consumed-modifiers functions keep using the traditional
    ("XKB") mode. I mark xkb_state_mod_mask_remove_consumed() and as
    deprecated without adding a *2 variant because I don't it is very useful
    (or used) in practice.
    
    Alternative modes are added in subsequent commits (this commit only adds
    a mode for the existing behavior).
    
    https://github.com/xkbcommon/libxkbcommon/issues/17
    
    Signed-off-by: Ran Benita <ran234@gmail.com>

diff --git a/src/state.c b/src/state.c
index 8845a4e..6611d33 100644
--- a/src/state.c
+++ b/src/state.c
@@ -1311,13 +1311,20 @@ xkb_state_led_name_is_active(struct xkb_state *state, const char *name)
     return xkb_state_led_index_is_active(state, idx);
 }
 
+/**
+ * See:
+ * - XkbTranslateKeyCode(3), mod_rtrn return value, from libX11.
+ * - MyEnhancedXkbTranslateKeyCode(), a modification of the above, from GTK+.
+ */
 static xkb_mod_mask_t
-key_get_consumed(struct xkb_state *state, const struct xkb_key *key)
+key_get_consumed(struct xkb_state *state, const struct xkb_key *key,
+                 enum xkb_consumed_mode mode)
 {
     const struct xkb_key_type *type;
-    const struct xkb_key_type_entry *entry;
-    xkb_mod_mask_t preserve;
+    const struct xkb_key_type_entry *matching_entry;
+    xkb_mod_mask_t preserve = 0;
     xkb_layout_index_t group;
+    xkb_mod_mask_t consumed = 0;
 
     group = xkb_state_key_get_layout(state, key->keycode);
     if (group == XKB_LAYOUT_INVALID)
@@ -1325,47 +1332,40 @@ key_get_consumed(struct xkb_state *state, const struct xkb_key *key)
 
     type = key->groups[group].type;
 
-    entry = get_entry_for_key_state(state, key, group);
-    if (entry)
-        preserve = entry->preserve.mask;
-    else
-        preserve = 0;
+    matching_entry = get_entry_for_key_state(state, key, group);
+    if (matching_entry)
+        preserve = matching_entry->preserve.mask;
 
-    return type->mods.mask & ~preserve;
+    switch (mode) {
+    case XKB_CONSUMED_MODE_XKB:
+        consumed = type->mods.mask;
+        break;
+    }
+
+    return consumed & ~preserve;
 }
 
-/**
- * Tests to see if a modifier is used up by our translation of a
- * keycode to keysyms, taking note of the current modifier state and
- * the appropriate key type's preserve information, if any. This allows
- * the user to mask out the modifier in later processing of the
- * modifiers, e.g. when implementing hot keys or accelerators.
- *
- * See also, for example:
- * - XkbTranslateKeyCode(3), mod_rtrn return value, from libX11.
- * - gdk_keymap_translate_keyboard_state, consumed_modifiers return value,
- *   from gtk+.
- */
 XKB_EXPORT int
-xkb_state_mod_index_is_consumed(struct xkb_state *state, xkb_keycode_t kc,
-                                xkb_mod_index_t idx)
+xkb_state_mod_index_is_consumed2(struct xkb_state *state, xkb_keycode_t kc,
+                                 xkb_mod_index_t idx,
+                                 enum xkb_consumed_mode mode)
 {
     const struct xkb_key *key = XkbKey(state->keymap, kc);
 
     if (!key || idx >= xkb_keymap_num_mods(state->keymap))
         return -1;
 
-    return !!((1u << idx) & key_get_consumed(state, key));
+    return !!((1u << idx) & key_get_consumed(state, key, mode));
+}
+
+XKB_EXPORT int
+xkb_state_mod_index_is_consumed(struct xkb_state *state, xkb_keycode_t kc,
+                                xkb_mod_index_t idx)
+{
+    return xkb_state_mod_index_is_consumed2(state, kc, idx,
+                                            XKB_CONSUMED_MODE_XKB);
 }
 
-/**
- * Calculates which modifiers should be consumed during key processing,
- * and returns the mask with all these modifiers removed.  e.g. if
- * given a state of Alt and Shift active for a two-level alphabetic
- * key containing plus and equal on the first and second level
- * respectively, will return a mask of only Alt, as Shift has been
- * consumed by the type handling.
- */
 XKB_EXPORT xkb_mod_mask_t
 xkb_state_mod_mask_remove_consumed(struct xkb_state *state, xkb_keycode_t kc,
                                    xkb_mod_mask_t mask)
@@ -1375,16 +1375,33 @@ xkb_state_mod_mask_remove_consumed(struct xkb_state *state, xkb_keycode_t kc,
     if (!key)
         return 0;
 
-    return mask & ~key_get_consumed(state, key);
+    return mask & ~key_get_consumed(state, key, XKB_CONSUMED_MODE_XKB);
 }
 
 XKB_EXPORT xkb_mod_mask_t
-xkb_state_key_get_consumed_mods(struct xkb_state *state, xkb_keycode_t kc)
+xkb_state_key_get_consumed_mods2(struct xkb_state *state, xkb_keycode_t kc,
+                                 enum xkb_consumed_mode mode)
 {
-    const struct xkb_key *key = XkbKey(state->keymap, kc);
+    const struct xkb_key *key;
 
+    switch (mode) {
+    case XKB_CONSUMED_MODE_XKB:
+        break;
+    default:
+        log_err_func(state->keymap->ctx,
+                     "unrecognized consumed modifiers mode: %d\n", mode);
+        return 0;
+    }
+
+    key = XkbKey(state->keymap, kc);
     if (!key)
         return 0;
 
-    return key_get_consumed(state, key);
+    return key_get_consumed(state, key, mode);
+}
+
+XKB_EXPORT xkb_mod_mask_t
+xkb_state_key_get_consumed_mods(struct xkb_state *state, xkb_keycode_t kc)
+{
+    return xkb_state_key_get_consumed_mods2(state, kc, XKB_CONSUMED_MODE_XKB);
 }
diff --git a/test/common.c b/test/common.c
index 2dd10a0..1bb6d35 100644
--- a/test/common.c
+++ b/test/common.c
@@ -350,7 +350,8 @@ test_compile_rules(struct xkb_context *context, const char *rules,
 void
 test_print_keycode_state(struct xkb_state *state,
                          struct xkb_compose_state *compose_state,
-                         xkb_keycode_t keycode)
+                         xkb_keycode_t keycode,
+                         enum xkb_consumed_mode consumed_mode)
 {
     struct xkb_keymap *keymap;
 
@@ -410,7 +411,8 @@ test_print_keycode_state(struct xkb_state *state,
         if (xkb_state_mod_index_is_active(state, mod,
                                           XKB_STATE_MODS_EFFECTIVE) <= 0)
             continue;
-        if (xkb_state_mod_index_is_consumed(state, keycode, mod))
+        if (xkb_state_mod_index_is_consumed2(state, keycode, mod,
+                                             consumed_mode))
             printf("-%s ", xkb_keymap_mod_get_name(keymap, mod));
         else
             printf("%s ", xkb_keymap_mod_get_name(keymap, mod));
diff --git a/test/interactive-evdev.c b/test/interactive-evdev.c
index 7853e59..0ba3eab 100644
--- a/test/interactive-evdev.c
+++ b/test/interactive-evdev.c
@@ -260,7 +260,8 @@ process_event(struct keyboard *kbd, uint16_t type, uint16_t code, int32_t value)
     }
 
     if (value != KEY_STATE_RELEASE)
-        test_print_keycode_state(kbd->state, kbd->compose_state, keycode);
+        test_print_keycode_state(kbd->state, kbd->compose_state, keycode,
+                                 XKB_CONSUMED_MODE_XKB);
 
     if (with_compose) {
         status = xkb_compose_state_get_status(kbd->compose_state);
diff --git a/test/interactive-wayland.c b/test/interactive-wayland.c
index 6769b12..94c60c8 100644
--- a/test/interactive-wayland.c
+++ b/test/interactive-wayland.c
@@ -360,7 +360,8 @@ kbd_key(void *data, struct wl_keyboard *wl_kbd, uint32_t serial, uint32_t time,
 		return;
 
 	printf("%s: ", seat->name_str);
-	test_print_keycode_state(seat->state, NULL, key + 8);
+	test_print_keycode_state(seat->state, NULL, key + 8,
+                                 XKB_CONSUMED_MODE_XKB);
 
 	/* Exit on ESC. */
 	if (xkb_state_key_get_one_sym(seat->state, key + 8) == XKB_KEY_Escape)
diff --git a/test/interactive-x11.c b/test/interactive-x11.c
index 904136f..bb641dd 100644
--- a/test/interactive-x11.c
+++ b/test/interactive-x11.c
@@ -236,7 +236,8 @@ process_event(xcb_generic_event_t *gevent, struct keyboard *kbd)
         xcb_key_press_event_t *event = (xcb_key_press_event_t *) gevent;
         xkb_keycode_t keycode = event->detail;
 
-        test_print_keycode_state(kbd->state, NULL, keycode);
+        test_print_keycode_state(kbd->state, NULL, keycode,
+                                 XKB_CONSUMED_MODE_XKB);
 
         /* Exit on ESC. */
         if (keycode == 9)
diff --git a/test/test.h b/test/test.h
index 440c7ea..297c062 100644
--- a/test/test.h
+++ b/test/test.h
@@ -84,7 +84,8 @@ test_compile_rules(struct xkb_context *context, const char *rules,
 void
 test_print_keycode_state(struct xkb_state *state,
                          struct xkb_compose_state *compose_state,
-                         xkb_keycode_t keycode);
+                         xkb_keycode_t keycode,
+                         enum xkb_consumed_mode consumed_mode);
 
 void
 test_print_state_changes(enum xkb_state_component changed);
diff --git a/xkbcommon.map b/xkbcommon.map
index ac01fcb..cc468c6 100644
--- a/xkbcommon.map
+++ b/xkbcommon.map
@@ -91,3 +91,9 @@ global:
 	xkb_keymap_key_get_name;
 	xkb_keymap_key_by_name;
 } V_0.5.0;
+
+V_0.7.0 {
+global:
+	xkb_state_key_get_consumed_mods2;
+	xkb_state_mod_index_is_consumed2;
+} V_0.6.0;
diff --git a/xkbcommon/xkbcommon.h b/xkbcommon/xkbcommon.h
index 6f96e4f..30c0508 100644
--- a/xkbcommon/xkbcommon.h
+++ b/xkbcommon/xkbcommon.h
@@ -1649,7 +1649,7 @@ xkb_state_mod_indices_are_active(struct xkb_state *state,
  *    Effectively, this means that consumed modifiers (Shift in this example)
  *    are masked out as well, before doing the comparison.
  *
- * In summary, this is how the matching would be performed:
+ * In summary, this is approximately how the matching would be performed:
  * @code
  *   (keysym == shortcut_keysym) &&
  *   ((state_mods & ~consumed_mods & significant_mods) == shortcut_mods)
@@ -1666,15 +1666,83 @@ xkb_state_mod_indices_are_active(struct xkb_state *state,
  */
 
 /**
+ * Consumed modifiers mode.
+ *
+ * There are several possible methods for deciding which modifiers are
+ * consumed and which are not, each applicable for different systems or
+ * situations. The mode selects the method to use.
+ *
+ * Keep in mind that in all methods, the keymap may decide to "preserve"
+ * a modifier, meaning it is not reported as consumed even if it would
+ * have otherwise.
+ */
+enum xkb_consumed_mode {
+    /**
+     * This is the mode defined in the XKB specification and used by libX11.
+     *
+     * A modifier is consumed iff it *may affect* key translation.
+     *
+     * For example, if `Control+Alt+<Backspace>` produces some assigned keysym,
+     * then when pressing just `<Backspace>`, `Control` and `Alt` are consumed,
+     * even though they are not active, since if they *were* active they would
+     * have affected key translation.
+     */
+    XKB_CONSUMED_MODE_XKB
+};
+
+/**
+ * Get the mask of modifiers consumed by translating a given key.
+ *
+ * @param state The keyboard state.
+ * @param key   The keycode of the key.
+ * @param mode  The consumed modifiers mode to use; see enum description.
+ *
+ * @returns a mask of the consumed modifiers.
+ *
+ * @memberof xkb_state
+ * @since 0.7.0
+ */
+xkb_mod_mask_t
+xkb_state_key_get_consumed_mods2(struct xkb_state *state, xkb_keycode_t key,
+                                 enum xkb_consumed_mode mode);
+
+/**
+ * Same as xkb_state_key_get_consumed_mods2() with mode XKB_CONSUMED_MODE_XKB.
+ *
+ * @memberof xkb_state
+ * @since 0.4.1
+ */
+xkb_mod_mask_t
+xkb_state_key_get_consumed_mods(struct xkb_state *state, xkb_keycode_t key);
+
+/**
  * Test whether a modifier is consumed by keyboard state translation for
  * a key.
  *
+ * @param state The keyboard state.
+ * @param key   The keycode of the key.
+ * @param idx   The index of the modifier to check.
+ * @param mode  The consumed modifiers mode to use; see enum description.
+ *
  * @returns 1 if the modifier is consumed, 0 if it is not.  If the modifier
  * index is not valid in the keymap, returns -1.
  *
  * @sa xkb_state_mod_mask_remove_consumed()
  * @sa xkb_state_key_get_consumed_mods()
  * @memberof xkb_state
+ * @since 0.7.0
+ */
+int
+xkb_state_mod_index_is_consumed2(struct xkb_state *state,
+                                 xkb_keycode_t key,
+                                 xkb_mod_index_t idx,
+                                 enum xkb_consumed_mode mode);
+
+/**
+ * Same as xkb_state_mod_index_is_consumed2() with mode XKB_CONSUMED_MOD_XKB.
+ *
+ * @memberof xkb_state
+ * @since 0.4.1
  */
 int
 xkb_state_mod_index_is_consumed(struct xkb_state *state, xkb_keycode_t key,
@@ -1683,6 +1751,8 @@ xkb_state_mod_index_is_consumed(struct xkb_state *state, xkb_keycode_t key,
 /**
  * Remove consumed modifiers from a modifier mask for a key.
  *
+ * @deprecated Use xkb_state_key_get_consumed_mods2() instead.
+ *
  * Takes the given modifier mask, and removes all modifiers which are
  * consumed for that particular key (as in xkb_state_mod_index_is_consumed()).
  *
@@ -1694,18 +1764,6 @@ xkb_state_mod_mask_remove_consumed(struct xkb_state *state, xkb_keycode_t key,
                                    xkb_mod_mask_t mask);
 
 /**
- * Get the mask of modifiers consumed by translating a given key.
- *
- * @returns a mask of the consumed modifiers.
- *
- * @sa xkb_state_mod_index_is_consumed()
- * @memberof xkb_state
- * @since 0.4.1
- */
-xkb_mod_mask_t
-xkb_state_key_get_consumed_mods(struct xkb_state *state, xkb_keycode_t key);
-
-/**
  * Test whether a layout is active in a given keyboard state by name.
  *
  * @returns 1 if the layout is active, 0 if it is not.  If no layout with

commit 90611719572fbac04ddf3329f5683feb3b71e681
Author: Ran Benita <ran234@gmail.com>
Date:   Sat Feb 27 22:29:57 2016 +0200

    utils: add popcount function
    
    Signed-off-by: Ran Benita <ran234@gmail.com>

diff --git a/configure.ac b/configure.ac
index 3f8de97..da201e1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -83,6 +83,7 @@ AS_IF([test "x$ac_cv_func_secure_getenv" = xno -a \
 ])
 
 AX_GCC_BUILTIN(__builtin_expect)
+AX_GCC_BUILTIN(__builtin_popcount)
 
 # Some tests use Linux-specific headers
 AC_CHECK_HEADER([linux/input.h])
diff --git a/src/utils.h b/src/utils.h
index 4b7e81c..11ef735 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -178,6 +178,19 @@ msb_pos(uint32_t mask)
     return pos;
 }
 
+static inline int
+popcount(uint32_t x)
+{
+    int count;
+#if defined(HAVE___BUILTIN_POPCOUNT)
+    count = __builtin_popcount(x);
+#else
+    for (count = 0; x; count++)
+        x &= x - 1;
+#endif
+    return count;
+}
+
 bool
 map_file(FILE *file, char **string_out, size_t *size_out);
 

commit 914c060a1dacb5b42b4bb9ded036c5c6951d842a
Author: Ran Benita <ran234@gmail.com>
Date:   Sat Oct 22 20:13:11 2016 +0300

    test/state: move wrongly-placed assert
    
    Signed-off-by: Ran Benita <ran234@gmail.com>

diff --git a/test/state.c b/test/state.c
index 8ae718c..d774496 100644
--- a/test/state.c
+++ b/test/state.c
@@ -445,6 +445,7 @@ test_consume(struct xkb_keymap *keymap)
 
     /* More complicated - CTRL+ALT */
     state = xkb_state_new(keymap);
+    assert(state);
 
     mask = xkb_state_key_get_consumed_mods(state, KEY_F1 + EVDEV_OFFSET);
     assert(mask == ((1U << shift) | (1U << alt) | (1U << ctrl) | (1U << mod5)));
@@ -458,8 +459,6 @@ test_consume(struct xkb_keymap *keymap)
     mask = xkb_state_key_get_consumed_mods(state, KEY_F1 + EVDEV_OFFSET);
     assert(mask == ((1U << shift) | (1U << alt) | (1U << ctrl) | (1U << mod5)));
 
-    assert(state);
-
     xkb_state_unref(state);
 }
 

commit fe81dcbd2f9a375b46f4e1b8cc1d1045bd112cf6
Author: Ran Benita <ran234@gmail.com>
Date:   Mon Sep 19 10:09:12 2016 +0300

    bench: fix compilation on hurd
    
    Patch by Samuel Thibault.
    
    https://github.com/xkbcommon/libxkbcommon/issues/39
    
    Signed-off-by: Ran Benita <ran234@gmail.com>

diff --git a/bench/bench.c b/bench/bench.c
index 37e41f5..6aa43d9 100644
--- a/bench/bench.c
+++ b/bench/bench.c
@@ -35,6 +35,7 @@
 
 #include <assert.h>
 #include <stdlib.h>
+#include <stdint.h>
 #include <string.h>
 #include <stdio.h>
 
diff --git a/bench/bench.h b/bench/bench.h
index 5c1769e..adc15bb 100644
--- a/bench/bench.h
+++ b/bench/bench.h
@@ -25,6 +25,8 @@
 #ifndef LIBXKBCOMMON_BENCH_H
 #define LIBXKBCOMMON_BENCH_H
 
+#include <stdint.h>
+
 struct bench_time {
     long seconds;
     long milliseconds;

commit 853b7502f4c8e90480f58b3909fbd008587a1ba6
Author: Ran Benita <ran234@gmail.com>
Date:   Fri Sep 16 09:36:27 2016 +0300

    bench/compose: tabs -> spaces
    
    Signed-off-by: Ran Benita <ran234@gmail.com>

diff --git a/bench/compose.c b/bench/compose.c
index 04873a7..e2bf3e0 100644
--- a/bench/compose.c
+++ b/bench/compose.c
@@ -46,10 +46,10 @@ main(void)
     path = test_get_path("compose/en_US.UTF-8/Compose");
     file = fopen(path, "r");
     if (file == NULL) {
-	    perror(path);
-	    free(path);
-	    xkb_context_unref(ctx);
-	    return -1;
+        perror(path);
+        free(path);
+        xkb_context_unref(ctx);
+        return -1;
     }
 
     xkb_context_set_log_level(ctx, XKB_LOG_LEVEL_CRITICAL);

commit af2c83b6642591cf36d4002decef6757ec90b3e2
Author: Bryce Harrington <bryce@osg.samsung.com>
Date:   Thu Sep 15 14:31:55 2016 -0700

    README: Add basic build directions
    
    In particular, highlight the use of configure flags to control locating
    X11 keyboard stuff when building for Wayland.
    
    Of particular note, if the locale root is not specified, then xkbcommon
    will look for them under $prefix (i.e. /usr/local/share/X11/locale).
    But unless the user has specifically installed them there, it is better
    to look in the standard system location, /usr/share/X11/locale.
    
    Otherwise, xkbcommon will error when it can't find them, e.g.:
    
      xkbcommon: ERROR: ~/.XCompose:4:9: failed to expand %L to the locale Compose file
      xkbcommon: ERROR: ~/.XCompose:4:12: unterminated string literal
    
    Signed-off-by: Bryce Harrington <bryce@osg.samsung.com>
    Signed-off-by: Ran Benita <ran234@gmail.com>

diff --git a/README.md b/README.md
index 706822a..04a5df0 100644
--- a/README.md
+++ b/README.md
@@ -9,6 +9,21 @@ and dead keys.
 
 See [Quick Guide](doc/quick-guide.md).
 
+## Building
+
+libxkbcommon is built the typical autoconf way:
+
+    ./autogen.sh
+    make
+
+To build for use with Wayland, you can disable X11 support while still
+using the X11 keyboard configuration resource files thusly:
+
+    ./autogen.sh --disable-x11 \
+        --with-xkb-config-root=/usr/share/X11/xkb \
+        --with-x-locale-root=/usr/share/X11/locale
+    make
+
 ## API
 
 While libxkbcommon's API is somewhat derived from the classic XKB API as found

commit e92e0b88c6e3f7e6005d208e95f5dff760d7a3c4
Author: Bryce Harrington <bryce@osg.samsung.com>
Date:   Thu Sep 15 14:31:54 2016 -0700

    README: Bug *reports* are welcome
    
    Signed-off-by: Bryce Harrington <bryce@osg.samsung.com>
    Reviewed-by: Yong Bakos <ybakos@humanoriented.com>
    Signed-off-by: Ran Benita <ran234@gmail.com>

diff --git a/README.md b/README.md
index 867b532..706822a 100644
--- a/README.md
+++ b/README.md
@@ -44,7 +44,7 @@ Patches are always welcome, and may be sent to either
     <xorg-devel@lists.x.org> or <wayland-devel@lists.freedesktop.org>
 or through github.
 
-Bugs are also welcome, and may be reported either at
+Bug reports are also welcome, and may be filed either at
     Bugzilla https://bugs.freedesktop.org/describecomponents.cgi?product=libxkbcommon
 or
     Github https://github.com/xkbcommon/libxkbcommon/issues

commit ea9a5bcfd7cd20a2ecce4f92915fd537a0a84d90
Author: Bryce Harrington <bryce@bryceharrington.org>
Date:   Thu Sep 15 14:12:38 2016 -0700

    bench: Check for errors opening Compose file
    
    Otherwise it can segfault e.g. running ./compose inside the bench
    directory.
    
    Signed-off-by: Bryce Harrington <bryce@bryceharrington.org>
    Signed-off-by: Ran Benita <ran234@gmail.com>

diff --git a/bench/compose.c b/bench/compose.c
index 267b757..04873a7 100644
--- a/bench/compose.c
+++ b/bench/compose.c
@@ -45,6 +45,12 @@ main(void)
 
     path = test_get_path("compose/en_US.UTF-8/Compose");
     file = fopen(path, "r");
+    if (file == NULL) {
+	    perror(path);
+	    free(path);
+	    xkb_context_unref(ctx);
+	    return -1;
+    }
 
     xkb_context_set_log_level(ctx, XKB_LOG_LEVEL_CRITICAL);
     xkb_context_set_log_verbosity(ctx, 0);

commit 599fd9ba39f6343644d621bd02a23b2656e91b51
Author: Ran Benita <ran234@gmail.com>
Date:   Thu Sep 1 21:17:43 2016 +0300

    doc/compat: (! MODIFIER) syntax is parsed but ignored
    
    Signed-off-by: Ran Benita <ran234@gmail.com>

diff --git a/doc/compat.md b/doc/compat.md
index c378133..d863787 100644
--- a/doc/compat.md
+++ b/doc/compat.md
@@ -51,5 +51,6 @@ Relative to the standard implementation in libX11 (described in the
 Compose(5) man-page), some features are not supported:
 
 - the (! MODIFIER) syntax
+    + parsed correctly but ignored.
 - using modifier keysyms in Compose sequences
 - several interactions with Braille keysyms

commit c29afcc346f903efaa2ecac0c121244373d59eea
Author: Ran Benita <ran234@gmail.com>
Date:   Thu Sep 1 21:13:49 2016 +0300

    doc/compat.md: xkbcomp ignores multiple-keysyms these days
    
    https://cgit.freedesktop.org/xorg/app/xkbcomp/commit/?id=e119cbec7e750ffc4d4bd08b577db2c697035a30
    
    Signed-off-by: Ran Benita <ran234@gmail.com>

diff --git a/doc/compat.md b/doc/compat.md
index 14c57c5..c378133 100644
--- a/doc/compat.md
+++ b/doc/compat.md
@@ -42,8 +42,7 @@ Notable additions:
 - extended number of modifiers (planned)
 - extended number of groups (planned)
 - multiple keysyms per level
-  + this requires incompatible dataset changes, such that X11 would
-    not be able to parse these
+  + such levels are ignored by x11/xkbcomp.
 - key names (e.g. `<AE11>`) can be longer than 4 characters.
 
 ## Compose support

commit d58fc90a2917e482470e74a662373f85ccb23f31
Author: Bryce Harrington <bryce@osg.samsung.com>
Date:   Wed Jun 15 17:36:18 2016 -0700

    doc: Also mention the wayland test client in the quick guide
    
    Signed-off-by: Bryce Harrington <bryce@osg.samsung.com>

diff --git a/doc/quick-guide.md b/doc/quick-guide.md
index 6e04ba5..9d66475 100644
--- a/doc/quick-guide.md
+++ b/doc/quick-guide.md
@@ -20,6 +20,8 @@ can find complete and more complex examples in the source directory:
 
 2. test/interactive-x11.c contains an interactive X11 client.
 
+3. test/interactive-wayland.c contains an interactive Wayland client.
+
 Also, the library contains many more functions for examining and using
 the library context, the keymap and the keyboard state. See the
 hyper-linked reference documentation or go through the header files in

commit 094c8dc59bd3a7b6e4ebd80c07ab8fdbc8eaf749
Author: Bryce Harrington <bryce@osg.samsung.com>
Date:   Wed Jun 15 17:36:17 2016 -0700

    doc: Declare keymap for wayland example
    
    keymap was defined in the X11 example, but also define it in the wayland
    example just to make it a bit more standalone
    
    Signed-off-by: Bryce Harrington <bryce@osg.samsung.com>

diff --git a/doc/quick-guide.md b/doc/quick-guide.md
index a576070..6e04ba5 100644
--- a/doc/quick-guide.md
+++ b/doc/quick-guide.md
@@ -74,6 +74,7 @@ with a keymap. In this case, we can create the keymap object like this:
 ~~~{.c}
     /* From the wl_keyboard::keymap event. */


Reply to: