};
struct xkb_state {
- xkb_layout_index_t base_group; /**< depressed */
- xkb_layout_index_t latched_group;
- xkb_layout_index_t locked_group;
+ /* These may be negative, because of -1 group actions. */
+ int32_t base_group; /**< depressed */
+ int32_t latched_group;
+ int32_t locked_group;
xkb_layout_index_t group; /**< effective */
xkb_mod_mask_t base_mods; /**< depressed */
}
static xkb_layout_index_t
-wrap_group_into_range(xkb_layout_index_t group,
+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)
return out_of_range_group_number;
case RANGE_SATURATE:
- return num_groups - 1;
+ if (group < 0)
+ return 0;
+ else
+ return num_groups - 1;
case RANGE_WRAP:
default:
- return group % num_groups;
+ /*
+ * C99 says a negative dividend in a modulo operation always
+ * gives a negative result.
+ */
+ if (group < 0)
+ return ((int) num_groups + (group % (int) num_groups));
+ else
+ return group % num_groups;
}
}
static void
xkb_state_update_derived(struct xkb_state *state)
{
- state->mods =
- (state->base_mods | state->latched_mods | state->locked_mods);
- /* FIXME: Clamp/wrap locked_group */
- state->group = state->locked_group + state->base_group +
- state->latched_group;
- /* FIXME: Clamp/wrap effective group */
+ xkb_layout_index_t num_groups = xkb_keymap_num_layouts(state->keymap);
+
+ state->mods = (state->base_mods |
+ state->latched_mods |
+ state->locked_mods);
+
+ /* TODO: Use groups_wrap control instead of always RANGE_WRAP. */
+
+ state->locked_group = wrap_group_into_range(state->locked_group,
+ num_groups,
+ RANGE_WRAP, 0);
+
+ state->group = wrap_group_into_range(state->base_group +
+ state->latched_group +
+ state->locked_group,
+ num_groups,
+ RANGE_WRAP, 0);
xkb_state_led_update_all(state);
}
KEY_V, BOTH, XKB_KEY_p, FINISH));
+ xkb_keymap_unref(keymap);
+ assert(ctx);
+ keymap = test_compile_rules(ctx, "evdev", "", "us,il,ru", "",
+ "grp:alt_shift_toggle_bidir,grp:menu_toggle");
+ assert(keymap);
+
+ assert(test_key_seq(keymap,
+ KEY_LEFTSHIFT, DOWN, XKB_KEY_Shift_L, NEXT,
+ KEY_LEFTALT, DOWN, XKB_KEY_ISO_Prev_Group, NEXT,
+ KEY_LEFTALT, UP, XKB_KEY_ISO_Prev_Group, NEXT,
+ KEY_LEFTSHIFT, UP, XKB_KEY_Shift_L, FINISH));
+
+ assert(test_key_seq(keymap,
+ KEY_LEFTALT, DOWN, XKB_KEY_Alt_L, NEXT,
+ KEY_LEFTSHIFT, DOWN, XKB_KEY_ISO_Prev_Group, NEXT,
+ KEY_LEFTSHIFT, UP, XKB_KEY_ISO_Prev_Group, NEXT,
+ KEY_LEFTALT, UP, XKB_KEY_Alt_L, FINISH));
+
+ /* Check backwards (negative) group switching and wrapping. */
+ assert(test_key_seq(keymap,
+ 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_LEFTSHIFT, DOWN, XKB_KEY_Shift_L, NEXT,
+ KEY_LEFTALT, BOTH, XKB_KEY_ISO_Prev_Group, NEXT,
+ KEY_LEFTSHIFT, UP, XKB_KEY_Shift_L, NEXT,
+ KEY_H, BOTH, XKB_KEY_hebrew_yod, 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,
+ 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,
+ KEY_H, BOTH, XKB_KEY_Cyrillic_er, NEXT,
+ KEY_COMPOSE, BOTH, XKB_KEY_ISO_Next_Group, NEXT,
+ KEY_H, BOTH, XKB_KEY_h, FINISH));
+
xkb_keymap_unref(keymap);
xkb_context_unref(ctx);
return 0;