From bc129d48659e0354170c3416650893d15bb20fef Mon Sep 17 00:00:00 2001 From: Pierre Le Marre Date: Fri, 12 Jul 2024 04:09:39 +0200 Subject: [PATCH] Enable out-of-range group action configuration --- include/xkbcommon/xkbcommon.h | 27 +++++++++++++++++++++++++++ src/keymap.c | 14 ++++++++++++++ src/keymap.h | 3 +++ src/state.c | 21 ++++++++++++++------- test/keyseq.c | 33 +++++++++++++++++++++++++++++++++ xkbcommon.map | 5 +++++ 6 files changed, 96 insertions(+), 7 deletions(-) diff --git a/include/xkbcommon/xkbcommon.h b/include/xkbcommon/xkbcommon.h index e3631df8e..2b753ddf5 100644 --- a/include/xkbcommon/xkbcommon.h +++ b/include/xkbcommon/xkbcommon.h @@ -993,6 +993,33 @@ char * xkb_keymap_get_as_string(struct xkb_keymap *keymap, enum xkb_keymap_format format); +/** + * Set the out-of-range layout action to “redirect into range”: + * + * - If the effective layout is invalid, it is set to the given layout. + * - If the given layout is invalid, it is set to the first one (0). + * + * @memberof xkb_keymap + * @sa xkb_keymap_set_out_of_range_layout_clamp + */ +void +xkb_keymap_set_out_of_range_layout_redirect(struct xkb_keymap *keymap, + xkb_layout_index_t layout); + +/** + * Set the out-of-range layout action to “clamp into range”: if the effective + * layout is invalid, it is set to nearest valid layout: + * + * - effective layout larger than the highest supported layout are mapped to + * the highest supported layout; + * - effective layout less than 0 are mapped to 0. + * + * @memberof xkb_keymap + * @sa xkb_keymap_set_out_of_range_layout_redirect + */ +void +xkb_keymap_set_out_of_range_layout_clamp(struct xkb_keymap *keymap); + /** @} */ /** diff --git a/src/keymap.c b/src/keymap.c index 0291aedbb..23ca890ed 100644 --- a/src/keymap.c +++ b/src/keymap.c @@ -243,6 +243,20 @@ xkb_keymap_new_from_file(struct xkb_context *ctx, return keymap; } +XKB_EXPORT void +xkb_keymap_set_out_of_range_layout_redirect(struct xkb_keymap *keymap, + xkb_layout_index_t layout) +{ + keymap->out_of_range_group_action = RANGE_REDIRECT; + keymap->out_of_range_group_number = layout; +} + +XKB_EXPORT void +xkb_keymap_set_out_of_range_layout_clamp(struct xkb_keymap *keymap) +{ + keymap->out_of_range_group_action = RANGE_SATURATE; +} + XKB_EXPORT char * xkb_keymap_get_as_string(struct xkb_keymap *keymap, enum xkb_keymap_format format) diff --git a/src/keymap.h b/src/keymap.h index f7ea5bdf1..681685a04 100644 --- a/src/keymap.h +++ b/src/keymap.h @@ -370,6 +370,9 @@ struct xkb_keymap { enum xkb_keymap_format format; enum xkb_action_controls enabled_ctrls; + /* groups_wrap control */ + enum xkb_range_exceed_type out_of_range_group_action; + xkb_layout_index_t out_of_range_group_number; xkb_keycode_t min_key_code; xkb_keycode_t max_key_code; diff --git a/src/state.c b/src/state.c index 543658bef..30a3f0091 100644 --- a/src/state.c +++ b/src/state.c @@ -173,9 +173,9 @@ XkbWrapGroupIntoRange(int32_t group, switch (out_of_range_group_action) { case RANGE_REDIRECT: - if (out_of_range_group_number >= num_groups) - return 0; - return out_of_range_group_number; + return (out_of_range_group_number >= num_groups) + ? 0 + : out_of_range_group_number; case RANGE_SATURATE: if (group < 0) @@ -687,19 +687,26 @@ xkb_state_update_derived(struct xkb_state *state) state->components.latched_mods | state->components.locked_mods); - /* TODO: Use groups_wrap control instead of always RANGE_WRAP. */ - wrapped = XkbWrapGroupIntoRange(state->components.locked_group, state->keymap->num_groups, - RANGE_WRAP, 0); + state->keymap->out_of_range_group_action, + state->keymap->out_of_range_group_number); state->components.locked_group = (wrapped == XKB_LAYOUT_INVALID ? 0 : wrapped); + wrapped = XkbWrapGroupIntoRange(state->components.base_group + state->components.latched_group + state->components.locked_group, state->keymap->num_groups, - RANGE_WRAP, 0); + state->keymap->out_of_range_group_action, + state->keymap->out_of_range_group_number); + + log_err(state->keymap->ctx, 0, + "xkb_state_update_derived: base_group: %d, latched_group: %d, locked_group: %d, wrapped: %u, out_of_range_group_action: %u\n", + state->components.base_group, state->components.latched_group, state->components.locked_group, + wrapped, state->keymap->out_of_range_group_action); + state->components.group = (wrapped == XKB_LAYOUT_INVALID ? 0 : wrapped); diff --git a/test/keyseq.c b/test/keyseq.c index 53de4232e..3ad4b418c 100644 --- a/test/keyseq.c +++ b/test/keyseq.c @@ -402,6 +402,39 @@ main(void) KEY_COMPOSE, BOTH, XKB_KEY_ISO_Next_Group, NEXT, KEY_H, BOTH, XKB_KEY_h, FINISH)); + /* Out-of-range group action: redirect */ + xkb_keymap_set_out_of_range_layout_redirect(keymap, 1); + assert(test_key_seq(keymap, + KEY_H, BOTH, XKB_KEY_h, NEXT, + KEY_LEFTSHIFT, DOWN, XKB_KEY_Shift_L, NEXT, + KEY_LEFTALT, BOTH, XKB_KEY_ISO_Prev_Group, NEXT, + KEY_LEFTSHIFT, UP, XKB_KEY_Shift_L, NEXT, + /* Negative group: redirect to second layout */ + KEY_H, BOTH, XKB_KEY_hebrew_yod, NEXT, + KEY_COMPOSE, BOTH, XKB_KEY_ISO_Next_Group, NEXT, + KEY_H, BOTH, XKB_KEY_Cyrillic_er, NEXT, + KEY_COMPOSE, BOTH, XKB_KEY_ISO_Next_Group, NEXT, + /* Greater that last group: redirect to second layout */ + KEY_H, BOTH, XKB_KEY_hebrew_yod, FINISH)); + + /* Out-of-range group action: clamp */ + xkb_keymap_set_out_of_range_layout_clamp(keymap); + assert(test_key_seq(keymap, + KEY_H, BOTH, XKB_KEY_h, NEXT, + KEY_LEFTSHIFT, DOWN, XKB_KEY_Shift_L, NEXT, + KEY_LEFTALT, BOTH, XKB_KEY_ISO_Prev_Group, NEXT, + KEY_LEFTSHIFT, UP, XKB_KEY_Shift_L, NEXT, + /* Negative group: redirect to first layout */ + KEY_H, BOTH, XKB_KEY_h, NEXT, + KEY_COMPOSE, BOTH, XKB_KEY_ISO_Next_Group, NEXT, + KEY_H, BOTH, XKB_KEY_hebrew_yod, NEXT, + KEY_COMPOSE, BOTH, XKB_KEY_ISO_Next_Group, NEXT, + KEY_H, BOTH, XKB_KEY_Cyrillic_er, NEXT, + KEY_COMPOSE, BOTH, XKB_KEY_ISO_Next_Group, NEXT, + KEY_COMPOSE, BOTH, XKB_KEY_ISO_Next_Group, NEXT, + /* Greater that last group: redirect to last layout */ + KEY_H, BOTH, XKB_KEY_Cyrillic_er, FINISH)); + xkb_keymap_unref(keymap); keymap = test_compile_rules(ctx, "evdev", "", "us,il,ru", "", "grp:switch,grp:lswitch,grp:menu_toggle"); diff --git a/xkbcommon.map b/xkbcommon.map index b2507272e..1e6be63ee 100644 --- a/xkbcommon.map +++ b/xkbcommon.map @@ -119,3 +119,8 @@ global: xkb_compose_table_iterator_free; xkb_compose_table_iterator_next; } V_1.0.0; + +V_1.8.0 { + xkb_keymap_set_out_of_range_layout_redirect; + xkb_keymap_set_out_of_range_layout_clamp; +} V_1.6.0;