Commit 60bd92021b63ecd3f8396704c841a0bf0fdab72b

Ran Benita 2012-11-11T00:22:46

keymap: wrap the layout parameter if it is out of range for the key The functions num_levels_for_key() and get_syms_by_level() have a 'layout' parameter. Currently it is expected that this value is always legal for the key, as determined by num_layouts_for_key(). However, there are legitimate use cases for passing an out-of-range layout there, most probably passing the effective layout, and expecting to get the keysyms/levels for just this layout. So we wrap it just as we do in the xkb_state_* functions. This is also useful for stuff like this: http://developer.gnome.org/gdk/stable/gdk-Keyboard-Handling.html#gdk-keymap-lookup-key If this behavior is not desired, the user has the option to check against num_layouts_for_key herself. https://bugs.freedesktop.org/show_bug.cgi?id=56866 Reported-by: Gatis Paeglis <gatis.paeglis@digia.com> Signed-off-by: Ran Benita <ran234@gmail.com>

diff --git a/src/keymap.c b/src/keymap.c
index 6736c2c..87694cf 100644
--- a/src/keymap.c
+++ b/src/keymap.c
@@ -227,6 +227,12 @@ xkb_keymap_num_levels_for_key(struct xkb_keymap *keymap, xkb_keycode_t kc,
     if (!key)
         return 0;
 
+    layout = wrap_group_into_range(layout, key->num_groups,
+                                   key->out_of_range_group_action,
+                                   key->out_of_range_group_number);
+    if (layout == XKB_LAYOUT_INVALID)
+        return 0;
+
     return XkbKeyGroupWidth(key, layout);
 }
 
@@ -287,8 +293,13 @@ xkb_keymap_key_get_syms_by_level(struct xkb_keymap *keymap,
 
     if (!key)
         goto err;
-    if (layout >= key->num_groups)
+
+    layout = wrap_group_into_range(layout, key->num_groups,
+                                   key->out_of_range_group_action,
+                                   key->out_of_range_group_number);
+    if (layout == XKB_LAYOUT_INVALID)
         goto err;
+
     if (level >= XkbKeyGroupWidth(key, layout))
         goto err;
 
diff --git a/src/keymap.h b/src/keymap.h
index 483ee90..cb035b0 100644
--- a/src/keymap.h
+++ b/src/keymap.h
@@ -427,4 +427,10 @@ xkb_keymap_new(struct xkb_context *ctx,
                enum xkb_keymap_format format,
                enum xkb_keymap_compile_flags);
 
+xkb_layout_index_t
+wrap_group_into_range(int32_t group,
+                      xkb_layout_index_t num_groups,
+                      enum xkb_range_exceed_type out_of_range_group_action,
+                      xkb_layout_index_t out_of_range_group_number);
+
 #endif
diff --git a/src/state.c b/src/state.c
index 48b2132..19b372a 100644
--- a/src/state.c
+++ b/src/state.c
@@ -151,7 +151,7 @@ xkb_state_key_get_level(struct xkb_state *state, xkb_keycode_t kc,
     return entry->level;
 }
 
-static xkb_layout_index_t
+xkb_layout_index_t
 wrap_group_into_range(int32_t group,
                       xkb_layout_index_t num_groups,
                       enum xkb_range_exceed_type out_of_range_group_action,
diff --git a/xkbcommon/xkbcommon.h b/xkbcommon/xkbcommon.h
index 43f9df1..244b35b 100644
--- a/xkbcommon/xkbcommon.h
+++ b/xkbcommon/xkbcommon.h
@@ -864,6 +864,10 @@ xkb_keymap_num_layouts_for_key(struct xkb_keymap *keymap, xkb_keycode_t key);
 /**
  * Get the number of shift levels for a specific key and layout.
  *
+ * If @c layout is out of range for this key (that is, larger or equal to
+ * the value returned by xkb_keymap_num_layouts_for_key()), it is brought
+ * back into range in a manner consistent with xkb_state_key_get_layout().
+ *
  * @sa xkb_level_index_t
  * @memberof xkb_keymap
  */
@@ -881,19 +885,17 @@ xkb_keymap_num_levels_for_key(struct xkb_keymap *keymap, xkb_keycode_t key,
  *
  * @param[in] keymap    The keymap.
  * @param[in] key       The keycode of the key.
- * @param[in] layout    The layout for which to get the keysyms. This must
- * be smaller than:
- * @code xkb_keymap_num_layouts_for_key(keymap, key) @endcode
- * Usually it would be:
- * @code xkb_state_key_get_layout(state, key) @endcode
+ * @param[in] layout    The layout for which to get the keysyms.
  * @param[in] level     The shift level in the layout for which to get the
  * keysyms. This must be smaller than:
  * @code xkb_keymap_num_layouts_for_key(keymap, key) @endcode
- * usually it would be:
- * @code xkb_state_key_get_level(state, key, layout) @endcode
- * @param[out] syms_out An immutible array of keysyms corresponding the
+ * @param[out] syms_out An immutible array of keysyms corresponding to the
  * key in the given layout and shift level.
  *
+ * If @c layout is out of range for this key (that is, larger or equal to
+ * the value returned by xkb_keymap_num_layouts_for_key()), it is brought
+ * back into range in a manner consistent with xkb_state_key_get_layout().
+ *
  * @returns The number of keysyms in the syms_out array.  If no keysyms
  * are produced by the key in the given layout and shift level, returns 0
  * and sets syms_out to NULL.