Skip to content

Commit

Permalink
symbols: Fix key symbols/actions merge
Browse files Browse the repository at this point in the history
  • Loading branch information
wismill committed Dec 19, 2024
1 parent 09ae28a commit b946df1
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 39 deletions.
24 changes: 24 additions & 0 deletions src/keymap-priv.c
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,30 @@ XkbLevelsSameSyms(const struct xkb_level *a, const struct xkb_level *b)
return memcmp(a->s.syms, b->s.syms, sizeof(*a->s.syms) * a->num_syms) == 0;
}

bool
XkbLevelHasNoKeysym(const struct xkb_level *level)
{
if (level->num_syms == 0)
return true;
if (level->num_syms == 1)
return level->s.sym == XKB_KEY_NoSymbol;
for (unsigned int k = 0; k < level->num_syms; k++) {
if (level->s.syms[k] != XKB_KEY_NoSymbol)
return false;
}
return true;
}

bool
XkbLevelsSameActions(const struct xkb_level *a, const struct xkb_level *b)
{
if (a->num_syms != b->num_syms)
return false;
if (a->num_syms <= 1)
return memcmp(&a->a.action, &b->a.action, sizeof(a->a.action)) == 0;
return memcmp(a->a.actions, b->a.actions, sizeof(*a->a.actions) * a->num_syms) == 0;
}

