xkb: fix group wrapping

- Use the number of groups we actually have instead of the maximum
  number of groups, when wrapping according to group_wrap control.

- Be careful with negative relative group actions. The group fields of
  xkb_state are all unsigned (and have a weird FIXME..), so don't use
  them directly.

- Add the grp:ctrl_shift_toggle option to the rmlvo set to also test
  locking the previous group (i.e. a negative relative group action).

Signed-off-by: Ran Benita <ran234@gmail.com>
Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
This commit is contained in:
Ran Benita 2011-12-29 21:46:56 +02:00 committed by David Herrmann
parent 83b95f643f
commit bb499f7513
2 changed files with 33 additions and 24 deletions

View File

@ -832,9 +832,14 @@ static bool process_group_action(struct xkb_desc *desc, struct xkb_state *state,
uint8_t flags = action->flags;
/*
* Note: action->group is signed and may be negative if GroupAbsolute
* is not set. A group itself cannot be negative.
* action->group is signed and may be negative if GroupAbsolute
* is not set. A group itself cannot be negative and is unsigend.
* Therefore we extend these to int16 to avoid underflow and
* signedness issues. Be careful!
*/
int16_t base_group = state->base_group;
int16_t latched_group = state->latched_group;
int16_t locked_group = state->locked_group;
/*
* FIXME: Some actions here should be conditioned "and no keys are
@ -845,28 +850,27 @@ static bool process_group_action(struct xkb_desc *desc, struct xkb_state *state,
case XkbSA_SetGroup:
if (key_state == KEY_STATE_PRESSED) {
if (flags & XkbSA_GroupAbsolute)
state->base_group = group;
base_group = group;
else
state->base_group += action->group;
base_group += group;
} else if (key_state == KEY_STATE_RELEASED) {
if (flags & XkbSA_ClearLocks)
state->locked_group = 0;
locked_group = 0;
}
break;
case XkbSA_LatchGroup:
if (key_state == KEY_STATE_PRESSED) {
if (flags & XkbSA_GroupAbsolute)
state->base_group = group;
base_group = group;
else
state->base_group += action->group;
base_group += group;
} else if (key_state == KEY_STATE_RELEASED) {
if ((flags & XkbSA_LatchToLock) &&
state->latched_group) {
state->locked_group += group;
state->latched_group -= group;
if ((flags & XkbSA_LatchToLock) && latched_group) {
locked_group += group;
latched_group -= group;
} else {
state->latched_group += group;
latched_group += group;
}
}
@ -874,14 +878,18 @@ static bool process_group_action(struct xkb_desc *desc, struct xkb_state *state,
case XkbSA_LockGroup:
if (key_state == KEY_STATE_PRESSED) {
if (flags & XkbSA_GroupAbsolute)
state->locked_group = group;
locked_group = group;
else
state->locked_group += group;
locked_group += group;
}
break;
}
/* Bring what was changed back into range. */
state->base_group = wrap_group_control(desc, base_group);
state->locked_group = wrap_group_control(desc, locked_group);
state->latched_group = wrap_group_control(desc, latched_group);
update_effective_group(desc, state);
return true;
}
@ -898,8 +906,14 @@ static uint8_t wrap_group(int16_t group, int num_groups, uint8_t group_info)
switch (XkbOutOfRangeGroupAction(group_info)) {
case XkbWrapIntoRange:
/* This is the default, common method. */
return group % num_groups;
/*
* C99 says a negative dividend in a modulo operation
* will always give a negative result.
*/
if (group < 0)
return num_groups + (group % num_groups);
else
return group % num_groups;
case XkbClampIntoRange:
/* This one seems to be unused. */
@ -907,7 +921,7 @@ static uint8_t wrap_group(int16_t group, int num_groups, uint8_t group_info)
case XkbRedirectIntoRange:
/* This one seems to be unused. */
group = XkbOutOfRangeGroupInfo(group_info);
group = XkbOutOfRangeGroupNumber(group_info);
/* If it's _still_ out of range, use the first group. */
if (group >= num_groups)
return 0;
@ -928,7 +942,7 @@ static uint8_t wrap_group_control(struct xkb_desc *desc, int16_t group)
int num_groups;
uint8_t group_info;
num_groups = XkbNumKbdGroups;
num_groups = desc->ctrls->num_groups;
group_info = desc->ctrls->groups_wrap;
return wrap_group(group, num_groups, group_info);
@ -972,11 +986,6 @@ static void update_effective_group(struct xkb_desc *desc,
{
int16_t group;
/* Bring what was changed back into range. */
state->base_group = wrap_group_control(desc, state->base_group);
state->locked_group = wrap_group_control(desc, state->locked_group);
state->latched_group = wrap_group_control(desc, state->latched_group);
/* Update the effective group. */
group = state->base_group + state->locked_group + state->latched_group;
state->group = wrap_group_control(desc, group);

View File

@ -244,7 +244,7 @@ int kmscon_input_new(struct kmscon_input **out)
/* TODO: Make configurable */
static const char *layout = "us,ru,il";
static const char *variant = "intl,,biblical";
static const char *options = "grp:menu_toggle";
static const char *options = "grp:menu_toggle,grp:ctrl_shift_toggle";
if (!out)
return -EINVAL;