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>
master
Ran Benita 2012-11-11 00:22:46 +02:00
parent 324d4dbd99
commit 60bd92021b
4 changed files with 29 additions and 10 deletions

View File

@ -227,6 +227,12 @@ xkb_keymap_num_levels_for_key(struct xkb_keymap *keymap, xkb_keycode_t kc,
if (!key) if (!key)
return 0; 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); return XkbKeyGroupWidth(key, layout);
} }
@ -287,8 +293,13 @@ xkb_keymap_key_get_syms_by_level(struct xkb_keymap *keymap,
if (!key) if (!key)
goto err; 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; goto err;
if (level >= XkbKeyGroupWidth(key, layout)) if (level >= XkbKeyGroupWidth(key, layout))
goto err; goto err;

View File

@ -427,4 +427,10 @@ xkb_keymap_new(struct xkb_context *ctx,
enum xkb_keymap_format format, enum xkb_keymap_format format,
enum xkb_keymap_compile_flags); 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 #endif

View File

@ -151,7 +151,7 @@ xkb_state_key_get_level(struct xkb_state *state, xkb_keycode_t kc,
return entry->level; return entry->level;
} }
static xkb_layout_index_t xkb_layout_index_t
wrap_group_into_range(int32_t group, wrap_group_into_range(int32_t group,
xkb_layout_index_t num_groups, xkb_layout_index_t num_groups,
enum xkb_range_exceed_type out_of_range_group_action, enum xkb_range_exceed_type out_of_range_group_action,

View File

@ -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. * 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 * @sa xkb_level_index_t
* @memberof xkb_keymap * @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] keymap The keymap.
* @param[in] key The keycode of the key. * @param[in] key The keycode of the key.
* @param[in] layout The layout for which to get the keysyms. This must * @param[in] layout The layout for which to get the keysyms.
* 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] level The shift level in the layout for which to get the * @param[in] level The shift level in the layout for which to get the
* keysyms. This must be smaller than: * keysyms. This must be smaller than:
* @code xkb_keymap_num_layouts_for_key(keymap, key) @endcode * @code xkb_keymap_num_layouts_for_key(keymap, key) @endcode
* usually it would be: * @param[out] syms_out An immutible array of keysyms corresponding to the
* @code xkb_state_key_get_level(state, key, layout) @endcode
* @param[out] syms_out An immutible array of keysyms corresponding the
* key in the given layout and shift level. * 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 * @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 * are produced by the key in the given layout and shift level, returns 0
* and sets syms_out to NULL. * and sets syms_out to NULL.