#include "vmod.h"
#include "keycodes.h"
#include "include.h"
+#include "keysym.h"
enum key_repeat {
+ KEY_REPEAT_UNDEFINED = 0,
KEY_REPEAT_YES = 1,
- KEY_REPEAT_NO = 0,
- KEY_REPEAT_UNDEFINED = -1
+ KEY_REPEAT_NO = 2,
};
enum group_field {
};
typedef struct {
- enum group_field defined;
+ unsigned int num_syms;
+ unsigned int sym_index;
+ union xkb_action act;
+} LevelInfo;
- xkb_level_index_t numLevels;
- darray(xkb_keysym_t) syms;
- /*
- * symsMapIndex[level] -> The index from which the syms for the
- * level begin in the syms array. Remember each keycode can have
- * multiple keysyms in each level (that is, each key press can
- * result in multiple keysyms).
- */
- darray(int) symsMapIndex;
- /*
- * symsMapNumEntries[level] -> How many syms are in
- * syms[symsMapIndex[level]].
- */
- darray(unsigned int) symsMapNumEntries;
- darray(union xkb_action) acts;
+typedef darray(xkb_keysym_t) darray_xkb_keysym_t;
+
+typedef struct {
+ enum group_field defined;
+ darray_xkb_keysym_t syms;
+ darray(LevelInfo) levels;
xkb_atom_t type;
} GroupInfo;
unsigned long name; /* the 4 chars of the key name, as long */
- GroupInfo groups[XKB_NUM_GROUPS];
+ darray(GroupInfo) groups;
enum key_repeat repeat;
xkb_mod_mask_t vmodmap;
xkb_atom_t dfltType;
enum xkb_range_exceed_type out_of_range_group_action;
- xkb_group_index_t out_of_range_group_number;
+ xkb_layout_index_t out_of_range_group_number;
} KeyInfo;
static void
ClearGroupInfo(GroupInfo *groupi)
{
darray_free(groupi->syms);
- darray_free(groupi->symsMapIndex);
- darray_free(groupi->symsMapNumEntries);
- darray_free(groupi->acts);
- InitGroupInfo(groupi);
+ darray_free(groupi->levels);
}
static void
InitKeyInfo(KeyInfo *keyi, unsigned file_id)
{
- xkb_group_index_t i;
- static const char dflt[4] = "*";
+ static const char dflt_key_name[XKB_KEY_NAME_LENGTH] = "*";
- keyi->defined = 0;
+ memset(keyi, 0, sizeof(*keyi));
keyi->file_id = file_id;
keyi->merge = MERGE_OVERRIDE;
- keyi->name = KeyNameToLong(dflt);
- for (i = 0; i < XKB_NUM_GROUPS; i++)
- InitGroupInfo(&keyi->groups[i]);
- keyi->dfltType = XKB_ATOM_NONE;
- keyi->vmodmap = 0;
- keyi->repeat = KEY_REPEAT_UNDEFINED;
+ keyi->name = KeyNameToLong(dflt_key_name);
keyi->out_of_range_group_action = RANGE_WRAP;
- keyi->out_of_range_group_number = 0;
}
static void
ClearKeyInfo(KeyInfo *keyi)
{
- xkb_group_index_t i;
-
- for (i = 0; i < XKB_NUM_GROUPS; i++)
- ClearGroupInfo(&keyi->groups[i]);
-}
-
-static bool
-CopyKeyInfo(KeyInfo * old, KeyInfo * new, bool clearOld)
-{
- xkb_group_index_t i;
-
- *new = *old;
-
- if (clearOld) {
- for (i = 0; i < XKB_NUM_GROUPS; i++) {
- InitGroupInfo(&old->groups[i]);
- }
- }
- else {
- for (i = 0; i < XKB_NUM_GROUPS; i++) {
- GroupInfo *n = &new->groups[i], *o = &old->groups[i];
- darray_copy(n->syms, o->syms);
- darray_copy(n->symsMapIndex, o->symsMapIndex);
- darray_copy(n->symsMapNumEntries, o->symsMapNumEntries);
- darray_copy(n->acts, o->acts);
- }
- }
-
- return true;
+ GroupInfo *groupi;
+ darray_foreach(groupi, keyi->groups)
+ ClearGroupInfo(groupi);
+ darray_free(keyi->groups);
}
/***====================================================================***/
int errorCount;
unsigned file_id;
enum merge_mode merge;
- xkb_group_index_t explicit_group;
+ xkb_layout_index_t explicit_group;
darray(KeyInfo) keys;
KeyInfo dflt;
VModInfo vmods;
ActionsInfo *actions;
- xkb_atom_t groupNames[XKB_NUM_GROUPS];
+ xkb_atom_t group_names[XKB_NUM_GROUPS];
darray(ModMapEntry) modMaps;
struct xkb_keymap *keymap;
InitSymbolsInfo(SymbolsInfo *info, struct xkb_keymap *keymap,
unsigned file_id, ActionsInfo *actions)
{
- xkb_group_index_t i;
-
- info->name = NULL;
- info->explicit_group = 0;
- info->errorCount = 0;
+ memset(info, 0, sizeof(*info));
+ info->keymap = keymap;
info->file_id = file_id;
info->merge = MERGE_OVERRIDE;
- darray_init(info->keys);
- darray_growalloc(info->keys, 110);
- darray_init(info->modMaps);
- for (i = 0; i < XKB_NUM_GROUPS; i++)
- info->groupNames[i] = XKB_ATOM_NONE;
InitKeyInfo(&info->dflt, file_id);
InitVModInfo(&info->vmods, keymap);
info->actions = actions;
- info->keymap = keymap;
}
static void
ClearSymbolsInfo(SymbolsInfo * info)
{
KeyInfo *keyi;
-
free(info->name);
darray_foreach(keyi, info->keys)
ClearKeyInfo(keyi);
darray_free(info->keys);
darray_free(info->modMaps);
- memset(info, 0, sizeof(SymbolsInfo));
+ ClearKeyInfo(&info->dflt);
}
static bool
-ResizeGroupInfo(GroupInfo *groupi, xkb_level_index_t numLevels,
- unsigned sizeSyms, bool forceActions)
-{
- xkb_level_index_t i;
-
- if (darray_size(groupi->syms) < sizeSyms)
- darray_resize0(groupi->syms, sizeSyms);
-
- if (darray_empty(groupi->symsMapIndex) ||
- groupi->numLevels < numLevels) {
- darray_resize(groupi->symsMapIndex, numLevels);
- for (i = groupi->numLevels; i < numLevels; i++)
- darray_item(groupi->symsMapIndex, i) = -1;
- }
-
- if (darray_empty(groupi->symsMapNumEntries) ||
- groupi->numLevels < numLevels)
- darray_resize0(groupi->symsMapNumEntries, numLevels);
-
- if ((forceActions && (groupi->numLevels < numLevels ||
- darray_empty(groupi->acts))) ||
- (groupi->numLevels < numLevels && !darray_empty(groupi->acts)))
- darray_resize0(groupi->acts, numLevels);
-
- groupi->numLevels = MAX(groupi->numLevels, numLevels);
-
- return true;
-}
-
-enum key_group_selector {
- NONE = 0,
- FROM = (1 << 0),
- TO = (1 << 1),
-};
-
-/*
- * Merge @from into @into, where both are groups with the same index
- * for the same key, and have at least on level to merge.
- * @group and @key_name are just for reporting.
- */
-static bool
MergeGroups(SymbolsInfo *info, GroupInfo *into, GroupInfo *from, bool clobber,
- bool report, xkb_group_index_t group, unsigned long key_name)
+ bool report, xkb_layout_index_t group, unsigned long key_name)
{
- GroupInfo result;
- unsigned int resultSize = 0;
- enum key_group_selector using = NONE;
- unsigned int cur_idx = 0;
- xkb_level_index_t i;
+ xkb_level_index_t i, numLevels;
+ enum { INTO = (1 << 0), FROM = (1 << 1) } using;
/* First find the type of the merged group. */
- if (into->type != from->type && from->type != XKB_ATOM_NONE) {
- if (into->type == XKB_ATOM_NONE) {
+ if (into->type != from->type) {
+ if (from->type == XKB_ATOM_NONE) {
+ }
+ else if (into->type == XKB_ATOM_NONE) {
into->type = from->type;
}
else {
- xkb_atom_t use, ignore;
-
- use = (clobber ? from->type : into->type);
- ignore = (clobber ? into->type : from->type);
+ xkb_atom_t use = (clobber ? from->type : into->type);
+ xkb_atom_t ignore = (clobber ? into->type : from->type);
if (report)
log_warn(info->keymap->ctx,
into->type = use;
}
-
- into->defined |= GROUP_FIELD_TYPE;
}
+ into->defined |= (from->defined & GROUP_FIELD_TYPE);
/* Now look at the levels. */
- /* Easy case: @from is empty. Just stick with @into. */
- if (from->numLevels == 0) {
+ if (darray_empty(from->levels)) {
InitGroupInfo(from);
return true;
}
- /* Easy case: @into is empty. Just copy @from as-is. */
- if (into->numLevels == 0) {
+ if (darray_empty(into->levels)) {
from->type = into->type;
*into = *from;
InitGroupInfo(from);
return true;
}
- /*
- * Hard case: need to start merging levels. The aim is to avoid
- * copying/allocating where possible.
- */
-
- InitGroupInfo(&result);
-
- if (into->numLevels >= from->numLevels) {
- result.acts = into->acts;
- result.numLevels = into->numLevels;
- }
- else {
- result.acts = from->acts;
- result.numLevels = from->numLevels;
- darray_resize(into->symsMapIndex, from->numLevels);
- darray_resize0(into->symsMapNumEntries, from->numLevels);
- for (i = into->numLevels; i < from->numLevels; i++)
- darray_item(into->symsMapIndex, i) = -1;
- }
-
- if (darray_empty(result.acts) && (!darray_empty(into->acts) ||
- !darray_empty(from->acts))) {
- darray_resize0(result.acts, result.numLevels);
- for (i = 0; i < result.numLevels; i++) {
- union xkb_action *fromAct = NULL, *toAct = NULL;
-
- if (!darray_empty(from->acts))
- fromAct = &darray_item(from->acts, i);
+ /* First we merge the actions and ensure @into has all the levels. */
+ numLevels = MAX(darray_size(into->levels), darray_size(from->levels));
+ for (i = 0; i < numLevels; i++) {
+ union xkb_action *intoAct, *fromAct;
- if (!darray_empty(into->acts))
- toAct = &darray_item(into->acts, i);
+ if (i >= darray_size(from->levels))
+ continue;
- if (((fromAct == NULL) || (fromAct->type == ACTION_TYPE_NONE))
- && (toAct != NULL)) {
- darray_item(result.acts, i) = *toAct;
- }
- else if (((toAct == NULL) || (toAct->type == ACTION_TYPE_NONE))
- && (fromAct != NULL)) {
- darray_item(result.acts, i) = *fromAct;
- }
- else {
- union xkb_action *use, *ignore;
- if (clobber) {
- use = fromAct;
- ignore = toAct;
- }
- else {
- use = toAct;
- ignore = fromAct;
- }
- if (report)
- log_warn(info->keymap->ctx,
- "Multiple actions for level %d/group %u on key %s; "
- "Using %s, ignoring %s\n",
- i + 1, group + 1, LongKeyNameText(key_name),
- ActionTypeText(use->type),
- ActionTypeText(ignore->type));
- if (use)
- darray_item(result.acts, i) = *use;
- }
+ if (i >= darray_size(into->levels)) {
+ darray_append(into->levels, darray_item(from->levels, i));
+ darray_item(into->levels, i).num_syms = 0;
+ darray_item(into->levels, i).sym_index = 0;
+ continue;
}
- }
-
- for (i = 0; i < result.numLevels; i++) {
- unsigned int fromSize = 0;
- unsigned int toSize = 0;
- if (!darray_empty(from->symsMapNumEntries) && i < from->numLevels)
- fromSize = darray_item(from->symsMapNumEntries, i);
+ intoAct = &darray_item(into->levels, i).act;
+ fromAct = &darray_item(from->levels, i).act;
- if (!darray_empty(into->symsMapNumEntries) && i < into->numLevels)
- toSize = darray_item(into->symsMapNumEntries, i);
-
- if (fromSize == 0) {
- resultSize += toSize;
- using |= TO;
+ if (fromAct->type == ACTION_TYPE_NONE) {
}
- else if (toSize == 0 || clobber) {
- resultSize += fromSize;
- using |= FROM;
+ else if (intoAct->type == ACTION_TYPE_NONE) {
+ *intoAct = *fromAct;
}
else {
- resultSize += toSize;
- using |= TO;
- }
- }
+ union xkb_action *use = (clobber ? fromAct : intoAct);
+ union xkb_action *ignore = (clobber ? intoAct : fromAct);
- if (resultSize == 0)
- goto out;
+ if (report)
+ log_warn(info->keymap->ctx,
+ "Multiple actions for level %d/group %u on key %s; "
+ "Using %s, ignoring %s\n",
+ i + 1, group + 1, LongKeyNameText(key_name),
+ ActionTypeText(use->type),
+ ActionTypeText(ignore->type));
- if (using == FROM) {
- result.syms = from->syms;
- darray_free(into->symsMapNumEntries);
- darray_free(into->symsMapIndex);
- into->symsMapNumEntries = from->symsMapNumEntries;
- into->symsMapIndex = from->symsMapIndex;
- darray_init(from->symsMapNumEntries);
- darray_init(from->symsMapIndex);
- goto out;
- }
- else if (using == TO) {
- result.syms = into->syms;
- goto out;
+ *intoAct = *use;
+ }
}
+ into->defined |= (from->defined & GROUP_FIELD_ACTS);
- darray_resize0(result.syms, resultSize);
-
- for (i = 0; i < result.numLevels; i++) {
- enum key_group_selector use = NONE;
- unsigned int fromSize = 0;
- unsigned int toSize = 0;
-
- if (i < from->numLevels)
- fromSize = darray_item(from->symsMapNumEntries, i);
+ /* Then merge the keysyms. */
- if (i < into->numLevels)
- toSize = darray_item(into->symsMapNumEntries, i);
+ /*
+ * We want to avoid copying and allocating if not necessary. So
+ * here we do a pre-scan of the levels to check if we'll only use
+ * @into's or @from's keysyms, and if so we'll just assign them.
+ * However if one level uses @into's and another uses @from's, we
+ * will need to construct a new syms array.
+ */
+ using = 0;
+ for (i = 0; i < numLevels; i++) {
+ unsigned int intoSize, fromSize;
- if (fromSize == 0 && toSize == 0) {
- darray_item(into->symsMapIndex, i) = -1;
- darray_item(into->symsMapNumEntries, i) = 0;
- continue;
- }
+ intoSize = darray_item(into->levels, i).num_syms;
+ if (i < darray_size(from->levels))
+ fromSize = darray_item(from->levels, i).num_syms;
+ else
+ fromSize = 0;
- if (fromSize == 0)
- use = TO;
- else if (toSize == 0 || clobber)
- use = FROM;
+ if (intoSize == 0 && fromSize == 0)
+ using |= 0;
+ else if (intoSize == 0)
+ using |= FROM;
+ else if (fromSize == 0)
+ using |= INTO;
else
- use = TO;
-
- if (toSize && fromSize && report) {
- log_info(info->keymap->ctx,
- "Multiple symbols for group %u, level %d on key %s; "
- "Using %s, ignoring %s\n",
- group + 1, i + 1, LongKeyNameText(key_name),
- (use == FROM ? "from" : "to"),
- (use == FROM ? "to" : "from"));
- }
+ using |= (clobber ? FROM : INTO);
+ }
- if (use == FROM) {
- memcpy(darray_mem(result.syms, cur_idx),
- darray_mem(from->syms, darray_item(from->symsMapIndex, i)),
- darray_item(from->symsMapNumEntries, i) * sizeof(xkb_keysym_t));
- darray_item(into->symsMapIndex, i) = cur_idx;
- darray_item(into->symsMapNumEntries, i) =
- darray_item(from->symsMapNumEntries, i);
- }
- else {
- memcpy(darray_mem(result.syms, cur_idx),
- darray_mem(into->syms, darray_item(into->symsMapIndex, i)),
- darray_item(into->symsMapNumEntries, i) * sizeof(xkb_keysym_t));
- darray_item(into->symsMapIndex, i) = cur_idx;
+ if (using == 0 || using == INTO) {
+ }
+ else if (using == FROM) {
+ darray_free(into->syms);
+ into->syms = from->syms;
+ darray_init(from->syms);
+ for (i = 0; i < darray_size(from->levels); i++) {
+ darray_item(into->levels, i).num_syms =
+ darray_item(from->levels, i).num_syms;
+ darray_item(into->levels, i).sym_index =
+ darray_item(from->levels, i).sym_index;
}
-
- cur_idx += darray_item(into->symsMapNumEntries, i);
}
+ else {
+ darray_xkb_keysym_t syms = darray_new();
-out:
- into->numLevels = result.numLevels;
+ for (i = 0; i < numLevels; i++) {
+ unsigned int intoSize, fromSize;
- if (!darray_same(result.acts, into->acts))
- darray_free(into->acts);
- if (!darray_same(result.acts, from->acts))
- darray_free(from->acts);
- into->acts = result.acts;
- into->defined |= GROUP_FIELD_ACTS;
- darray_init(from->acts);
- from->defined &= ~GROUP_FIELD_ACTS;
+ intoSize = darray_item(into->levels, i).num_syms;
+ if (i < darray_size(from->levels))
+ fromSize = darray_item(from->levels, i).num_syms;
+ else
+ fromSize = 0;
+
+ /* Empty level. */
+ if (intoSize == 0 && fromSize == 0)
+ continue;
- if (!darray_same(result.syms, into->syms))
+ if (intoSize != 0 && fromSize != 0 && report)
+ log_info(info->keymap->ctx,
+ "Multiple symbols for group %u, level %d on key %s; "
+ "Using %s, ignoring %s\n",
+ group + 1, i + 1, LongKeyNameText(key_name),
+ (clobber ? "from" : "to"),
+ (clobber ? "to" : "from"));
+
+ if (intoSize == 0 || (fromSize != 0 && clobber)) {
+ unsigned sym_index = darray_item(from->levels, i).sym_index;
+ darray_item(into->levels, i).sym_index = darray_size(syms);
+ darray_item(into->levels, i).num_syms = fromSize;
+ darray_append_items(syms, &darray_item(from->syms, sym_index),
+ fromSize);
+ }
+ else
+ {
+ unsigned sym_index = darray_item(into->levels, i).sym_index;
+ darray_item(into->levels, i).sym_index = darray_size(syms);
+ darray_item(into->levels, i).num_syms = intoSize;
+ darray_append_items(syms, &darray_item(into->syms, sym_index),
+ intoSize);
+ }
+ }
darray_free(into->syms);
- if (!darray_same(result.syms, from->syms))
- darray_free(from->syms);
- into->syms = result.syms;
- if (darray_empty(into->syms))
- into->defined &= ~GROUP_FIELD_SYMS;
- else
- into->defined |= GROUP_FIELD_SYMS;
- darray_init(from->syms);
- from->defined &= ~GROUP_FIELD_SYMS;
-
- darray_free(from->symsMapIndex);
- darray_free(from->symsMapNumEntries);
+ into->syms = syms;
+ }
+ into->defined |= (from->defined & GROUP_FIELD_SYMS);
return true;
}
}
-/* Merge @from into @into, where both contain info for the same key. */
static bool
MergeKeys(SymbolsInfo *info, KeyInfo *into, KeyInfo *from)
{
- xkb_group_index_t i;
+ xkb_layout_index_t i;
+ xkb_layout_index_t groups_in_both;
enum key_field collide = 0;
bool clobber, report;
- int verbosity = xkb_get_log_verbosity(info->keymap->ctx);
+ int verbosity = xkb_context_get_log_verbosity(info->keymap->ctx);
- /* Forget about @into; just copy @from as-is. */
if (from->merge == MERGE_REPLACE) {
- for (i = 0; i < XKB_NUM_GROUPS; i++)
- if (into->groups[i].numLevels != 0)
- ClearGroupInfo(&into->groups[i]);
+ ClearKeyInfo(into);
*into = *from;
InitKeyInfo(from, info->file_id);
return true;
report = (verbosity > 9 ||
(into->file_id == from->file_id && verbosity > 0));
- /* Start looking into the key groups. */
- for (i = 0; i < XKB_NUM_GROUPS; i++)
- MergeGroups(info, &into->groups[i], &from->groups[i], clobber,
- report, i, into->name);
+ groups_in_both = MIN(darray_size(into->groups),
+ darray_size(from->groups));
+ for (i = 0; i < groups_in_both; i++)
+ MergeGroups(info,
+ &darray_item(into->groups, i),
+ &darray_item(from->groups, i),
+ clobber, report, i, into->name);
+ /* If @from has extra groups, just move them to @into. */
+ for (i = groups_in_both; i < darray_size(from->groups); i++) {
+ darray_append(into->groups, darray_item(from->groups, i));
+ InitGroupInfo(&darray_item(from->groups, i));
+ }
if (UseNewKeyField(KEY_FIELD_VMODMAP, into->defined, from->defined,
clobber, report, &collide)) {
LongKeyNameText(into->name),
(clobber ? "first" : "last"));
+ ClearKeyInfo(from);
+ InitKeyInfo(from, info->file_id);
return true;
}
AddKeySymbols(SymbolsInfo *info, KeyInfo *keyi)
{
unsigned long real_name;
- KeyInfo *iter, *new;
+ KeyInfo *iter;
+
+ /*
+ * Don't keep aliases in the keys array; this guarantees that
+ * searching for keys to merge with by straight comparison (see the
+ * following loop) is enough, and we won't get multiple KeyInfo's
+ * for the same key because of aliases.
+ */
+ if (FindKeyNameForAlias(info->keymap, keyi->name, &real_name))
+ keyi->name = real_name;
darray_foreach(iter, info->keys)
if (iter->name == keyi->name)
return MergeKeys(info, iter, keyi);
- if (FindKeyNameForAlias(info->keymap, keyi->name, &real_name))
- darray_foreach(iter, info->keys)
- if (iter->name == real_name)
- return MergeKeys(info, iter, keyi);
-
- darray_resize0(info->keys, darray_size(info->keys) + 1);
- new = &darray_item(info->keys, darray_size(info->keys) - 1);
- return CopyKeyInfo(keyi, new, true);
+ darray_append(info->keys, *keyi);
+ InitKeyInfo(keyi, info->file_id);
+ return true;
}
static bool
from->name = NULL;
}
for (i = 0; i < XKB_NUM_GROUPS; i++) {
- if (from->groupNames[i] != XKB_ATOM_NONE) {
+ if (from->group_names[i] != XKB_ATOM_NONE) {
if ((merge != MERGE_AUGMENT) ||
- (into->groupNames[i] == XKB_ATOM_NONE))
- into->groupNames[i] = from->groupNames[i];
+ (into->group_names[i] == XKB_ATOM_NONE))
+ into->group_names[i] = from->group_names[i];
}
}
InitSymbolsInfo(&next_incl, info->keymap, rtrn->id, info->actions);
next_incl.merge = next_incl.dflt.merge = MERGE_OVERRIDE;
- if (stmt->modifier)
+ if (stmt->modifier) {
next_incl.explicit_group = atoi(stmt->modifier) - 1;
- else
+ if (next_incl.explicit_group >= XKB_NUM_GROUPS) {
+ log_err(info->keymap->ctx,
+ "Cannot set explicit group to %d - must be between 1..%d; "
+ "Ignoring group number\n",
+ next_incl.explicit_group + 1, XKB_NUM_GROUPS);
+ next_incl.explicit_group = info->explicit_group;
+ }
+ }
+ else {
next_incl.explicit_group = info->explicit_group;
+ }
HandleSymbolsFile(&next_incl, rtrn, MERGE_OVERRIDE);
static bool
GetGroupIndex(SymbolsInfo *info, KeyInfo *keyi, ExprDef *arrayNdx,
- unsigned what, xkb_group_index_t *ndx_rtrn)
+ unsigned what, xkb_layout_index_t *ndx_rtrn)
{
const char *name = (what == SYMBOLS ? "symbols" : "actions");
if (arrayNdx == NULL) {
- xkb_group_index_t i;
+ xkb_layout_index_t i;
+ GroupInfo *groupi;
enum group_field field = (what == SYMBOLS ?
GROUP_FIELD_SYMS : GROUP_FIELD_ACTS);
- for (i = 0; i < XKB_NUM_GROUPS; i++) {
- if (!(keyi->groups[i].defined & field)) {
+ darray_enumerate(i, groupi, keyi->groups) {
+ if (!(groupi->defined & field)) {
*ndx_rtrn = i;
return true;
}
}
- log_err(info->keymap->ctx,
- "Too many groups of %s for key %s (max %u); "
- "Ignoring %s defined for extra groups\n",
- name, LongKeyNameText(keyi->name), XKB_NUM_GROUPS + 1, name);
- return false;
+ if (i >= XKB_NUM_GROUPS) {
+ log_err(info->keymap->ctx,
+ "Too many groups of %s for key %s (max %u); "
+ "Ignoring %s defined for extra groups\n",
+ name, LongKeyNameText(keyi->name), XKB_NUM_GROUPS + 1, name);
+ return false;
+ }
+
+ darray_resize0(keyi->groups, darray_size(keyi->groups) + 1);
+ *ndx_rtrn = darray_size(keyi->groups) - 1;
+ return true;
}
if (!ExprResolveGroup(info->keymap->ctx, arrayNdx, ndx_rtrn)) {
}
(*ndx_rtrn)--;
+ if (*ndx_rtrn >= darray_size(keyi->groups))
+ darray_resize0(keyi->groups, *ndx_rtrn + 1);
+
return true;
}
AddSymbolsToKey(SymbolsInfo *info, KeyInfo *keyi, ExprDef *arrayNdx,
ExprDef *value)
{
- xkb_group_index_t ndx;
+ xkb_layout_index_t ndx;
GroupInfo *groupi;
unsigned int nSyms;
xkb_level_index_t nLevels;
if (!GetGroupIndex(info, keyi, arrayNdx, SYMBOLS, &ndx))
return false;
- groupi = &keyi->groups[ndx];
+ groupi = &darray_item(keyi->groups, ndx);
if (value == NULL) {
groupi->defined |= GROUP_FIELD_SYMS;
return false;
}
- if (!darray_empty(groupi->syms)) {
+ if (groupi->defined & GROUP_FIELD_SYMS) {
log_err(info->keymap->ctx,
"Symbols for key %s, group %u already defined; "
"Ignoring duplicate definition\n",
nSyms = darray_size(value->value.list.syms);
nLevels = darray_size(value->value.list.symsMapIndex);
- if ((groupi->numLevels < nSyms || darray_empty(groupi->syms))) {
- if (!ResizeGroupInfo(groupi, nLevels, nSyms, false)) {
- log_wsgo(info->keymap->ctx,
- "Could not resize group %u of key %s to contain %zu levels; "
- "Symbols lost\n",
- ndx + 1, LongKeyNameText(keyi->name), nSyms);
- return false;
- }
- }
+ if (darray_size(groupi->syms) < nSyms)
+ darray_resize0(groupi->syms, nSyms);
+
+ if (darray_size(groupi->levels) < nLevels)
+ darray_resize0(groupi->levels, nLevels);
groupi->defined |= GROUP_FIELD_SYMS;
for (i = 0; i < nLevels; i++) {
- darray_item(groupi->symsMapIndex, i) =
- darray_item(value->value.list.symsMapIndex, i);
- darray_item(groupi->symsMapNumEntries, i) =
- darray_item(value->value.list.symsNumEntries, i);
+ LevelInfo *leveli = &darray_item(groupi->levels, i);
- for (j = 0; j < darray_item(groupi->symsMapNumEntries, i); j++) {
- /* FIXME: What's abort() doing here? */
- if (darray_item(groupi->symsMapIndex, i) + j >= nSyms)
- abort();
+ leveli->sym_index = darray_item(value->value.list.symsMapIndex, i);
+ leveli->num_syms = darray_item(value->value.list.symsNumEntries, i);
+ for (j = 0; j < leveli->num_syms; j++) {
if (!LookupKeysym(darray_item(value->value.list.syms,
- darray_item(value->value.list.symsMapIndex, i) + j),
+ leveli->sym_index + j),
&darray_item(groupi->syms,
- darray_item(groupi->symsMapIndex, i) + j))) {
+ leveli->sym_index + j))) {
log_warn(info->keymap->ctx,
- "Could not resolve keysym %s for key %s, group %u (%s), level %zu\n",
+ "Could not resolve keysym %s for key %s, group %u (%s), level %u\n",
darray_item(value->value.list.syms, i),
LongKeyNameText(keyi->name),
ndx + 1,
xkb_atom_text(info->keymap->ctx,
- info->groupNames[ndx]),
+ info->group_names[ndx]),
nSyms);
-
- while (--j >= 0)
- darray_item(groupi->syms,
- darray_item(groupi->symsMapIndex, i) + j) = XKB_KEY_NoSymbol;
-
- darray_item(groupi->symsMapIndex, i) = -1;
- darray_item(groupi->symsMapNumEntries, i) = 0;
+ leveli->sym_index = 0;
+ leveli->num_syms = 0;
break;
}
- if (darray_item(groupi->symsMapNumEntries, i) == 1 &&
+ if (leveli->num_syms == 1 &&
darray_item(groupi->syms,
- darray_item(groupi->symsMapIndex, i) + j) == XKB_KEY_NoSymbol) {
- darray_item(groupi->symsMapIndex, i) = -1;
- darray_item(groupi->symsMapNumEntries, i) = 0;
+ leveli->sym_index + j) == XKB_KEY_NoSymbol) {
+ leveli->sym_index = 0;
+ leveli->num_syms = 0;
}
}
}
- for (j = groupi->numLevels - 1;
- j >= 0 && darray_item(groupi->symsMapNumEntries, j) == 0; j--)
- groupi->numLevels--;
+ for (j = darray_size(groupi->levels) - 1;
+ j >= 0 && darray_item(groupi->levels, j).num_syms == 0; j--)
+ (void) darray_pop(groupi->levels);
return true;
}
ExprDef *value)
{
unsigned int i;
- xkb_group_index_t ndx;
+ xkb_layout_index_t ndx;
GroupInfo *groupi;
unsigned int nActs;
ExprDef *act;
if (!GetGroupIndex(info, keyi, arrayNdx, ACTIONS, &ndx))
return false;
- groupi = &keyi->groups[ndx];
+ groupi = &darray_item(keyi->groups, ndx);
if (value == NULL) {
groupi->defined |= GROUP_FIELD_ACTS;
return false;
}
- if (!darray_empty(groupi->acts)) {
+ if (groupi->defined & GROUP_FIELD_ACTS) {
log_wsgo(info->keymap->ctx,
"Actions for key %s, group %u already defined\n",
LongKeyNameText(keyi->name), ndx);
return false;
}
- for (nActs = 0, act = value->value.child; act != NULL; nActs++) {
- act = (ExprDef *) act->common.next;
- }
-
- if (nActs < 1) {
- log_wsgo(info->keymap->ctx,
- "Action list but not actions in AddActionsToKey\n");
- return false;
- }
+ nActs = 0;
+ for (act = value->value.child; act; act = (ExprDef *) act->common.next)
+ nActs++;
- if ((groupi->numLevels < nActs || darray_empty(groupi->acts))) {
- if (!ResizeGroupInfo(&keyi->groups[ndx], nActs, nActs, true)) {
- log_wsgo(info->keymap->ctx,
- "Could not resize group %u of key %s; "
- "Actions lost\n",
- ndx, LongKeyNameText(keyi->name));
- return false;
- }
- }
+ if (darray_size(groupi->levels) < nActs)
+ darray_resize0(groupi->levels, nActs);
groupi->defined |= GROUP_FIELD_ACTS;
- toAct = darray_mem(groupi->acts, 0);
act = value->value.child;
- for (i = 0; i < nActs; i++, toAct++) {
- if (!HandleActionDef(act, info->keymap, toAct, info->actions)) {
+ for (i = 0; i < nActs; i++) {
+ toAct = &darray_item(groupi->levels, i).act;
+
+ if (!HandleActionDef(act, info->keymap, toAct, info->actions))
log_err(info->keymap->ctx,
"Illegal action definition for %s; "
"Action for group %u/level %u ignored\n",
LongKeyNameText(keyi->name), ndx + 1, i + 1);
- }
+
act = (ExprDef *) act->common.next;
}
struct xkb_context *ctx = info->keymap->ctx;
if (istreq(field, "type")) {
- xkb_group_index_t ndx;
+ xkb_layout_index_t ndx;
xkb_atom_t val;
if (!ExprResolveString(ctx, value, &val))
}
else {
ndx--;
- keyi->groups[ndx].type = val;
- keyi->groups[ndx].defined |= GROUP_FIELD_TYPE;
+ if (ndx >= darray_size(keyi->groups))
+ darray_resize0(keyi->groups, ndx + 1);
+ darray_item(keyi->groups, ndx).type = val;
+ darray_item(keyi->groups, ndx).defined |= GROUP_FIELD_TYPE;
}
}
else if (istreq(field, "symbols"))
}
else if (istreq(field, "groupsredirect") ||
istreq(field, "redirectgroups")) {
- xkb_group_index_t grp;
+ xkb_layout_index_t grp;
if (!ExprResolveGroup(ctx, value, &grp)) {
log_err(info->keymap->ctx,
static int
SetGroupName(SymbolsInfo *info, ExprDef *arrayNdx, ExprDef *value)
{
- xkb_group_index_t grp;
+ xkb_layout_index_t grp;
xkb_atom_t name;
if (!arrayNdx) {
return false;
}
- info->groupNames[grp - 1 + info->explicit_group] = name;
+ info->group_names[grp - 1 + info->explicit_group] = name;
return true;
}
static int
-HandleSymbolsVar(SymbolsInfo *info, VarDef *stmt)
+HandleGlobalVar(SymbolsInfo *info, VarDef *stmt)
{
const char *elem, *field;
ExprDef *arrayNdx;
for (; def; def = (VarDef *) def->common.next) {
if (def->name && def->name->op == EXPR_FIELD_REF) {
- ok = HandleSymbolsVar(info, def);
+ log_err(info->keymap->ctx,
+ "Cannot set a global default value from within a key statement; "
+ "Move statements to the global file scope\n");
continue;
}
static bool
SetExplicitGroup(SymbolsInfo *info, KeyInfo *keyi)
{
- xkb_group_index_t i;
+ xkb_layout_index_t i;
+ GroupInfo *groupi;
+ bool warn = false;
if (info->explicit_group == 0)
return true;
- for (i = 1; i < XKB_NUM_GROUPS; i++) {
- if (keyi->groups[i].defined) {
- log_warn(info->keymap->ctx,
- "For the map %s an explicit group specified, "
- "but key %s has more than one group defined; "
- "All groups except first one will be ignored\n",
- info->name, LongKeyNameText(keyi->name));
- break;
+ darray_enumerate_from(i, groupi, keyi->groups, 1) {
+ if (groupi->defined) {
+ warn = true;
+ ClearGroupInfo(groupi);
}
}
- if (i < XKB_NUM_GROUPS)
- for (i = 1; i < XKB_NUM_GROUPS; i++)
- ClearGroupInfo(&keyi->groups[i]);
- keyi->groups[info->explicit_group] = keyi->groups[0];
- InitGroupInfo(&keyi->groups[0]);
+ if (warn)
+ log_warn(info->keymap->ctx,
+ "For the map %s an explicit group specified, "
+ "but key %s has more than one group defined; "
+ "All groups except first one will be ignored\n",
+ info->name, LongKeyNameText(keyi->name));
+
+ darray_resize0(keyi->groups, info->explicit_group + 1);
+ darray_item(keyi->groups, info->explicit_group) =
+ darray_item(keyi->groups, 0);
+ InitGroupInfo(&darray_item(keyi->groups, 0));
return true;
}
HandleSymbolsDef(SymbolsInfo *info, SymbolsDef *stmt)
{
KeyInfo keyi;
-
- InitKeyInfo(&keyi, info->file_id);
- CopyKeyInfo(&info->dflt, &keyi, false);
+ xkb_layout_index_t i;
+
+ keyi = info->dflt;
+ darray_init(keyi.groups);
+ darray_copy(keyi.groups, info->dflt.groups);
+ for (i = 0; i < darray_size(keyi.groups); i++) {
+ darray_init(darray_item(keyi.groups, i).syms);
+ darray_copy(darray_item(keyi.groups, i).syms,
+ darray_item(info->dflt.groups, i).syms);
+ darray_init(darray_item(keyi.groups, i).levels);
+ darray_copy(darray_item(keyi.groups, i).levels,
+ darray_item(info->dflt.groups, i).levels);
+ }
keyi.merge = stmt->merge;
keyi.name = KeyNameToLong(stmt->keyName);
+
if (!HandleSymbolsBody(info, (VarDef *) stmt->symbols, &keyi)) {
info->errorCount++;
return false;
info->errorCount++;
return false;
}
+
return true;
}
ok = HandleSymbolsDef(info, (SymbolsDef *) stmt);
break;
case STMT_VAR:
- ok = HandleSymbolsVar(info, (VarDef *) stmt);
+ ok = HandleGlobalVar(info, (VarDef *) stmt);
break;
case STMT_VMOD:
ok = HandleVModDef((VModDef *) stmt, info->keymap, merge,
FindKeyForSymbol(struct xkb_keymap *keymap, xkb_keysym_t sym)
{
struct xkb_key *key, *ret = NULL;
- xkb_group_index_t group, min_group = UINT32_MAX;
+ xkb_layout_index_t group, min_group = UINT32_MAX;
xkb_level_index_t level, min_level = UINT16_MAX;
xkb_foreach_key(key, keymap) {
return ret;
}
-/**
- * Find the given name in the keymap->map->types and return its index.
- *
- * @param name The name to search for.
- * @param type_rtrn Set to the index of the name if found.
- *
- * @return true if found, false otherwise.
- */
static bool
FindNamedType(struct xkb_keymap *keymap, xkb_atom_t name, unsigned *type_rtrn)
{
* symbol per level.
*/
static bool
-FindAutomaticType(struct xkb_keymap *keymap, xkb_level_index_t width,
+FindAutomaticType(struct xkb_context *ctx, xkb_level_index_t width,
const xkb_keysym_t *syms, xkb_atom_t *typeNameRtrn,
bool *autoType)
{
*autoType = false;
if ((width == 1) || (width == 0)) {
- *typeNameRtrn = xkb_atom_intern(keymap->ctx, "ONE_LEVEL");
+ *typeNameRtrn = xkb_atom_intern(ctx, "ONE_LEVEL");
*autoType = true;
}
else if (width == 2) {
if (syms && xkb_keysym_is_lower(syms[0]) &&
xkb_keysym_is_upper(syms[1])) {
- *typeNameRtrn = xkb_atom_intern(keymap->ctx, "ALPHABETIC");
+ *typeNameRtrn = xkb_atom_intern(ctx, "ALPHABETIC");
}
else if (syms && (xkb_keysym_is_keypad(syms[0]) ||
xkb_keysym_is_keypad(syms[1]))) {
- *typeNameRtrn = xkb_atom_intern(keymap->ctx, "KEYPAD");
+ *typeNameRtrn = xkb_atom_intern(ctx, "KEYPAD");
*autoType = true;
}
else {
- *typeNameRtrn = xkb_atom_intern(keymap->ctx, "TWO_LEVEL");
+ *typeNameRtrn = xkb_atom_intern(ctx, "TWO_LEVEL");
*autoType = true;
}
}
xkb_keysym_is_upper(syms[1]))
if (xkb_keysym_is_lower(syms[2]) && xkb_keysym_is_upper(syms[3]))
*typeNameRtrn =
- xkb_atom_intern(keymap->ctx, "FOUR_LEVEL_ALPHABETIC");
+ xkb_atom_intern(ctx, "FOUR_LEVEL_ALPHABETIC");
else
- *typeNameRtrn = xkb_atom_intern(keymap->ctx,
+ *typeNameRtrn = xkb_atom_intern(ctx,
"FOUR_LEVEL_SEMIALPHABETIC");
else if (syms && (xkb_keysym_is_keypad(syms[0]) ||
xkb_keysym_is_keypad(syms[1])))
- *typeNameRtrn = xkb_atom_intern(keymap->ctx, "FOUR_LEVEL_KEYPAD");
+ *typeNameRtrn = xkb_atom_intern(ctx, "FOUR_LEVEL_KEYPAD");
else
- *typeNameRtrn = xkb_atom_intern(keymap->ctx, "FOUR_LEVEL");
+ *typeNameRtrn = xkb_atom_intern(ctx, "FOUR_LEVEL");
/* XXX: why not set autoType here? */
}
return width <= 4;
}
-/**
- * Ensure the given KeyInfo is in a coherent state, i.e. no gaps between the
- * groups, and reduce to one group if all groups are identical anyway.
- */
-static void
-PrepareKeyDef(KeyInfo *keyi)
+static bool
+CopySymbolsDef(SymbolsInfo *info, KeyInfo *keyi)
{
- xkb_group_index_t i, lastGroup;
+ struct xkb_keymap *keymap = info->keymap;
+ struct xkb_key *key;
+ GroupInfo *groupi;
const GroupInfo *group0;
- bool identical;
+ xkb_layout_index_t i;
+ bool haveActions;
+ unsigned int sizeSyms;
+ unsigned int symIndex;
- /* get highest group number */
- for (i = XKB_NUM_GROUPS - 1; i > 0; i--)
- if (keyi->groups[i].defined)
- break;
- lastGroup = i;
+ /*
+ * The name is guaranteed to be real and not an alias (see
+ * AddKeySymbols), so 'false' is safe here.
+ */
+ key = FindNamedKey(keymap, keyi->name, false);
+ if (!key) {
+ log_vrb(info->keymap->ctx, 5,
+ "Key %s not found in keycodes; Symbols ignored\n",
+ LongKeyNameText(keyi->name));
+ return false;
+ }
- if (lastGroup == 0)
- return;
+ /* Find the range of groups we need. */
+ key->num_groups = 0;
+ darray_enumerate(i, groupi, keyi->groups)
+ if (groupi->defined)
+ key->num_groups = i + 1;
- group0 = &keyi->groups[0];
+ if (key->num_groups <= 0)
+ return false; /* WSGO */
- /* If there are empty groups between non-empty ones fill them with data */
- /* from the first group. */
- /* We can make a wrong assumption here. But leaving gaps is worse. */
- for (i = lastGroup; i > 0; i--) {
- GroupInfo *groupi = &keyi->groups[i];
+ darray_resize(keyi->groups, key->num_groups);
+ /*
+ * If there are empty groups between non-empty ones, fill them with data
+ * from the first group.
+ * We can make a wrong assumption here. But leaving gaps is worse.
+ */
+ group0 = &darray_item(keyi->groups, 0);
+ darray_foreach_from(groupi, keyi->groups, 1) {
if (groupi->defined)
continue;
- if (group0->defined & GROUP_FIELD_TYPE) {
- groupi->type = group0->type;
- groupi->defined |= GROUP_FIELD_TYPE;
- }
- if ((group0->defined & GROUP_FIELD_ACTS) &&
- !darray_empty(group0->acts)) {
- darray_copy(groupi->acts, group0->acts);
- groupi->defined |= GROUP_FIELD_ACTS;
- }
- if ((group0->defined & GROUP_FIELD_SYMS) &&
- !darray_empty(group0->syms)) {
- darray_copy(groupi->syms, group0->syms);
- darray_copy(groupi->symsMapIndex, group0->symsMapIndex);
- darray_copy(groupi->symsMapNumEntries, group0->symsMapNumEntries);
- groupi->defined |= GROUP_FIELD_SYMS;
- }
- if (group0->defined)
- groupi->numLevels = group0->numLevels;
+ groupi->type = group0->type;
+ darray_copy(groupi->syms, group0->syms);
+ darray_copy(groupi->levels, group0->levels);
+ groupi->defined = group0->defined;
}
- /* If all groups are completely identical remove them all */
- /* exept the first one. */
- identical = true;
- for (i = lastGroup; i > 0; i--) {
- GroupInfo *groupi = &keyi->groups[i];
-
- if (groupi->numLevels != group0->numLevels ||
- groupi->type != group0->type) {
- identical = false;
- break;
- }
- if (!darray_same(groupi->syms, group0->syms) &&
- (darray_empty(groupi->syms) || darray_empty(group0->syms) ||
- darray_size(groupi->syms) != darray_size(group0->syms) ||
- memcmp(darray_mem(groupi->syms, 0),
- darray_mem(group0->syms, 0),
- sizeof(xkb_keysym_t) * darray_size(group0->syms)))) {
- identical = false;
- break;
- }
- if (!darray_same(groupi->symsMapIndex, group0->symsMapIndex) &&
- (darray_empty(groupi->symsMapIndex) ||
- darray_empty(group0->symsMapIndex) ||
- memcmp(darray_mem(groupi->symsMapIndex, 0),
- darray_mem(group0->symsMapIndex, 0),
- group0->numLevels * sizeof(int)))) {
- identical = false;
- continue;
- }
- if (!darray_same(groupi->symsMapNumEntries,
- group0->symsMapNumEntries) &&
- (darray_empty(groupi->symsMapNumEntries) ||
- darray_empty(group0->symsMapNumEntries) ||
- memcmp(darray_mem(groupi->symsMapNumEntries, 0),
- darray_mem(group0->symsMapNumEntries, 0),
- group0->numLevels * sizeof(unsigned int)))) {
- identical = false;
- continue;
- }
- if (!darray_same(groupi->acts, group0->acts) &&
- (darray_empty(groupi->acts) || darray_empty(group0->acts) ||
- memcmp(darray_mem(groupi->acts, 0),
- darray_mem(group0->acts, 0),
- group0->numLevels * sizeof(union xkb_action)))) {
- identical = false;
- break;
+ /* See if we need to allocate an actions array. */
+ haveActions = false;
+ darray_foreach(groupi, keyi->groups) {
+ LevelInfo *leveli;
+ darray_foreach(leveli, groupi->levels) {
+ if (leveli->act.type != ACTION_TYPE_NONE) {
+ haveActions = true;
+ goto out_of_loops;
+ }
}
}
+out_of_loops:
- if (identical)
- for (i = lastGroup; i > 0; i--)
- ClearGroupInfo(&keyi->groups[i]);
-}
-
-/**
- * Copy the KeyInfo into the keyboard description.
- *
- * This function recurses.
- */
-static bool
-CopySymbolsDef(SymbolsInfo *info, KeyInfo *keyi,
- xkb_keycode_t start_from)
-{
- struct xkb_keymap *keymap = info->keymap;
- xkb_keycode_t kc;
- struct xkb_key *key;
- unsigned int sizeSyms = 0;
- xkb_group_index_t i, nGroups;
- xkb_level_index_t width, tmp;
- struct xkb_key_type * type;
- bool haveActions, autoType, useAlias;
- unsigned types[XKB_NUM_GROUPS];
- unsigned int symIndex = 0;
-
- useAlias = (start_from == 0);
-
- key = FindNamedKey(keymap, keyi->name, useAlias, start_from);
- if (!key) {
- if (start_from == 0)
- log_vrb(info->keymap->ctx, 5,
- "Key %s not found in keycodes; Symbols ignored\n",
- LongKeyNameText(keyi->name));
- return false;
- }
- kc = XkbKeyGetKeycode(keymap, key);
-
- haveActions = false;
- width = 0;
- for (i = nGroups = 0; i < XKB_NUM_GROUPS; i++) {
- GroupInfo *groupi = &keyi->groups[i];
-
- if (i + 1 > nGroups && groupi->defined)
- nGroups = i + 1;
-
- if (!darray_empty(groupi->acts))
- haveActions = true;
-
- autoType = false;
+ /*
+ * Find and assign the groups' types in the keymap. Also find the
+ * key width according to the largest type.
+ */
+ key->kt_index = calloc(key->num_groups, sizeof(*key->kt_index));
+ key->width = 0;
+ darray_enumerate(i, groupi, keyi->groups) {
+ struct xkb_key_type *type;
+ bool autoType = false;
- /* Assign the type to the key, if it is missing. */
+ /* Find the type of the group, if it is missing. */
if (groupi->type == XKB_ATOM_NONE) {
if (keyi->dfltType != XKB_ATOM_NONE)
groupi->type = keyi->dfltType;
- else if (FindAutomaticType(keymap, groupi->numLevels,
+ else if (FindAutomaticType(keymap->ctx,
+ darray_size(groupi->levels),
darray_mem(groupi->syms, 0),
&groupi->type, &autoType)) { }
else
log_vrb(info->keymap->ctx, 5,
- "No automatic type for %d symbols; "
- "Using %s for the %s key (keycode %d)\n",
- groupi->numLevels,
+ "No automatic type for %d levels; "
+ "Using %s for the %s key\n",
+ (int) darray_size(groupi->levels),
xkb_atom_text(keymap->ctx, groupi->type),
- LongKeyNameText(keyi->name), kc);
+ LongKeyNameText(keyi->name));
}
- if (FindNamedType(keymap, groupi->type, &types[i])) {
- if (!autoType || groupi->numLevels > 2)
+ /* Find the type in the keymap, if it was defined in xkb_types. */
+ if (FindNamedType(keymap, groupi->type, &key->kt_index[i])) {
+ if (!autoType || darray_size(groupi->levels) > 2)
key->explicit_groups |= (1 << i);
}
else {
log_vrb(info->keymap->ctx, 3,
"Type \"%s\" is not defined; "
- "Using default type for the %s key (keycode %d)\n",
+ "Using default type for the %s key\n",
xkb_atom_text(keymap->ctx, groupi->type),
- LongKeyNameText(keyi->name), kc);
+ LongKeyNameText(keyi->name));
/*
* Index 0 is guaranteed to contain something, usually
* ONE_LEVEL or at least some default one-level type.
*/
- types[i] = 0;
+ key->kt_index[i] = 0;
}
- /* if the type specifies fewer levels than the key has, shrink the key */
- type = &keymap->types[types[i]];
- if (type->num_levels < groupi->numLevels) {
+ /* If the type specifies fewer levels than the key has, shrink the key. */
+ type = &keymap->types[key->kt_index[i]];
+ if (type->num_levels < darray_size(groupi->levels)) {
log_vrb(info->keymap->ctx, 1,
- "Type \"%s\" has %d levels, but %s has %d symbols; "
+ "Type \"%s\" has %d levels, but %s has %d levels; "
"Ignoring extra symbols\n",
xkb_atom_text(keymap->ctx, type->name),
type->num_levels,
LongKeyNameText(keyi->name),
- groupi->numLevels);
- groupi->numLevels = type->num_levels;
+ (int) darray_size(groupi->levels));
+ darray_resize(groupi->levels, type->num_levels);
}
- width = MAX3(width, groupi->numLevels, type->num_levels);
- sizeSyms += darray_size(groupi->syms);
+ /*
+ * Why type->num_levels and not darray_size(groupi->levels)?
+ * Because the type may have more levels, and each group must
+ * have at least as many levels as its type. Because the
+ * key->syms array is indexed by (group * width + level), we
+ * must take the largest one.
+ * Maybe we can change it to save some space.
+ */
+ key->width = MAX(key->width, type->num_levels);
}
- key->syms = calloc(sizeSyms, sizeof(*key->syms));
- key->num_groups = nGroups;
- key->width = width;
- key->sym_index = calloc(nGroups * width, sizeof(*key->sym_index));
- key->num_syms = calloc(nGroups * width, sizeof(*key->num_syms));
-
- if (haveActions) {
- key->actions = calloc(nGroups * width, sizeof(*key->actions));
- key->explicit |= EXPLICIT_INTERP;
- }
+ /* Find the size of the syms array. */
+ sizeSyms = 0;
+ darray_foreach(groupi, keyi->groups)
+ sizeSyms += darray_size(groupi->syms);
+ /* Initialize the xkb_key, now that we know the sizes. */
+ key->syms = calloc(sizeSyms, sizeof(*key->syms));
+ key->sym_index = calloc(key->num_groups * key->width,
+ sizeof(*key->sym_index));
+ key->num_syms = calloc(key->num_groups * key->width,
+ sizeof(*key->num_syms));
key->out_of_range_group_number = keyi->out_of_range_group_number;
key->out_of_range_group_action = keyi->out_of_range_group_action;
-
- for (i = 0; i < nGroups; i++) {
- GroupInfo *groupi = &keyi->groups[i];
-
- /* assign kt_index[i] to the index of the type in map->types.
- * kt_index[i] may have been set by a previous run (if we have two
- * layouts specified). Let's not overwrite it with the ONE_LEVEL
- * default group if we dont even have keys for this group anyway.
- *
- * FIXME: There should be a better fix for this.
- */
- if (groupi->numLevels)
- key->kt_index[i] = types[i];
-
- if (!darray_empty(groupi->syms)) {
- /* fill key to "width" symbols*/
- for (tmp = 0; tmp < width; tmp++) {
- if (tmp < groupi->numLevels &&
- darray_item(groupi->symsMapNumEntries, tmp) != 0) {
- memcpy(&key->syms[symIndex],
- darray_mem(groupi->syms,
- darray_item(groupi->symsMapIndex, tmp)),
- darray_item(groupi->symsMapNumEntries, tmp) * sizeof(xkb_keysym_t));
- key->sym_index[(i * width) + tmp] = symIndex;
- key->num_syms[(i * width) + tmp] =
- darray_item(groupi->symsMapNumEntries, tmp);
- symIndex += key->num_syms[(i * width) + tmp];
- }
- else {
- key->sym_index[(i * width) + tmp] = -1;
- key->num_syms[(i * width) + tmp] = 0;
- }
-
- if (key->actions && !darray_empty(groupi->acts)) {
- if (tmp < groupi->numLevels)
- key->actions[tmp] = darray_item(groupi->acts, tmp);
- else
- key->actions[tmp].type = ACTION_TYPE_NONE;
- }
- }
- }
+ if (haveActions) {
+ key->actions = calloc(key->num_groups * key->width,
+ sizeof(*key->actions));
+ key->explicit |= EXPLICIT_INTERP;
}
-
if (keyi->defined & KEY_FIELD_VMODMAP) {
key->vmodmap = keyi->vmodmap;
key->explicit |= EXPLICIT_VMODMAP;
key->explicit |= EXPLICIT_REPEAT;
}
- /* do the same thing for the next key */
- CopySymbolsDef(info, keyi, kc + 1);
+ /* Copy keysyms and actions. */
+ symIndex = 0;
+ darray_enumerate(i, groupi, keyi->groups) {
+ xkb_level_index_t j;
+ LevelInfo *leveli;
+
+ /* We rely on calloc having zeroized the arrays up to key->width. */
+ darray_enumerate(j, leveli, groupi->levels) {
+ if (leveli->act.type != ACTION_TYPE_NONE)
+ key->actions[i * key->width + j] = leveli->act;
+
+ if (leveli->num_syms <= 0)
+ continue;
+
+ memcpy(&key->syms[symIndex],
+ &darray_item(groupi->syms, leveli->sym_index),
+ leveli->num_syms * sizeof(*key->syms));
+ key->sym_index[i * key->width + j] = symIndex;
+ key->num_syms[i * key->width + j] = leveli->num_syms;
+ symIndex += key->num_syms[i * key->width + j];
+ }
+ }
+
return true;
}
struct xkb_keymap *keymap = info->keymap;
if (!entry->haveSymbol) {
- key = FindNamedKey(keymap, entry->u.keyName, true, 0);
+ key = FindNamedKey(keymap, entry->u.keyName, true);
if (!key) {
log_vrb(info->keymap->ctx, 5,
"Key %s not found in keycodes; "
return true;
}
-/**
- * Handle the xkb_symbols section of an xkb file.
- *
- * @param file The parsed xkb_symbols section of the xkb file.
- * @param keymap Handle to the keyboard description to store the symbols in.
- * @param merge Merge strategy (e.g. MERGE_OVERRIDE).
- */
+static bool
+CopySymbolsToKeymap(struct xkb_keymap *keymap, SymbolsInfo *info)
+{
+ KeyInfo *keyi;
+ ModMapEntry *mm;
+ xkb_layout_index_t i;
+ struct xkb_key *key;
+
+ keymap->symbols_section_name = strdup_safe(info->name);
+
+ for (i = 0; i < XKB_NUM_GROUPS; i++)
+ if (info->group_names[i] != XKB_ATOM_NONE)
+ keymap->group_names[i] = info->group_names[i];
+
+ darray_foreach(keyi, info->keys)
+ if (!CopySymbolsDef(info, keyi))
+ info->errorCount++;
+
+ if (xkb_context_get_log_verbosity(keymap->ctx) > 3) {
+ xkb_foreach_key(key, keymap) {
+ if (key->name[0] == '\0')
+ continue;
+
+ if (key->num_groups < 1)
+ log_info(keymap->ctx,
+ "No symbols defined for %s\n",
+ KeyNameText(key->name));
+ }
+ }
+
+ darray_foreach(mm, info->modMaps)
+ if (!CopyModMapDef(info, mm))
+ info->errorCount++;
+
+ /* XXX: If we don't ignore errorCount, things break. */
+ return true;
+}
+
bool
CompileSymbols(XkbFile *file, struct xkb_keymap *keymap,
enum merge_mode merge)
{
- xkb_group_index_t i;
- struct xkb_key *key;
SymbolsInfo info;
ActionsInfo *actions;
- KeyInfo *keyi;
- ModMapEntry *mm;
actions = NewActionsInfo();
if (!actions)
if (info.errorCount != 0)
goto err_info;
- if (info.name)
- keymap->symbols_section_name = strdup(info.name);
-
- for (i = 0; i < XKB_NUM_GROUPS; i++)
- if (info.groupNames[i] != XKB_ATOM_NONE)
- keymap->group_names[i] = info.groupNames[i];
-
- /* sanitize keys */
- darray_foreach(keyi, info.keys)
- PrepareKeyDef(keyi);
-
- /* copy! */
- darray_foreach(keyi, info.keys)
- if (!CopySymbolsDef(&info, keyi, 0))
- info.errorCount++;
-
- if (xkb_get_log_verbosity(keymap->ctx) > 3) {
- xkb_foreach_key(key, keymap) {
- if (key->name[0] == '\0')
- continue;
-
- if (key->num_groups < 1)
- log_info(info.keymap->ctx,
- "No symbols defined for %s (keycode %d)\n",
- KeyNameText(key->name),
- XkbKeyGetKeycode(keymap, key));
- }
- }
-
- darray_foreach(mm, info.modMaps)
- if (!CopyModMapDef(&info, mm))
- info.errorCount++;
+ if (!CopySymbolsToKeymap(keymap, &info))
+ goto err_info;
ClearSymbolsInfo(&info);
FreeActionsInfo(actions);