From 3a54d92cf7bc133a9db6fe1584ec82b9648efc2e Mon Sep 17 00:00:00 2001
From: Pierre Le Marre <dev@wismill.eu>
Date: Tue, 3 Dec 2024 10:09:10 +0100
Subject: [PATCH] state: Avoid keycode lookup when key ref is available

---
 src/keymap-priv.c         |  3 +-
 src/keymap.h              |  2 +-
 src/state.c               | 59 ++++++++++++++++++++++-----------------
 src/xkbcomp/keymap-dump.c |  2 +-
 4 files changed, 37 insertions(+), 29 deletions(-)

diff --git a/src/keymap-priv.c b/src/keymap-priv.c
index 41f4c754..5c475261 100644
--- a/src/keymap-priv.c
+++ b/src/keymap-priv.c
@@ -205,12 +205,11 @@ XkbWrapGroupIntoRange(int32_t group,
 
 unsigned int
 xkb_keymap_key_get_actions_by_level(struct xkb_keymap *keymap,
-                                    xkb_keycode_t kc,
+                                    const struct xkb_key *key,
                                     xkb_layout_index_t layout,
                                     xkb_level_index_t level,
                                     const union xkb_action **actions)
 {
-    const struct xkb_key *key = XkbKey(keymap, kc);
     if (!key)
         goto err;
 
diff --git a/src/keymap.h b/src/keymap.h
index 218a389e..4be42e63 100644
--- a/src/keymap.h
+++ b/src/keymap.h
@@ -512,7 +512,7 @@ mod_mask_get_effective(struct xkb_keymap *keymap, xkb_mod_mask_t mods);
 
 unsigned int
 xkb_keymap_key_get_actions_by_level(struct xkb_keymap *keymap,
-                                    xkb_keycode_t kc,
+                                    const struct xkb_key *key,
                                     xkb_layout_index_t layout,
                                     xkb_level_index_t level,
                                     const union xkb_action **actions);
diff --git a/src/state.c b/src/state.c
index 81dbc766..929a498b 100644
--- a/src/state.c
+++ b/src/state.c
@@ -137,6 +137,23 @@ get_entry_for_key_state(struct xkb_state *state, const struct xkb_key *key,
     return get_entry_for_mods(type, active_mods);
 }
 
+static inline xkb_level_index_t
+_xkb_state_key_get_level(struct xkb_state *state, const struct xkb_key *key,
+                         xkb_layout_index_t layout)
+{
+    if (layout >= key->num_groups)
+        return XKB_LEVEL_INVALID;
+
+    /* If we don't find an explicit match the default is 0. */
+    const struct xkb_key_type_entry *entry =
+        get_entry_for_key_state(state, key, layout);
+
+    if (!entry)
+        return 0;
+
+    return entry->level;
+}
+
 /**
  * Returns the level to use for the given key and state, or
  * XKB_LEVEL_INVALID.
@@ -146,17 +163,19 @@ xkb_state_key_get_level(struct xkb_state *state, xkb_keycode_t kc,
                         xkb_layout_index_t layout)
 {
     const struct xkb_key *key = XkbKey(state->keymap, kc);
-    const struct xkb_key_type_entry *entry;
 
-    if (!key || layout >= key->num_groups)
+    if (!key)
         return XKB_LEVEL_INVALID;
 
-    /* If we don't find an explicit match the default is 0. */
-    entry = get_entry_for_key_state(state, key, layout);
-    if (!entry)
-        return 0;
+    return _xkb_state_key_get_level(state, key, layout);
+}
 
-    return entry->level;
+static inline xkb_layout_index_t
+_xkb_state_key_get_layout(struct xkb_state *state, const struct xkb_key *key)
+{
+    return XkbWrapGroupIntoRange(state->components.group, key->num_groups,
+                                 key->out_of_range_group_action,
+                                 key->out_of_range_group_number);
 }
 
 /**
@@ -171,32 +190,22 @@ xkb_state_key_get_layout(struct xkb_state *state, xkb_keycode_t kc)
     if (!key)
         return XKB_LAYOUT_INVALID;
 
-    return XkbWrapGroupIntoRange(state->components.group, key->num_groups,
-                                 key->out_of_range_group_action,
-                                 key->out_of_range_group_number);
+    return _xkb_state_key_get_layout(state, key);
 }
 
 static unsigned int
 xkb_key_get_actions(struct xkb_state *state, const struct xkb_key *key,
                     const union xkb_action **actions)
 {
-    xkb_layout_index_t layout;
-    xkb_level_index_t level;
-
-    layout = xkb_state_key_get_layout(state, key->keycode);
-    if (layout == XKB_LAYOUT_INVALID)
-        goto err;
-
-    level = xkb_state_key_get_level(state, key->keycode, layout);
-    if (level == XKB_LEVEL_INVALID)
-        goto err;
+    xkb_layout_index_t layout = _xkb_state_key_get_layout(state, key);
+    xkb_level_index_t level = _xkb_state_key_get_level(state, key, layout);
+    if (level == XKB_LEVEL_INVALID) {
+        *actions = NULL;
+        return 0;
+    }
 
-    return xkb_keymap_key_get_actions_by_level(state->keymap, key->keycode,
+    return xkb_keymap_key_get_actions_by_level(state->keymap, key,
                                                layout, level, actions);
-
-err:
-    *actions = NULL;
-    return 0;
 }
 
 static struct xkb_filter *
diff --git a/src/xkbcomp/keymap-dump.c b/src/xkbcomp/keymap-dump.c
index 3fc730d9..2fd986bc 100644
--- a/src/xkbcomp/keymap-dump.c
+++ b/src/xkbcomp/keymap-dump.c
@@ -423,7 +423,7 @@ write_actions(struct xkb_keymap *keymap, struct buf *buf, struct buf *buf2,
         if (level != 0)
             write_buf(buf, ", ");
 
-        count = xkb_keymap_key_get_actions_by_level(keymap, key->keycode,
+        count = xkb_keymap_key_get_actions_by_level(keymap, key,
                                                     group, level, &actions);
         buf2->size = 0;
         if (count == 0) {