bool
XkbLevelHasNoAction(const struct xkb_level *level)
{
Expand Down
6 changes: 6 additions & 0 deletions src/keymap.h
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,12 @@ XkbModNameToIndex(const struct xkb_mod_set *mods, xkb_atom_t name,
bool
XkbLevelsSameSyms(const struct xkb_level *a, const struct xkb_level *b);

bool
XkbLevelHasNoKeysym(const struct xkb_level *level);

bool
XkbLevelsSameActions(const struct xkb_level *a, const struct xkb_level *b);

bool
XkbLevelHasNoAction(const struct xkb_level *level);

Expand Down
124 changes: 85 additions & 39 deletions src/xkbcomp/symbols.c
Original file line number Diff line number Diff line change
Expand Up @@ -302,17 +302,52 @@ MergeGroups(SymbolsInfo *info, GroupInfo *into, GroupInfo *from, bool clobber,
struct xkb_level *intoLevel = &darray_item(into->levels, i);
struct xkb_level *fromLevel = &darray_item(from->levels, i);

if (fromLevel->num_syms == 0) {
/* it's empty for consistency with other comparisons */
const bool fromHasNoKeysym = XkbLevelHasNoKeysym(fromLevel);
const bool fromHasNoAction = XkbLevelHasNoAction(fromLevel);
if (fromHasNoKeysym && fromHasNoAction) {
/* Empty `from`: do nothing */
continue;
}
else if (intoLevel->num_syms == 0) {

const bool intoHasNoKeysym = XkbLevelHasNoKeysym(intoLevel);
const bool intoHasNoAction = XkbLevelHasNoAction(intoLevel);
if (intoHasNoKeysym && intoHasNoAction) {
/* Empty `into`: use `from` keysyms and actions */
StealLevelInfo(intoLevel, fromLevel);
continue;
}

if (intoLevel->num_syms != fromLevel->num_syms) {
/* Handle different keysyms/actions count */
assert(intoLevel->num_syms > 0);
assert(fromLevel->num_syms > 0);
if (report) {
log_warn(info->ctx, XKB_WARNING_CONFLICTING_KEY_SYMBOL,
"Multiple definitions for level %d/group %u on key %s "
"with incompatible keysyms/actions count; "
"Using %s (count: %u), ignoring %s (count: %u)\n",
i + 1, group + 1, KeyNameText(info->ctx, key_name),
(clobber ? "from" : "to"),
(clobber ? fromLevel->num_syms : intoLevel->num_syms),
(clobber ? "to" : "from"),
(clobber ? intoLevel->num_syms : fromLevel->num_syms));
}
if (clobber) {
/* There is no obvious way to deal with this case other than
* just cloning `from` */
StealLevelInfo(intoLevel, fromLevel);
}
continue;
}
else {
bool actions_replaced = false;
/* Possible level conflict */
assert(intoLevel->num_syms > 0);
assert(fromLevel->num_syms == intoLevel->num_syms);

/* Handle keysyms */
if (!XkbLevelsSameSyms(fromLevel, intoLevel)) {
if (report) {
/* Incompatible keysyms */
if (report && !(intoHasNoKeysym || fromHasNoKeysym)) {
log_warn(info->ctx, XKB_WARNING_CONFLICTING_KEY_SYMBOL,
"Multiple symbols for level %d/group %u on key %s; "
"Using %s, ignoring %s\n",
Expand All @@ -322,45 +357,34 @@ MergeGroups(SymbolsInfo *info, GroupInfo *into, GroupInfo *from, bool clobber,
}

if (clobber) {
/* Use `from` keysyms and actions */
if (report && !XkbLevelHasNoAction(intoLevel)) {
if (fromLevel->num_syms > 1) {
log_warn(
info->ctx, XKB_WARNING_CONFLICTING_KEY_ACTION,
"Multiple actions for level %d/group %u "
"on key %s; Using from, ignoring to\n",
i + 1, group + 1,
KeyNameText(info->ctx, key_name));
} else {
log_warn(
info->ctx, XKB_WARNING_CONFLICTING_KEY_ACTION,
"Multiple actions for level %d/group %u "
"on key %s; Using %s, ignoring %s\n",
i + 1, group + 1,
KeyNameText(info->ctx, key_name),
ActionTypeText(fromLevel->a.action.type),
ActionTypeText(intoLevel->a.action.type));
/* Override: copy any defined keysym from `from` */
if (unlikely(intoLevel->num_syms > 1)) {
for (unsigned int k = 0; k < fromLevel->num_syms; k++) {
if (fromLevel->s.syms[k] != XKB_KEY_NoSymbol)
intoLevel->s.syms[k] = fromLevel->s.syms[k];
}
} else if (fromLevel->s.sym != XKB_KEY_NoSymbol) {
intoLevel->s.sym = fromLevel->s.sym;
}
} else {
/* Augment: copy only the keysyms from `from` that are
* undefined in `into` */
if (unlikely(intoLevel->num_syms > 1)) {
for (unsigned int k = 0; k < intoLevel->num_syms; k++) {
if (intoLevel->s.syms[k] == XKB_KEY_NoSymbol)
intoLevel->s.syms[k] = fromLevel->s.syms[k];
}
} else if (intoLevel->s.sym == XKB_KEY_NoSymbol) {
intoLevel->s.sym = fromLevel->s.sym;
}
StealLevelInfo(intoLevel, fromLevel);
actions_replaced = true;
}
}

/* Handle actions */
if (actions_replaced) {
/* Already handled, included incompatible keysyms/actions count */
} else if (XkbLevelHasNoAction(fromLevel)) {
/* It's empty for consistency with other comparisons */
} else if (XkbLevelHasNoAction(intoLevel)) {
/* Take actions from `from` */
assert(intoLevel->num_syms == fromLevel->num_syms);
StealLevelInfo(intoLevel, fromLevel);
} else {
if (!XkbLevelsSameActions(intoLevel, fromLevel)) {
/* Incompatible actions */
assert(intoLevel->num_syms == fromLevel->num_syms);
if (report) {
if (intoLevel->num_syms > 1) {
if (report && !(intoHasNoAction || fromHasNoAction)) {
if (unlikely(intoLevel->num_syms > 1)) {
log_warn(
info->ctx, XKB_WARNING_CONFLICTING_KEY_ACTION,
"Multiple actions for level %d/group %u on key %s; "
Expand All @@ -386,14 +410,36 @@ MergeGroups(SymbolsInfo *info, GroupInfo *into, GroupInfo *from, bool clobber,
ActionTypeText(ignore->type));
}
}
if (clobber)
StealLevelInfo(intoLevel, fromLevel);
if (clobber) {
/* Override: copy any defined action from `from` */
if (unlikely(fromLevel->num_syms > 1)) {
for (unsigned int k = 0; k < fromLevel->num_syms; k++) {
if (fromLevel->a.actions[k].type != ACTION_TYPE_NONE)
intoLevel->a.actions[k] = fromLevel->a.actions[k];
}
} else if (fromLevel->a.action.type != ACTION_TYPE_NONE) {
intoLevel->a.action = fromLevel->a.action;
}
} else {
/* Augment: copy only the actions from `from` that are
* undefined in `into` */
if (unlikely(intoLevel->num_syms > 1)) {
for (unsigned int k = 0; k < intoLevel->num_syms; k++) {
if (intoLevel->a.actions[k].type == ACTION_TYPE_NONE)
intoLevel->a.actions[k] = fromLevel->a.actions[k];
}
} else if (intoLevel->a.action.type == ACTION_TYPE_NONE) {
intoLevel->a.action = fromLevel->a.action;
}
}
}
}
}
/* If @from has extra levels, get them as well. */
darray_foreach_from(level, from->levels, levels_in_both) {
darray_append(into->levels, *level);
/* We may have stolen keysyms or actions arrays:
* do not free them when clearing `from` */
level->num_syms = 0;
}
into->defined |= (from->defined & GROUP_FIELD_ACTS);
Expand Down

0 comments on commit b946df1

Please sign in to comment.