summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/keymap.c33
-rw-r--r--test/keymap.c3
2 files changed, 32 insertions, 4 deletions
diff --git a/src/keymap.c b/src/keymap.c
index 54ac7c0..d2baf94 100644
--- a/src/keymap.c
+++ b/src/keymap.c
@@ -433,12 +433,39 @@ xkb_keymap_key_get_mods_for_level(struct xkb_keymap *keymap,
const struct xkb_key_type *type = key->groups[layout].type;
size_t count = 0;
- for (unsigned i = 0; i < type->num_entries && count < masks_size; i++)
+
+ /*
+ * If the active set of modifiers doesn't match any explicit entry of
+ * the key type, the resulting level is 0 (i.e. Level 1).
+ * So, if we are asked to find the modifiers for level==0, we can offer
+ * an ~infinite supply, which is not very workable.
+ * What we do instead, is special case the empty set of modifiers for
+ * this purpose. If the empty set isn't explicit mapped to a level, we
+ * take it to map to Level 1.
+ * This is almost always what we want. If applicable, given it priority
+ * over other ways to generate the level.
+ */
+ if (level == 0) {
+ bool empty_mapped = false;
+ for (unsigned i = 0; i < type->num_entries && count < masks_size; i++)
+ if (entry_is_active(&type->entries[i]) &&
+ type->entries[i].mods.mask == 0) {
+ empty_mapped = true;
+ break;
+ }
+ if (!empty_mapped && count < masks_size) {
+ masks_out[count++] = 0;
+ }
+ }
+
+ /* Now search explicit mappings. */
+ for (unsigned i = 0; i < type->num_entries && count < masks_size; i++) {
if (entry_is_active(&type->entries[i]) &&
type->entries[i].level == level) {
- masks_out[count] = type->entries[i].mods.mask;
- ++count;
+ masks_out[count++] = type->entries[i].mods.mask;
}
+ }
+
return count;
}
diff --git a/test/keymap.c b/test/keymap.c
index 75e59f3..a6bade8 100644
--- a/test/keymap.c
+++ b/test/keymap.c
@@ -69,7 +69,8 @@ main(void)
// AC01 level 0 ('a') requires no modifiers on us-pc104
mask_count = xkb_keymap_key_get_mods_for_level(keymap, kc, 0, 0, masks_out, 4);
- assert(mask_count == 0);
+ assert(mask_count == 1);
+ assert(masks_out[0] == 0);
shift_mask = 1 << xkb_keymap_mod_get_index(keymap, "Shift");
lock_mask = 1 << xkb_keymap_mod_get_index(keymap, "Lock");