Add xkb_map_mod_mask_remove_consumed A fairly simple helper which, given an xkb_mod_mask_t, removes all modifiers which are consumed during processing of a particular key. Signed-off-by: Daniel Stone <daniel@fooishbar.org>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
diff --git a/src/map.c b/src/map.c
index aa6b08b..4a7ce31 100644
--- a/src/map.c
+++ b/src/map.c
@@ -346,6 +346,24 @@ xkb_key_repeats(struct xkb_keymap *keymap, xkb_keycode_t kc)
return XkbKey(keymap, kc)->repeats;
}
+static struct xkb_kt_map_entry *
+get_entry_for_key_state(struct xkb_state *state, struct xkb_key_type *type,
+ xkb_keycode_t kc)
+{
+ xkb_mod_mask_t active_mods;
+ unsigned int i;
+
+ active_mods = xkb_state_serialize_mods(state, XKB_STATE_EFFECTIVE);
+ active_mods &= type->mods.mask;
+
+ for (i = 0; i < type->num_entries; i++) {
+ if (type->map[i].mods.mask == active_mods)
+ return &type->map[i];
+ }
+
+ return NULL;
+}
+
/**
* 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
@@ -363,29 +381,47 @@ xkb_key_mod_index_is_consumed(struct xkb_state *state, xkb_keycode_t kc,
xkb_mod_index_t idx)
{
struct xkb_keymap *keymap = xkb_state_get_map(state);
- xkb_group_index_t group;
struct xkb_key_type *type;
- unsigned int i;
- struct xkb_kt_map_entry *entry = NULL;
- xkb_mod_mask_t active_mods;
+ struct xkb_kt_map_entry *entry;
+ xkb_group_index_t group;
if (!XkbKeycodeInRange(keymap, kc))
return 0;
group = xkb_key_get_group(state, kc);
type = XkbKeyType(keymap, XkbKey(keymap, kc), group);
- active_mods = xkb_state_serialize_mods(state, XKB_STATE_EFFECTIVE);
- active_mods &= type->mods.mask;
+ entry = get_entry_for_key_state(state, type, kc);
+ if (!entry)
+ return 0;
- for (i = 0; i < type->num_entries; i++) {
- if (type->map[i].mods.mask == active_mods) {
- entry = &type->map[i];
- break;
- }
- }
+ return !!((type->mods.mask & (~entry->preserve.mask)) & (1 << idx));
+}
+/**
+ * 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_key_mod_mask_remove_consumed(struct xkb_state *state, xkb_keycode_t kc,
+ xkb_mod_mask_t mask)
+{
+ struct xkb_keymap *keymap = xkb_state_get_map(state);
+ struct xkb_key_type *type;
+ struct xkb_kt_map_entry *entry;
+ xkb_group_index_t group;
+
+ if (!XkbKeycodeInRange(keymap, kc))
+ return 0;
+
+ group = xkb_key_get_group(state, kc);
+ type = XkbKeyType(keymap, XkbKey(keymap, kc), group);
+ entry = get_entry_for_key_state(state, type, kc);
if (!entry)
return 0;
- return !!((type->mods.mask & (~entry->preserve.mask)) & (1 << idx));
+ return mask & ~(type->mods.mask & ~entry->preserve.mask);
}
diff --git a/test/state.c b/test/state.c
index 4eccb34..d4f61ef 100644
--- a/test/state.c
+++ b/test/state.c
@@ -236,6 +236,36 @@ test_repeat(struct xkb_keymap *keymap)
assert(xkb_key_repeats(keymap, KEY_KBDILLUMDOWN + 8));
}
+static void
+test_consume(struct xkb_keymap *keymap)
+{
+ struct xkb_state *state = xkb_state_new(keymap);
+ xkb_mod_index_t alt, shift;
+ xkb_mod_mask_t mask;
+
+ assert(state);
+
+ alt = xkb_map_mod_get_index(keymap, XKB_MOD_NAME_ALT);
+ assert(alt != XKB_MOD_INVALID);
+ shift = xkb_map_mod_get_index(keymap, XKB_MOD_NAME_SHIFT);
+ assert(shift != XKB_MOD_INVALID);
+
+ xkb_state_update_key(state, KEY_LEFTALT + EVDEV_OFFSET, XKB_KEY_DOWN);
+ xkb_state_update_key(state, KEY_LEFTSHIFT + EVDEV_OFFSET, XKB_KEY_DOWN);
+ xkb_state_update_key(state, KEY_EQUAL + EVDEV_OFFSET, XKB_KEY_DOWN);
+
+ fprintf(stderr, "dumping state for Alt-Shift-+\n");
+ print_state(state);
+
+ mask = xkb_state_serialize_mods(state, XKB_STATE_EFFECTIVE);
+ assert(mask == ((1 << alt) | (1 << shift)));
+ mask = xkb_key_mod_mask_remove_consumed(state, KEY_EQUAL + EVDEV_OFFSET,
+ mask);
+ assert(mask == (1 << alt));
+
+ xkb_state_unref(state);
+}
+
int
main(void)
{
@@ -250,6 +280,7 @@ main(void)
test_update_key(keymap);
test_serialisation(keymap);
test_repeat(keymap);
+ test_consume(keymap);
xkb_map_unref(keymap);
xkb_context_unref(context);
diff --git a/xkbcommon/xkbcommon.h b/xkbcommon/xkbcommon.h
index 6afe5e1..0c2f06f 100644
--- a/xkbcommon/xkbcommon.h
+++ b/xkbcommon/xkbcommon.h
@@ -657,6 +657,15 @@ xkb_key_mod_index_is_consumed(struct xkb_state *state, xkb_keycode_t key,
xkb_mod_index_t idx);
/**
+ * Takes the given modifier mask, and removes all modifiers which are
+ * marked as 'consumed' (see xkb_key_mod_index_is_consumed definition)
+ * for that particular key.
+ */
+xkb_mod_mask_t
+xkb_key_mod_mask_remove_consumed(struct xkb_state *state, xkb_keycode_t key,
+ xkb_mod_mask_t mask);
+
+/**
* 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