cast a function's return value
[platform/upstream/libxkbcommon.git] / src / keymap.c
index 6ed0408..c1d5a10 100644 (file)
@@ -50,6 +50,8 @@
  *
  * ********************************************************/
 
+#include "config.h"
+
 #include "keymap.h"
 #include "text.h"
 
@@ -72,7 +74,7 @@ xkb_keymap_unref(struct xkb_keymap *keymap)
             if (key->groups) {
                 for (unsigned i = 0; i < key->num_groups; i++) {
                     if (key->groups[i].levels) {
-                        for (unsigned j = 0; j < XkbKeyGroupWidth(key, i); j++)
+                        for (unsigned j = 0; j < XkbKeyNumLevels(key, i); j++)
                             if (key->groups[i].levels[j].num_syms > 1)
                                 free(key->groups[i].levels[j].u.syms);
                         free(key->groups[i].levels);
@@ -192,6 +194,10 @@ xkb_keymap_new_from_buffer(struct xkb_context *ctx,
     if (!keymap)
         return NULL;
 
+    /* Allow a zero-terminated string as a buffer */
+    if (length > 0 && buffer[length - 1] == '\0')
+        length--;
+
     if (!ops->keymap_new_from_string(keymap, buffer, length)) {
         xkb_keymap_unref(keymap);
         return NULL;
@@ -363,7 +369,7 @@ xkb_keymap_num_levels_for_key(struct xkb_keymap *keymap, xkb_keycode_t kc,
     if (layout == XKB_LAYOUT_INVALID)
         return 0;
 
-    return XkbKeyGroupWidth(key, layout);
+    return XkbKeyNumLevels(key, layout);
 }
 
 /**
@@ -407,6 +413,66 @@ xkb_keymap_led_get_index(struct xkb_keymap *keymap, const char *name)
     return XKB_LED_INVALID;
 }
 
+XKB_EXPORT size_t
+xkb_keymap_key_get_mods_for_level(struct xkb_keymap *keymap,
+                                  xkb_keycode_t kc,
+                                  xkb_layout_index_t layout,
+                                  xkb_level_index_t level,
+                                  xkb_mod_mask_t *masks_out,
+                                  size_t masks_size)
+{
+    const struct xkb_key *key = XkbKey(keymap, kc);
+    if (!key)
+        return 0;
+
+    layout = XkbWrapGroupIntoRange(layout, key->num_groups,
+                                   key->out_of_range_group_action,
+                                   key->out_of_range_group_number);
+    if (layout == XKB_LAYOUT_INVALID)
+        return 0;
+
+    if (level >= XkbKeyNumLevels(key, layout))
+        return 0;
+
+    const struct xkb_key_type *type = key->groups[layout].type;
+
+    size_t count = 0;
+
+    /*
+     * 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;
+        }
+    }
+
+    return count;
+}
+
 /**
  * As below, but takes an explicit layout/level rather than state.
  */
@@ -429,7 +495,7 @@ xkb_keymap_key_get_syms_by_level(struct xkb_keymap *keymap,
     if (layout == XKB_LAYOUT_INVALID)
         goto err;
 
-    if (level >= XkbKeyGroupWidth(key, layout))
+    if (level >= XkbKeyNumLevels(key, layout))
         goto err;
 
     num_syms = key->groups[layout].levels[level].num_syms;
@@ -470,6 +536,40 @@ xkb_keymap_key_for_each(struct xkb_keymap *keymap, xkb_keymap_key_iter_t iter,
         iter(keymap, key->keycode, data);
 }
 
+XKB_EXPORT const char *
+xkb_keymap_key_get_name(struct xkb_keymap *keymap, xkb_keycode_t kc)
+{
+    const struct xkb_key *key = XkbKey(keymap, kc);
+
+    if (!key)
+        return NULL;
+
+    return xkb_atom_text(keymap->ctx, key->name);
+}
+
+XKB_EXPORT xkb_keycode_t
+xkb_keymap_key_by_name(struct xkb_keymap *keymap, const char *name)
+{
+    struct xkb_key *key;
+    xkb_atom_t atom;
+
+    atom = xkb_atom_lookup(keymap->ctx, name);
+    if (atom) {
+        xkb_atom_t ratom = XkbResolveKeyAlias(keymap, atom);
+        if (ratom)
+            atom = ratom;
+    }
+    if (!atom)
+        return XKB_KEYCODE_INVALID;
+
+    xkb_keys_foreach(key, keymap) {
+        if (key->name == atom)
+            return key->keycode;
+    }
+
+    return XKB_KEYCODE_INVALID;
+}
+
 /**
  * Simple boolean specifying whether or not the key should repeat.
  */
@@ -483,3 +583,17 @@ xkb_keymap_key_repeats(struct xkb_keymap *keymap, xkb_keycode_t kc)
 
     return key->repeats;
 }
+
+XKB_EXPORT int
+xkb_keymap_key_set_repeats(struct xkb_keymap *keymap, xkb_keycode_t kc, int enable)
+{
+    struct xkb_key *key = (struct xkb_key *)XkbKey(keymap, kc);
+
+    if (!key)
+        return 0;
+
+    key->repeats = !!enable;
+    key->explicit |= EXPLICIT_REPEAT;
+
+    return 1;
+}