Pass around xkb_key's instead of keycodes
[platform/upstream/libxkbcommon.git] / src / xkbcomp / symbols.c
index 7f8b9d1..d766cd0 100644 (file)
@@ -55,7 +55,6 @@ typedef darray (union xkb_action) darray_xkb_action;
 typedef struct _KeyInfo {
     CommonInfo defs;
     unsigned long name; /* the 4 chars of the key name, as long */
-    unsigned char groupInfo;
     unsigned char typesDefined;
     unsigned char symsDefined;
     unsigned char actsDefined;
@@ -83,66 +82,56 @@ typedef struct _KeyInfo {
     struct xkb_behavior behavior;
     unsigned short vmodmap;
     xkb_atom_t dfltType;
+
+    uint8_t out_of_range_group_action;
+    uint8_t out_of_range_group_number;
 } KeyInfo;
 
 /**
  * Init the given key info to sane values.
  */
 static void
-InitKeyInfo(KeyInfo * info, unsigned file_id)
+InitKeyInfo(KeyInfo *keyi, unsigned file_id)
 {
     int i;
     static const char dflt[4] = "*";
 
-    info->defs.defined = 0;
-    info->defs.file_id = file_id;
-    info->defs.merge = MERGE_OVERRIDE;
-    info->defs.next = NULL;
-    info->name = KeyNameToLong(dflt);
-    info->groupInfo = 0;
-    info->typesDefined = info->symsDefined = info->actsDefined = 0;
+    keyi->defs.defined = 0;
+    keyi->defs.file_id = file_id;
+    keyi->defs.merge = MERGE_OVERRIDE;
+    keyi->defs.next = NULL;
+    keyi->name = KeyNameToLong(dflt);
+    keyi->typesDefined = keyi->symsDefined = keyi->actsDefined = 0;
+
     for (i = 0; i < XkbNumKbdGroups; i++) {
-        info->numLevels[i] = 0;
-        info->types[i] = XKB_ATOM_NONE;
-        darray_init(info->syms[i]);
-        darray_init(info->symsMapIndex[i]);
-        darray_init(info->symsMapNumEntries[i]);
-        darray_init(info->acts[i]);
-    }
-    info->dfltType = XKB_ATOM_NONE;
-    info->behavior.type = XkbKB_Default;
-    info->behavior.data = 0;
-    info->vmodmap = 0;
-    info->repeat = RepeatUndefined;
+        keyi->numLevels[i] = 0;
+        keyi->types[i] = XKB_ATOM_NONE;
+        darray_init(keyi->syms[i]);
+        darray_init(keyi->symsMapIndex[i]);
+        darray_init(keyi->symsMapNumEntries[i]);
+        darray_init(keyi->acts[i]);
+    }
+
+    keyi->dfltType = XKB_ATOM_NONE;
+    keyi->behavior.type = XkbKB_Default;
+    keyi->behavior.data = 0;
+    keyi->vmodmap = 0;
+    keyi->repeat = RepeatUndefined;
+    keyi->out_of_range_group_action = 0;
+    keyi->out_of_range_group_number = 0;
 }
 
-/**
- * Free memory associated with this key info and reset to sane values.
- */
 static void
-FreeKeyInfo(KeyInfo * info)
+FreeKeyInfo(KeyInfo *keyi)
 {
     int i;
 
-    info->defs.defined = 0;
-    info->defs.file_id = 0;
-    info->defs.merge = MERGE_OVERRIDE;
-    info->defs.next = NULL;
-    info->groupInfo = 0;
-    info->typesDefined = info->symsDefined = info->actsDefined = 0;
     for (i = 0; i < XkbNumKbdGroups; i++) {
-        info->numLevels[i] = 0;
-        info->types[i] = XKB_ATOM_NONE;
-        darray_free(info->syms[i]);
-        darray_free(info->symsMapIndex[i]);
-        darray_free(info->symsMapNumEntries[i]);
-        darray_free(info->acts[i]);
-    }
-    info->dfltType = XKB_ATOM_NONE;
-    info->behavior.type = XkbKB_Default;
-    info->behavior.data = 0;
-    info->vmodmap = 0;
-    info->repeat = RepeatUndefined;
+        darray_free(keyi->syms[i]);
+        darray_free(keyi->symsMapIndex[i]);
+        darray_free(keyi->symsMapNumEntries[i]);
+        darray_free(keyi->acts[i]);
+    }
 }
 
 /**
@@ -232,11 +221,12 @@ InitSymbolsInfo(SymbolsInfo * info, struct xkb_keymap *keymap,
 static void
 FreeSymbolsInfo(SymbolsInfo * info)
 {
-    KeyInfo *key;
+    KeyInfo *keyi;
 
     free(info->name);
-    darray_foreach(key, info->keys)
-    FreeKeyInfo(key);
+    darray_foreach(keyi, info->keys) {
+        FreeKeyInfo(keyi);
+    }
     darray_free(info->keys);
     if (info->modMap)
         ClearCommonInfo(&info->modMap->defs);
@@ -246,32 +236,32 @@ FreeSymbolsInfo(SymbolsInfo * info)
 }
 
 static bool
-ResizeKeyGroup(KeyInfo * key, unsigned int group, unsigned int numLevels,
+ResizeKeyGroup(KeyInfo *keyi, unsigned int group, unsigned int numLevels,
                unsigned sizeSyms, bool forceActions)
 {
     int i;
 
-    if (darray_size(key->syms[group]) < sizeSyms)
-        darray_resize0(key->syms[group], sizeSyms);
+    if (darray_size(keyi->syms[group]) < sizeSyms)
+        darray_resize0(keyi->syms[group], sizeSyms);
 
-    if (darray_empty(key->symsMapIndex[group]) ||
-        key->numLevels[group] < numLevels) {
-        darray_resize(key->symsMapIndex[group], numLevels);
-        for (i = key->numLevels[group]; i < numLevels; i++)
-            darray_item(key->symsMapIndex[group], i) = -1;
+    if (darray_empty(keyi->symsMapIndex[group]) ||
+        keyi->numLevels[group] < numLevels) {
+        darray_resize(keyi->symsMapIndex[group], numLevels);
+        for (i = keyi->numLevels[group]; i < numLevels; i++)
+            darray_item(keyi->symsMapIndex[group], i) = -1;
     }
 
-    if (darray_empty(key->symsMapNumEntries[group]) ||
-        key->numLevels[group] < numLevels)
-        darray_resize0(key->symsMapNumEntries[group], numLevels);
+    if (darray_empty(keyi->symsMapNumEntries[group]) ||
+        keyi->numLevels[group] < numLevels)
+        darray_resize0(keyi->symsMapNumEntries[group], numLevels);
 
-    if ((forceActions && (key->numLevels[group] < numLevels ||
-                          darray_empty(key->acts[group]))) ||
-        (key->numLevels[group] < numLevels && !darray_empty(key->acts[group])))
-        darray_resize0(key->acts[group], numLevels);
+    if ((forceActions && (keyi->numLevels[group] < numLevels ||
+                          darray_empty(keyi->acts[group]))) ||
+        (keyi->numLevels[group] < numLevels && !darray_empty(keyi->acts[group])))
+        darray_resize0(keyi->acts[group], numLevels);
 
-    if (key->numLevels[group] < numLevels)
-        key->numLevels[group] = numLevels;
+    if (keyi->numLevels[group] < numLevels)
+        keyi->numLevels[group] = numLevels;
 
     return true;
 }
@@ -581,7 +571,8 @@ MergeKeys(SymbolsInfo *info, struct xkb_keymap *keymap,
         into->defs.defined |= _Key_Type_Dflt;
     }
     if (UseNewField(_Key_GroupInfo, &into->defs, &from->defs, &collide)) {
-        into->groupInfo = from->groupInfo;
+        into->out_of_range_group_action = from->out_of_range_group_action;
+        into->out_of_range_group_number = from->out_of_range_group_number;
         into->defs.defined |= _Key_GroupInfo;
     }
     if (collide) {
@@ -594,23 +585,23 @@ MergeKeys(SymbolsInfo *info, struct xkb_keymap *keymap,
 }
 
 static bool
-AddKeySymbols(SymbolsInfo *info, KeyInfo *key, struct xkb_keymap *keymap)
+AddKeySymbols(SymbolsInfo *info, KeyInfo *keyi, struct xkb_keymap *keymap)
 {
     unsigned long real_name;
     KeyInfo *iter, *new;
 
     darray_foreach(iter, info->keys)
-    if (iter->name == key->name)
-        return MergeKeys(info, keymap, iter, key);
+        if (iter->name == keyi->name)
+            return MergeKeys(info, keymap, iter, keyi);
 
-    if (FindKeyNameForAlias(keymap, key->name, &real_name))
+    if (FindKeyNameForAlias(keymap, keyi->name, &real_name))
         darray_foreach(iter, info->keys)
-        if (iter->name == real_name)
-            return MergeKeys(info, keymap, iter, key);
+            if (iter->name == real_name)
+                return MergeKeys(info, keymap, iter, keyi);
 
     darray_resize0(info->keys, darray_size(info->keys) + 1);
     new = &darray_item(info->keys, darray_size(info->keys) - 1);
-    return CopyKeyInfo(key, new, true);
+    return CopyKeyInfo(keyi, new, true);
 }
 
 static bool
@@ -685,7 +676,7 @@ MergeIncludedSymbols(SymbolsInfo *into, SymbolsInfo *from,
                      enum merge_mode merge, struct xkb_keymap *keymap)
 {
     unsigned int i;
-    KeyInfo *key;
+    KeyInfo *keyi;
 
     if (from->errorCount > 0) {
         into->errorCount += from->errorCount;
@@ -703,11 +694,11 @@ MergeIncludedSymbols(SymbolsInfo *into, SymbolsInfo *from,
         }
     }
 
-    darray_foreach(key, from->keys) {
+    darray_foreach(keyi, from->keys) {
         if (merge != MERGE_DEFAULT)
-            key->defs.merge = merge;
+            keyi->defs.merge = merge;
 
-        if (!AddKeySymbols(into, key, keymap))
+        if (!AddKeySymbols(into, keyi, keymap))
             into->errorCount++;
     }
 
@@ -818,7 +809,7 @@ HandleIncludeSymbols(IncludeStmt *stmt, struct xkb_keymap *keymap,
 #define ACTIONS 2
 
 static bool
-GetGroupIndex(KeyInfo *key, struct xkb_keymap *keymap,
+GetGroupIndex(KeyInfo *keyi, struct xkb_keymap *keymap,
               ExprDef * arrayNdx, unsigned what, unsigned *ndx_rtrn)
 {
     const char *name;
@@ -833,9 +824,9 @@ GetGroupIndex(KeyInfo *key, struct xkb_keymap *keymap,
         int i;
         unsigned defined;
         if (what == SYMBOLS)
-            defined = key->symsDefined;
+            defined = keyi->symsDefined;
         else
-            defined = key->actsDefined;
+            defined = keyi->actsDefined;
 
         for (i = 0; i < XkbNumKbdGroups; i++) {
             if ((defined & (1 << i)) == 0) {
@@ -844,13 +835,13 @@ GetGroupIndex(KeyInfo *key, struct xkb_keymap *keymap,
             }
         }
         ERROR("Too many groups of %s for key %s (max %d)\n", name,
-              longText(key->name), XkbNumKbdGroups + 1);
+              longText(keyi->name), XkbNumKbdGroups + 1);
         ACTION("Ignoring %s defined for extra groups\n", name);
         return false;
     }
     if (!ExprResolveGroup(keymap->ctx, arrayNdx, &tmp)) {
         ERROR("Illegal group index for %s of key %s\n", name,
-              longText(key->name));
+              longText(keyi->name));
         ACTION("Definition with non-integer array index ignored\n");
         return false;
     }
@@ -859,88 +850,88 @@ GetGroupIndex(KeyInfo *key, struct xkb_keymap *keymap,
 }
 
 static bool
-AddSymbolsToKey(KeyInfo *key, struct xkb_keymap *keymap,
+AddSymbolsToKey(KeyInfo *keyi, struct xkb_keymap *keymap,
                 ExprDef *arrayNdx, ExprDef *value, SymbolsInfo *info)
 {
     unsigned ndx, nSyms, nLevels;
     unsigned int i;
     long j;
 
-    if (!GetGroupIndex(key, keymap, arrayNdx, SYMBOLS, &ndx))
+    if (!GetGroupIndex(keyi, keymap, arrayNdx, SYMBOLS, &ndx))
         return false;
     if (value == NULL) {
-        key->symsDefined |= (1 << ndx);
+        keyi->symsDefined |= (1 << ndx);
         return true;
     }
     if (value->op != ExprKeysymList) {
         ERROR("Expected a list of symbols, found %s\n", exprOpText(value->op));
         ACTION("Ignoring symbols for group %d of %s\n", ndx + 1,
-               longText(key->name));
+               longText(keyi->name));
         return false;
     }
-    if (!darray_empty(key->syms[ndx])) {
+    if (!darray_empty(keyi->syms[ndx])) {
         ERROR("Symbols for key %s, group %d already defined\n",
-              longText(key->name), ndx + 1);
+               longText(keyi->name), ndx + 1);
         ACTION("Ignoring duplicate definition\n");
         return false;
     }
     nSyms = darray_size(value->value.list.syms);
     nLevels = darray_size(value->value.list.symsMapIndex);
-    if ((key->numLevels[ndx] < nSyms || darray_empty(key->syms[ndx])) &&
-        (!ResizeKeyGroup(key, ndx, nLevels, nSyms, false))) {
+    if ((keyi->numLevels[ndx] < nSyms || darray_empty(keyi->syms[ndx])) &&
+        (!ResizeKeyGroup(keyi, ndx, nLevels, nSyms, false))) {
         WSGO("Could not resize group %d of key %s to contain %d levels\n",
-             ndx + 1, longText(key->name), nSyms);
+             ndx + 1, longText(keyi->name), nSyms);
         ACTION("Symbols lost\n");
         return false;
     }
-    key->symsDefined |= (1 << ndx);
+    keyi->symsDefined |= (1 << ndx);
     for (i = 0; i < nLevels; i++) {
-        darray_item(key->symsMapIndex[ndx], i) =
+        darray_item(keyi->symsMapIndex[ndx], i) =
             darray_item(value->value.list.symsMapIndex, i);
-        darray_item(key->symsMapNumEntries[ndx], i) =
+        darray_item(keyi->symsMapNumEntries[ndx], i) =
             darray_item(value->value.list.symsNumEntries, i);
 
-        for (j = 0; j < darray_item(key->symsMapNumEntries[ndx], i); j++) {
+        for (j = 0; j < darray_item(keyi->symsMapNumEntries[ndx], i); j++) {
             /* FIXME: What's abort() doing here? */
-            if (darray_item(key->symsMapIndex[ndx], i) + j >= nSyms)
+            if (darray_item(keyi->symsMapIndex[ndx], i) + j >= nSyms)
                 abort();
             if (!LookupKeysym(darray_item(value->value.list.syms,
-                                          darray_item(value->value.list.
-                                                      symsMapIndex, i) + j),
-                              &darray_item(key->syms[ndx],
-                                           darray_item(key->symsMapIndex[ndx],
+                                          darray_item(value->value.list.symsMapIndex,
+                                                      i) + j),
+                              &darray_item(keyi->syms[ndx],
+                                           darray_item(keyi->symsMapIndex[ndx],
                                                        i) + j))) {
                 WARN(
                     "Could not resolve keysym %s for key %s, group %d (%s), level %d\n",
                     darray_item(value->value.list.syms, i),
-                    longText(key->name),
+                    longText(keyi->name),
                     ndx + 1,
                     xkb_atom_text(keymap->ctx, info->groupNames[ndx]), nSyms);
                 while (--j >= 0)
-                    darray_item(key->syms[ndx],
-                                darray_item(key->symsMapIndex[ndx],
+                    darray_item(keyi->syms[ndx],
+                                darray_item(keyi->symsMapIndex[ndx],
                                             i) + j) = XKB_KEY_NoSymbol;
-                darray_item(key->symsMapIndex[ndx], i) = -1;
-                darray_item(key->symsMapNumEntries[ndx], i) = 0;
+                darray_item(keyi->symsMapIndex[ndx], i) = -1;
+                darray_item(keyi->symsMapNumEntries[ndx], i) = 0;
                 break;
             }
-            if (darray_item(key->symsMapNumEntries[ndx], i) == 1 &&
-                darray_item(key->syms[ndx],
-                            darray_item(key->symsMapIndex[ndx],
+            if (darray_item(keyi->symsMapNumEntries[ndx], i) == 1 &&
+                darray_item(keyi->syms[ndx],
+                            darray_item(keyi->symsMapIndex[ndx],
                                         i) + j) == XKB_KEY_NoSymbol) {
-                darray_item(key->symsMapIndex[ndx], i) = -1;
-                darray_item(key->symsMapNumEntries[ndx], i) = 0;
+                darray_item(keyi->symsMapIndex[ndx], i) = -1;
+                darray_item(keyi->symsMapNumEntries[ndx], i) = 0;
             }
         }
     }
-    for (j = key->numLevels[ndx] - 1;
-         j >= 0 && darray_item(key->symsMapNumEntries[ndx], j) == 0; j--)
-        key->numLevels[ndx]--;
+    for (j = keyi->numLevels[ndx] - 1;
+         j >= 0 && darray_item(keyi->symsMapNumEntries[ndx], j) == 0; j--)
+        keyi->numLevels[ndx]--;
     return true;
 }
 
 static bool
-AddActionsToKey(KeyInfo *key, struct xkb_keymap *keymap, ExprDef *arrayNdx,
+AddActionsToKey(KeyInfo *keyi, struct xkb_keymap *keymap, ExprDef *arrayNdx,
                 ExprDef *value, SymbolsInfo *info)
 {
     unsigned int i;
@@ -948,22 +939,22 @@ AddActionsToKey(KeyInfo *key, struct xkb_keymap *keymap, ExprDef *arrayNdx,
     ExprDef *act;
     struct xkb_any_action *toAct;
 
-    if (!GetGroupIndex(key, keymap, arrayNdx, ACTIONS, &ndx))
+    if (!GetGroupIndex(keyi, keymap, arrayNdx, ACTIONS, &ndx))
         return false;
 
     if (value == NULL) {
-        key->actsDefined |= (1 << ndx);
+        keyi->actsDefined |= (1 << ndx);
         return true;
     }
     if (value->op != ExprActionList) {
         WSGO("Bad expression type (%d) for action list value\n", value->op);
         ACTION("Ignoring actions for group %d of %s\n", ndx,
-               longText(key->name));
+               longText(keyi->name));
         return false;
     }
-    if (!darray_empty(key->acts[ndx])) {
+    if (!darray_empty(keyi->acts[ndx])) {
         WSGO("Actions for key %s, group %d already defined\n",
-             longText(key->name), ndx);
+             longText(keyi->name), ndx);
         return false;
     }
     for (nActs = 0, act = value->value.child; act != NULL; nActs++) {
@@ -973,21 +964,21 @@ AddActionsToKey(KeyInfo *key, struct xkb_keymap *keymap, ExprDef *arrayNdx,
         WSGO("Action list but not actions in AddActionsToKey\n");
         return false;
     }
-    if ((key->numLevels[ndx] < nActs || darray_empty(key->acts[ndx])) &&
-        !ResizeKeyGroup(key, ndx, nActs, nActs, true)) {
+    if ((keyi->numLevels[ndx] < nActs || darray_empty(keyi->acts[ndx])) &&
+        !ResizeKeyGroup(keyi, ndx, nActs, nActs, true)) {
         WSGO("Could not resize group %d of key %s\n", ndx,
-             longText(key->name));
+              longText(keyi->name));
         ACTION("Actions lost\n");
         return false;
     }
-    key->actsDefined |= (1 << ndx);
+    keyi->actsDefined |= (1 << ndx);
 
-    toAct = (struct xkb_any_action *) darray_mem(key->acts[ndx], 0);
+    toAct = (struct xkb_any_action *) darray_mem(keyi->acts[ndx], 0);
     act = value->value.child;
     for (i = 0; i < nActs; i++, toAct++) {
         if (!HandleActionDef(act, keymap, toAct, info->action)) {
             ERROR("Illegal action definition for %s\n",
-                  longText(key->name));
+                  longText(keyi->name));
             ACTION("Action for group %d/level %d ignored\n", ndx + 1, i + 1);
         }
         act = (ExprDef *) act->common.next;
@@ -1018,7 +1009,7 @@ static const LookupEntry repeatEntries[] = {
 };
 
 static bool
-SetSymbolsField(KeyInfo *key, struct xkb_keymap *keymap, char *field,
+SetSymbolsField(KeyInfo *keyi, struct xkb_keymap *keymap, char *field,
                 ExprDef *arrayNdx, ExprDef *value, SymbolsInfo *info)
 {
     bool ok = true;
@@ -1032,39 +1023,39 @@ SetSymbolsField(KeyInfo *key, struct xkb_keymap *keymap, char *field,
             ACTION("Ignoring illegal type definition\n");
         }
         if (arrayNdx == NULL) {
-            key->dfltType = xkb_atom_intern(keymap->ctx, tmp.str);
-            key->defs.defined |= _Key_Type_Dflt;
+            keyi->dfltType = xkb_atom_intern(keymap->ctx, tmp.str);
+            keyi->defs.defined |= _Key_Type_Dflt;
         }
         else if (!ExprResolveGroup(keymap->ctx, arrayNdx, &ndx)) {
             ERROR("Illegal group index for type of key %s\n",
-                  longText(key->name));
+                  longText(keyi->name));
             ACTION("Definition with non-integer array index ignored\n");
             free(tmp.str);
             return false;
         }
         else {
-            key->types[ndx.uval - 1] = xkb_atom_intern(keymap->ctx, tmp.str);
-            key->typesDefined |= (1 << (ndx.uval - 1));
+            keyi->types[ndx.uval - 1] = xkb_atom_intern(keymap->ctx, tmp.str);
+            keyi->typesDefined |= (1 << (ndx.uval - 1));
         }
         free(tmp.str);
     }
     else if (strcasecmp(field, "symbols") == 0)
-        return AddSymbolsToKey(key, keymap, arrayNdx, value, info);
+        return AddSymbolsToKey(keyi, keymap, arrayNdx, value, info);
     else if (strcasecmp(field, "actions") == 0)
-        return AddActionsToKey(key, keymap, arrayNdx, value, info);
+        return AddActionsToKey(keyi, keymap, arrayNdx, value, info);
     else if ((strcasecmp(field, "vmods") == 0) ||
              (strcasecmp(field, "virtualmods") == 0) ||
              (strcasecmp(field, "virtualmodifiers") == 0)) {
         ok = ExprResolveVModMask(value, &tmp, keymap);
         if (ok) {
-            key->vmodmap = (tmp.uval >> 8);
-            key->defs.defined |= _Key_VModMap;
+            keyi->vmodmap = (tmp.uval >> 8);
+            keyi->defs.defined |= _Key_VModMap;
         }
         else {
             ERROR("Expected a virtual modifier mask, found %s\n",
                   exprOpText(value->op));
             ACTION("Ignoring virtual modifiers definition for key %s\n",
-                   longText(key->name));
+                   longText(keyi->name));
         }
     }
     else if ((strcasecmp(field, "locking") == 0) ||
@@ -1072,22 +1063,22 @@ SetSymbolsField(KeyInfo *key, struct xkb_keymap *keymap, char *field,
              (strcasecmp(field, "locks") == 0)) {
         ok = ExprResolveEnum(keymap->ctx, value, &tmp, lockingEntries);
         if (ok)
-            key->behavior.type = tmp.uval;
-        key->defs.defined |= _Key_Behavior;
+            keyi->behavior.type = tmp.uval;
+        keyi->defs.defined |= _Key_Behavior;
     }
     else if ((strcasecmp(field, "radiogroup") == 0) ||
              (strcasecmp(field, "permanentradiogroup") == 0) ||
              (strcasecmp(field, "allownone") == 0)) {
         ERROR("Radio groups not supported\n");
         ACTION("Ignoring radio group specification for key %s\n",
-               longText(key->name));
+               longText(keyi->name));
         return false;
     }
     else if (uStrCasePrefix("overlay", field) ||
              uStrCasePrefix("permanentoverlay", field)) {
         ERROR("Overlays not supported\n");
         ACTION("Ignoring overlay specification for key %s\n",
-               longText(key->name));
+               longText(keyi->name));
     }
     else if ((strcasecmp(field, "repeating") == 0) ||
              (strcasecmp(field, "repeats") == 0) ||
@@ -1095,54 +1086,54 @@ SetSymbolsField(KeyInfo *key, struct xkb_keymap *keymap, char *field,
         ok = ExprResolveEnum(keymap->ctx, value, &tmp, repeatEntries);
         if (!ok) {
             ERROR("Illegal repeat setting for %s\n",
-                  longText(key->name));
+                  longText(keyi->name));
             ACTION("Non-boolean repeat setting ignored\n");
             return false;
         }
-        key->repeat = tmp.uval;
-        key->defs.defined |= _Key_Repeat;
+        keyi->repeat = tmp.uval;
+        keyi->defs.defined |= _Key_Repeat;
     }
     else if ((strcasecmp(field, "groupswrap") == 0) ||
              (strcasecmp(field, "wrapgroups") == 0)) {
         ok = ExprResolveBoolean(keymap->ctx, value, &tmp);
         if (!ok) {
             ERROR("Illegal groupsWrap setting for %s\n",
-                  longText(key->name));
+                  longText(keyi->name));
             ACTION("Non-boolean value ignored\n");
             return false;
         }
         if (tmp.uval)
-            key->groupInfo = XkbWrapIntoRange;
+            keyi->out_of_range_group_action = XkbWrapIntoRange;
         else
-            key->groupInfo = XkbClampIntoRange;
-        key->defs.defined |= _Key_GroupInfo;
+            keyi->out_of_range_group_action = XkbClampIntoRange;
+        keyi->defs.defined |= _Key_GroupInfo;
     }
     else if ((strcasecmp(field, "groupsclamp") == 0) ||
              (strcasecmp(field, "clampgroups") == 0)) {
         ok = ExprResolveBoolean(keymap->ctx, value, &tmp);
         if (!ok) {
             ERROR("Illegal groupsClamp setting for %s\n",
-                  longText(key->name));
+                  longText(keyi->name));
             ACTION("Non-boolean value ignored\n");
             return false;
         }
         if (tmp.uval)
-            key->groupInfo = XkbClampIntoRange;
+            keyi->out_of_range_group_action = XkbClampIntoRange;
         else
-            key->groupInfo = XkbWrapIntoRange;
-        key->defs.defined |= _Key_GroupInfo;
+            keyi->out_of_range_group_action = XkbWrapIntoRange;
+        keyi->defs.defined |= _Key_GroupInfo;
     }
     else if ((strcasecmp(field, "groupsredirect") == 0) ||
              (strcasecmp(field, "redirectgroups") == 0)) {
         if (!ExprResolveGroup(keymap->ctx, value, &tmp)) {
             ERROR("Illegal group index for redirect of key %s\n",
-                  longText(key->name));
+                  longText(keyi->name));
             ACTION("Definition with non-integer group ignored\n");
             return false;
         }
-        key->groupInfo =
-            XkbSetGroupInfo(0, XkbRedirectIntoRange, tmp.uval - 1);
-        key->defs.defined |= _Key_GroupInfo;
+        keyi->out_of_range_group_action = XkbRedirectIntoRange;
+        keyi->out_of_range_group_number = tmp.uval - 1;
+        keyi->defs.defined |= _Key_GroupInfo;
     }
     else {
         ERROR("Unknown field %s in a symbol interpretation\n", field);
@@ -1236,7 +1227,7 @@ HandleSymbolsVar(VarDef *stmt, struct xkb_keymap *keymap, SymbolsInfo *info)
 }
 
 static bool
-HandleSymbolsBody(VarDef *def, struct xkb_keymap *keymap, KeyInfo *key,
+HandleSymbolsBody(VarDef *def, struct xkb_keymap *keymap, KeyInfo *keyi,
                   SymbolsInfo *info)
 {
     bool ok = true;
@@ -1262,7 +1253,7 @@ HandleSymbolsBody(VarDef *def, struct xkb_keymap *keymap, KeyInfo *key,
                                     &arrayNdx);
             }
             if (ok)
-                ok = SetSymbolsField(key, keymap, field.str, arrayNdx,
+                ok = SetSymbolsField(keyi, keymap, field.str, arrayNdx,
                                      def->value, info);
             free(field.str);
         }
@@ -1271,40 +1262,40 @@ HandleSymbolsBody(VarDef *def, struct xkb_keymap *keymap, KeyInfo *key,
 }
 
 static bool
-SetExplicitGroup(SymbolsInfo *info, KeyInfo *key)
+SetExplicitGroup(SymbolsInfo *info, KeyInfo *keyi)
 {
     unsigned group = info->explicit_group;
 
     if (group == 0)
         return true;
 
-    if ((key->typesDefined | key->symsDefined | key->actsDefined) & ~1) {
+    if ((keyi->typesDefined | keyi->symsDefined | keyi->actsDefined) & ~1) {
         int i;
         WARN("For the map %s an explicit group specified\n", info->name);
         WARN("but key %s has more than one group defined\n",
-             longText(key->name));
+             longText(keyi->name));
         ACTION("All groups except first one will be ignored\n");
         for (i = 1; i < XkbNumKbdGroups; i++) {
-            key->numLevels[i] = 0;
-            darray_free(key->syms[i]);
-            darray_free(key->acts[i]);
-            key->types[i] = 0;
-        }
-    }
-    key->typesDefined = key->symsDefined = key->actsDefined = 1 << group;
-
-    key->numLevels[group] = key->numLevels[0];
-    key->numLevels[0] = 0;
-    key->syms[group] = key->syms[0];
-    darray_init(key->syms[0]);
-    key->symsMapIndex[group] = key->symsMapIndex[0];
-    darray_init(key->symsMapIndex[0]);
-    key->symsMapNumEntries[group] = key->symsMapNumEntries[0];
-    darray_init(key->symsMapNumEntries[0]);
-    key->acts[group] = key->acts[0];
-    darray_init(key->acts[0]);
-    key->types[group] = key->types[0];
-    key->types[0] = 0;
+            keyi->numLevels[i] = 0;
+            darray_free(keyi->syms[i]);
+            darray_free(keyi->acts[i]);
+            keyi->types[i] = 0;
+        }
+    }
+    keyi->typesDefined = keyi->symsDefined = keyi->actsDefined = 1 << group;
+
+    keyi->numLevels[group] = keyi->numLevels[0];
+    keyi->numLevels[0] = 0;
+    keyi->syms[group] = keyi->syms[0];
+    darray_init(keyi->syms[0]);
+    keyi->symsMapIndex[group] = keyi->symsMapIndex[0];
+    darray_init(keyi->symsMapIndex[0]);
+    keyi->symsMapNumEntries[group] = keyi->symsMapNumEntries[0];
+    darray_init(keyi->symsMapNumEntries[0]);
+    keyi->acts[group] = keyi->acts[0];
+    darray_init(keyi->acts[0]);
+    keyi->types[group] = keyi->types[0];
+    keyi->types[0] = 0;
     return true;
 }
 
@@ -1312,23 +1303,23 @@ static int
 HandleSymbolsDef(SymbolsDef *stmt, struct xkb_keymap *keymap,
                  SymbolsInfo *info)
 {
-    KeyInfo key;
+    KeyInfo keyi;
 
-    InitKeyInfo(&key, info->file_id);
-    CopyKeyInfo(&info->dflt, &key, false);
-    key.defs.merge = stmt->merge;
-    key.name = KeyNameToLong(stmt->keyName);
-    if (!HandleSymbolsBody((VarDef *) stmt->symbols, keymap, &key, info)) {
+    InitKeyInfo(&keyi, info->file_id);
+    CopyKeyInfo(&info->dflt, &keyi, false);
+    keyi.defs.merge = stmt->merge;
+    keyi.name = KeyNameToLong(stmt->keyName);
+    if (!HandleSymbolsBody((VarDef *) stmt->symbols, keymap, &keyi, info)) {
         info->errorCount++;
         return false;
     }
 
-    if (!SetExplicitGroup(info, &key)) {
+    if (!SetExplicitGroup(info, &keyi)) {
         info->errorCount++;
         return false;
     }
 
-    if (!AddKeySymbols(info, &key, keymap)) {
+    if (!AddKeySymbols(info, &keyi, keymap)) {
         info->errorCount++;
         return false;
     }
@@ -1431,9 +1422,8 @@ HandleSymbolsFile(XkbFile *file, struct xkb_keymap *keymap,
 }
 
 /**
- * Given a keysym @sym, find the keycode which generates it
- * (returned in @kc_rtrn). This is used for example in a modifier
- * map definition, such as:
+ * Given a keysym @sym, return a key which generates it, or NULL.
+ * This is used for example in a modifier map definition, such as:
  *      modifier_map Lock           { Caps_Lock };
  * where we want to add the Lock modifier to the modmap of the key
  * which matches the keysym Caps_Lock.
@@ -1441,19 +1431,18 @@ HandleSymbolsFile(XkbFile *file, struct xkb_keymap *keymap,
  * is chosen first by lowest group in which the keysym appears, than
  * by lowest level and than by lowest key code.
  */
-static bool
-FindKeyForSymbol(struct xkb_keymap *keymap, xkb_keysym_t sym,
-                 xkb_keycode_t *kc_rtrn)
+static struct xkb_key *
+FindKeyForSymbol(struct xkb_keymap *keymap, xkb_keysym_t sym)
 {
-    xkb_keycode_t key;
+    struct xkb_key *key, *ret = NULL;
     unsigned int group, level, min_group = UINT_MAX, min_level = UINT_MAX;
 
-    for (key = keymap->min_key_code; key <= keymap->max_key_code; key++) {
-        for (group = 0; group < XkbKeyNumGroups(keymap, key); group++) {
+    xkb_foreach_key(key, keymap) {
+        for (group = 0; group < key->num_groups; group++) {
             for (level = 0; level < XkbKeyGroupWidth(keymap, key, group);
                  level++) {
-                if (XkbKeyNumSyms(keymap, key, group, level) != 1 ||
-                    (XkbKeySymEntry(keymap, key, group, level))[0] != sym)
+                if (XkbKeyNumSyms(key, group, level) != 1 ||
+                    (XkbKeySymEntry(key, group, level))[0] != sym)
                     continue;
 
                 /*
@@ -1463,9 +1452,9 @@ FindKeyForSymbol(struct xkb_keymap *keymap, xkb_keysym_t sym,
                  */
                 if (group < min_group ||
                     (group == min_group && level < min_level)) {
-                    *kc_rtrn = key;
+                    ret = key;
                     if (group == 0 && level == 0) {
-                        return true;
+                        return ret;
                     }
                     else {
                         min_group = group;
@@ -1476,7 +1465,7 @@ FindKeyForSymbol(struct xkb_keymap *keymap, xkb_keysym_t sym,
         }
     }
 
-    return min_group != UINT_MAX;
+    return ret;
 }
 
 /**
@@ -1576,12 +1565,12 @@ FindAutomaticType(struct xkb_keymap *keymap, int width,
  * groups, and reduce to one group if all groups are identical anyway.
  */
 static void
-PrepareKeyDef(KeyInfo * key)
+PrepareKeyDef(KeyInfo *keyi)
 {
     int i, j, width, defined, lastGroup;
     bool identical;
 
-    defined = key->symsDefined | key->actsDefined | key->typesDefined;
+    defined = keyi->symsDefined | keyi->actsDefined | keyi->typesDefined;
     /* get highest group number */
     for (i = XkbNumKbdGroups - 1; i >= 0; i--) {
         if (defined & (1 << i))
@@ -1598,85 +1587,86 @@ PrepareKeyDef(KeyInfo * key)
     for (i = lastGroup; i > 0; i--) {
         if (defined & (1 << i))
             continue;
-        width = key->numLevels[0];
-        if (key->typesDefined & 1) {
+        width = keyi->numLevels[0];
+        if (keyi->typesDefined & 1) {
             for (j = 0; j < width; j++) {
-                key->types[i] = key->types[0];
+                keyi->types[i] = keyi->types[0];
             }
-            key->typesDefined |= 1 << i;
+            keyi->typesDefined |= 1 << i;
         }
-        if ((key->actsDefined & 1) && !darray_empty(key->acts[0])) {
-            darray_copy(key->acts[i], key->acts[0]);
-            key->actsDefined |= 1 << i;
+        if ((keyi->actsDefined & 1) && !darray_empty(keyi->acts[0])) {
+            darray_copy(keyi->acts[i], keyi->acts[0]);
+            keyi->actsDefined |= 1 << i;
         }
-        if ((key->symsDefined & 1) && !darray_empty(key->syms[0])) {
-            darray_copy(key->syms[i], key->syms[0]);
-            darray_copy(key->symsMapIndex[i], key->symsMapIndex[0]);
-            darray_copy(key->symsMapNumEntries[i], key->symsMapNumEntries[0]);
-            key->symsDefined |= 1 << i;
+        if ((keyi->symsDefined & 1) && !darray_empty(keyi->syms[0])) {
+            darray_copy(keyi->syms[i], keyi->syms[0]);
+            darray_copy(keyi->symsMapIndex[i], keyi->symsMapIndex[0]);
+            darray_copy(keyi->symsMapNumEntries[i],
+                        keyi->symsMapNumEntries[0]);
+            keyi->symsDefined |= 1 << i;
         }
         if (defined & 1) {
-            key->numLevels[i] = key->numLevels[0];
+            keyi->numLevels[i] = keyi->numLevels[0];
         }
     }
     /* If all groups are completely identical remove them all */
     /* exept the first one. */
     identical = true;
     for (i = lastGroup; i > 0; i--) {
-        if ((key->numLevels[i] != key->numLevels[0]) ||
-            (key->types[i] != key->types[0])) {
+        if ((keyi->numLevels[i] != keyi->numLevels[0]) ||
+            (keyi->types[i] != keyi->types[0])) {
             identical = false;
             break;
         }
-        if (!darray_same(key->syms[i], key->syms[0]) &&
-            (darray_empty(key->syms[i]) || darray_empty(key->syms[0]) ||
-             darray_size(key->syms[i]) != darray_size(key->syms[0]) ||
-             memcmp(darray_mem(key->syms[i], 0),
-                    darray_mem(key->syms[0], 0),
-                    sizeof(xkb_keysym_t) * darray_size(key->syms[0])))) {
+        if (!darray_same(keyi->syms[i], keyi->syms[0]) &&
+            (darray_empty(keyi->syms[i]) || darray_empty(keyi->syms[0]) ||
+             darray_size(keyi->syms[i]) != darray_size(keyi->syms[0]) ||
+             memcmp(darray_mem(keyi->syms[i], 0),
+                    darray_mem(keyi->syms[0], 0),
+                   sizeof(xkb_keysym_t) * darray_size(keyi->syms[0])))) {
             identical = false;
             break;
         }
-        if (!darray_same(key->symsMapIndex[i], key->symsMapIndex[0]) &&
-            (darray_empty(key->symsMapIndex[i]) ||
-             darray_empty(key->symsMapIndex[0]) ||
-             memcmp(darray_mem(key->symsMapIndex[i], 0),
-                    darray_mem(key->symsMapIndex[0], 0),
-                    key->numLevels[0] * sizeof(int)))) {
+        if (!darray_same(keyi->symsMapIndex[i], keyi->symsMapIndex[0]) &&
+            (darray_empty(keyi->symsMapIndex[i]) ||
+             darray_empty(keyi->symsMapIndex[0]) ||
+             memcmp(darray_mem(keyi->symsMapIndex[i], 0),
+                    darray_mem(keyi->symsMapIndex[0], 0),
+                    keyi->numLevels[0] * sizeof(int)))) {
             identical = false;
             continue;
         }
-        if (!darray_same(key->symsMapNumEntries[i],
-                         key->symsMapNumEntries[0]) &&
-            (darray_empty(key->symsMapNumEntries[i]) ||
-             darray_empty(key->symsMapNumEntries[0]) ||
-             memcmp(darray_mem(key->symsMapNumEntries[i], 0),
-                    darray_mem(key->symsMapNumEntries[0], 0),
-                    key->numLevels[0] * sizeof(size_t)))) {
+        if (!darray_same(keyi->symsMapNumEntries[i],
+                         keyi->symsMapNumEntries[0]) &&
+            (darray_empty(keyi->symsMapNumEntries[i]) ||
+             darray_empty(keyi->symsMapNumEntries[0]) ||
+             memcmp(darray_mem(keyi->symsMapNumEntries[i], 0),
+                    darray_mem(keyi->symsMapNumEntries[0], 0),
+                    keyi->numLevels[0] * sizeof(size_t)))) {
             identical = false;
             continue;
         }
-        if (!darray_same(key->acts[i], key->acts[0]) &&
-            (darray_empty(key->acts[i]) || darray_empty(key->acts[0]) ||
-             memcmp(darray_mem(key->acts[i], 0),
-                    darray_mem(key->acts[0], 0),
-                    key->numLevels[0] * sizeof(union xkb_action)))) {
+        if (!darray_same(keyi->acts[i], keyi->acts[0]) &&
+            (darray_empty(keyi->acts[i]) || darray_empty(keyi->acts[0]) ||
+             memcmp(darray_mem(keyi->acts[i], 0),
+                    darray_mem(keyi->acts[0], 0),
+                    keyi->numLevels[0] * sizeof(union xkb_action)))) {
             identical = false;
             break;
         }
     }
     if (identical) {
         for (i = lastGroup; i > 0; i--) {
-            key->numLevels[i] = 0;
-            darray_free(key->syms[i]);
-            darray_free(key->symsMapIndex[i]);
-            darray_free(key->symsMapNumEntries[i]);
-            darray_free(key->acts[i]);
-            key->types[i] = 0;
+            keyi->numLevels[i] = 0;
+            darray_free(keyi->syms[i]);
+            darray_free(keyi->symsMapIndex[i]);
+            darray_free(keyi->symsMapNumEntries[i]);
+            darray_free(keyi->acts[i]);
+            keyi->types[i] = 0;
         }
-        key->symsDefined &= 1;
-        key->actsDefined &= 1;
-        key->typesDefined &= 1;
+        keyi->symsDefined &= 1;
+        keyi->actsDefined &= 1;
+        keyi->typesDefined &= 1;
     }
 }
 
@@ -1686,10 +1676,11 @@ PrepareKeyDef(KeyInfo * key)
  * This function recurses.
  */
 static bool
-CopySymbolsDef(struct xkb_keymap *keymap, KeyInfo *key, int start_from)
+CopySymbolsDef(struct xkb_keymap *keymap, KeyInfo *keyi, int start_from)
 {
     unsigned int i;
     xkb_keycode_t kc;
+    struct xkb_key *key;
     unsigned int sizeSyms = 0;
     unsigned width, tmp, nGroups;
     struct xkb_key_type * type;
@@ -1697,105 +1688,99 @@ CopySymbolsDef(struct xkb_keymap *keymap, KeyInfo *key, int start_from)
     unsigned types[XkbNumKbdGroups];
     union xkb_action *outActs;
     unsigned int symIndex = 0;
-    struct xkb_sym_map *sym_map;
 
     useAlias = (start_from == 0);
 
-    /* get the keycode for the key. */
-    if (!FindNamedKey(keymap, key->name, &kc, useAlias,
-                      CreateKeyNames(keymap), start_from)) {
-        if ((start_from == 0) && (warningLevel >= 5)) {
-            WARN("Key %s not found in keycodes\n", longText(key->name));
+    key = FindNamedKey(keymap, keyi->name, useAlias,
+                       CreateKeyNames(keymap), start_from);
+    if (!key) {
+        if (start_from == 0 && warningLevel >= 5) {
+            WARN("Key %s not found in keycodes\n", longText(keyi->name));
             ACTION("Symbols ignored\n");
         }
         return false;
     }
+    kc = XkbKeyGetKeycode(keymap, key);
 
     haveActions = false;
     for (i = width = nGroups = 0; i < XkbNumKbdGroups; i++) {
         if (((i + 1) > nGroups)
-            && (((key->symsDefined | key->actsDefined) & (1 << i))
-                || (key->typesDefined) & (1 << i)))
+            && (((keyi->symsDefined | keyi->actsDefined) & (1 << i))
+                || (keyi->typesDefined) & (1 << i)))
             nGroups = i + 1;
-        if (!darray_empty(key->acts[i]))
+        if (!darray_empty(keyi->acts[i]))
             haveActions = true;
         autoType = false;
         /* Assign the type to the key, if it is missing. */
-        if (key->types[i] == XKB_ATOM_NONE) {
-            if (key->dfltType != XKB_ATOM_NONE)
-                key->types[i] = key->dfltType;
-            else if (FindAutomaticType(keymap, key->numLevels[i],
-                                       darray_mem(key->syms[i], 0),
-                                       &key->types[i], &autoType)) { }
+        if (keyi->types[i] == XKB_ATOM_NONE) {
+            if (keyi->dfltType != XKB_ATOM_NONE)
+                keyi->types[i] = keyi->dfltType;
+            else if (FindAutomaticType(keymap, keyi->numLevels[i],
+                                       darray_mem(keyi->syms[i], 0),
+                                       &keyi->types[i], &autoType)) { }
             else {
                 if (warningLevel >= 5) {
                     WARN("No automatic type for %d symbols\n",
-                         (unsigned int) key->numLevels[i]);
+                          (unsigned int) keyi->numLevels[i]);
                     ACTION("Using %s for the %s key (keycode %d)\n",
-                           xkb_atom_text(keymap->ctx, key->types[i]),
-                           longText(key->name), kc);
+                            xkb_atom_text(keymap->ctx, keyi->types[i]),
+                            longText(keyi->name), kc);
                 }
             }
         }
-        if (FindNamedType(keymap, key->types[i], &types[i])) {
-            if (!autoType || key->numLevels[i] > 2)
-                keymap->explicit[kc] |= (1 << i);
+        if (FindNamedType(keymap, keyi->types[i], &types[i])) {
+            if (!autoType || keyi->numLevels[i] > 2)
+                key->explicit |= (1 << i);
         }
         else {
             if (warningLevel >= 3) {
                 WARN("Type \"%s\" is not defined\n",
-                     xkb_atom_text(keymap->ctx, key->types[i]));
+                     xkb_atom_text(keymap->ctx, keyi->types[i]));
                 ACTION("Using TWO_LEVEL for the %s key (keycode %d)\n",
-                       longText(key->name), kc);
+                       longText(keyi->name), kc);
             }
             types[i] = XkbTwoLevelIndex;
         }
         /* if the type specifies fewer levels than the key has, shrink the key */
         type = &darray_item(keymap->types, types[i]);
-        if (type->num_levels < key->numLevels[i]) {
+        if (type->num_levels < keyi->numLevels[i]) {
             if (warningLevel > 0) {
                 WARN("Type \"%s\" has %d levels, but %s has %d symbols\n",
                      type->name, type->num_levels,
-                     xkb_atom_text(keymap->ctx, key->name), key->numLevels[i]);
+                     xkb_atom_text(keymap->ctx, keyi->name), keyi->numLevels[i]);
                 ACTION("Ignoring extra symbols\n");
             }
-            key->numLevels[i] = type->num_levels;
+            keyi->numLevels[i] = type->num_levels;
         }
-        if (key->numLevels[i] > width)
-            width = key->numLevels[i];
+        if (keyi->numLevels[i] > width)
+            width = keyi->numLevels[i];
         if (type->num_levels > width)
             width = type->num_levels;
-        sizeSyms += darray_size(key->syms[i]);
+        sizeSyms += darray_size(keyi->syms[i]);
     }
 
-    if (!XkbcResizeKeySyms(keymap, kc, sizeSyms)) {
-        WSGO("Could not enlarge symbols for %s (keycode %d)\n",
-             longText(key->name), kc);
-        return false;
-    }
+    darray_resize0(key->syms, sizeSyms);
+
     if (haveActions) {
-        outActs = XkbcResizeKeyActions(keymap, kc, width * nGroups);
+        outActs = XkbcResizeKeyActions(keymap, key, width * nGroups);
         if (outActs == NULL) {
             WSGO("Could not enlarge actions for %s (key %d)\n",
-                 longText(key->name), kc);
+                 longText(keyi->name), kc);
             return false;
         }
-        keymap->explicit[kc] |= XkbExplicitInterpretMask;
+        key->explicit |= XkbExplicitInterpretMask;
     }
     else
         outActs = NULL;
 
-    sym_map = &darray_item(keymap->key_sym_map, kc);
-
-    if (key->defs.defined & _Key_GroupInfo)
-        i = key->groupInfo;
-    else
-        i = sym_map->group_info;
-
-    sym_map->group_info = XkbSetNumGroups(i, nGroups);
-    sym_map->width = width;
-    sym_map->sym_index = uTypedCalloc(nGroups * width, int);
-    sym_map->num_syms = uTypedCalloc(nGroups * width, unsigned int);
+    key->num_groups = nGroups;
+    if (keyi->defs.defined & _Key_GroupInfo) {
+        key->out_of_range_group_number = keyi->out_of_range_group_number;
+        key->out_of_range_group_action = keyi->out_of_range_group_action;
+    }
+    key->width = width;
+    key->sym_index = calloc(nGroups * width, sizeof(*key->sym_index));
+    key->num_syms = calloc(nGroups * width, sizeof(*key->num_syms));
 
     for (i = 0; i < nGroups; i++) {
         /* assign kt_index[i] to the index of the type in map->types.
@@ -1805,89 +1790,91 @@ CopySymbolsDef(struct xkb_keymap *keymap, KeyInfo *key, int start_from)
          *
          * FIXME: There should be a better fix for this.
          */
-        if (key->numLevels[i])
-            sym_map->kt_index[i] = types[i];
-        if (!darray_empty(key->syms[i])) {
+        if (keyi->numLevels[i])
+            key->kt_index[i] = types[i];
+        if (!darray_empty(keyi->syms[i])) {
             /* fill key to "width" symbols*/
             for (tmp = 0; tmp < width; tmp++) {
-                if (tmp < key->numLevels[i] &&
-                    darray_item(key->symsMapNumEntries[i], tmp) != 0) {
-                    memcpy(darray_mem(sym_map->syms, symIndex),
-                           darray_mem(key->syms[i],
-                                      darray_item(key->symsMapIndex[i], tmp)),
-                           darray_item(key->symsMapNumEntries[i],
+                if (tmp < keyi->numLevels[i] &&
+                    darray_item(keyi->symsMapNumEntries[i], tmp) != 0) {
+                    memcpy(darray_mem(key->syms, symIndex),
+                           darray_mem(keyi->syms[i],
+                                      darray_item(keyi->symsMapIndex[i], tmp)),
+                           darray_item(keyi->symsMapNumEntries[i],
                                        tmp) * sizeof(xkb_keysym_t));
-                    sym_map->sym_index[(i * width) + tmp] = symIndex;
-                    sym_map->num_syms[(i * width) + tmp] =
-                        darray_item(key->symsMapNumEntries[i], tmp);
-                    symIndex += sym_map->num_syms[(i * width) + tmp];
+                    key->sym_index[(i * width) + tmp] = symIndex;
+                    key->num_syms[(i * width) + tmp] =
+                        darray_item(keyi->symsMapNumEntries[i], tmp);
+                    symIndex += key->num_syms[(i * width) + tmp];
                 }
                 else {
-                    sym_map->sym_index[(i * width) + tmp] = -1;
-                    sym_map->num_syms[(i * width) + tmp] = 0;
+                    key->sym_index[(i * width) + tmp] = -1;
+                    key->num_syms[(i * width) + tmp] = 0;
                 }
-                if (outActs != NULL && !darray_empty(key->acts[i])) {
-                    if (tmp < key->numLevels[i])
-                        outActs[tmp] = darray_item(key->acts[i], tmp);
+                if (outActs != NULL && !darray_empty(keyi->acts[i])) {
+                    if (tmp < keyi->numLevels[i])
+                        outActs[tmp] = darray_item(keyi->acts[i], tmp);
                     else
                         outActs[tmp].type = XkbSA_NoAction;
                 }
             }
         }
     }
-    switch (key->behavior.type & XkbKB_OpMask) {
+    switch (keyi->behavior.type & XkbKB_OpMask) {
     case XkbKB_Default:
         break;
 
     default:
-        keymap->behaviors[kc] = key->behavior;
-        keymap->explicit[kc] |= XkbExplicitBehaviorMask;
+        key->behavior = keyi->behavior;
+        key->explicit |= XkbExplicitBehaviorMask;
         break;
     }
-    if (key->defs.defined & _Key_VModMap) {
-        keymap->vmodmap[kc] = key->vmodmap;
-        keymap->explicit[kc] |= XkbExplicitVModMapMask;
+    if (keyi->defs.defined & _Key_VModMap) {
+        key->vmodmap = keyi->vmodmap;
+        key->explicit |= XkbExplicitVModMapMask;
     }
-    if (key->repeat != RepeatUndefined) {
-        if (key->repeat == RepeatYes)
-            keymap->ctrls->per_key_repeat[kc / 8] |= (1 << (kc % 8));
-        else
-            keymap->ctrls->per_key_repeat[kc / 8] &= ~(1 << (kc % 8));
-        keymap->explicit[kc] |= XkbExplicitAutoRepeatMask;
+    if (keyi->repeat != RepeatUndefined) {
+        key->repeats = keyi->repeat == RepeatYes;
+        key->explicit |= XkbExplicitAutoRepeatMask;
     }
 
     /* do the same thing for the next key */
-    CopySymbolsDef(keymap, key, kc + 1);
+    CopySymbolsDef(keymap, keyi, kc + 1);
     return true;
 }
 
 static bool
 CopyModMapDef(struct xkb_keymap *keymap, ModMapEntry *entry)
 {
-    xkb_keycode_t kc;
-
-    if (!entry->haveSymbol &&
-        !FindNamedKey(keymap, entry->u.keyName, &kc, true,
-                      CreateKeyNames(keymap), 0)) {
-        if (warningLevel >= 5) {
-            WARN("Key %s not found in keycodes\n",
-                 longText(entry->u.keyName));
-            ACTION("Modifier map entry for %s not updated\n",
-                   XkbcModIndexText(entry->modifier));
+    struct xkb_key *key;
+
+    if (!entry->haveSymbol) {
+        key = FindNamedKey(keymap, entry->u.keyName, true,
+                           CreateKeyNames(keymap), 0);
+        if (!key) {
+            if (warningLevel >= 5) {
+                WARN("Key %s not found in keycodes\n",
+                     longText(entry->u.keyName));
+                ACTION("Modifier map entry for %s not updated\n",
+                       XkbcModIndexText(entry->modifier));
+            }
+            return false;
         }
-        return false;
     }
-    else if (entry->haveSymbol &&
-             !FindKeyForSymbol(keymap, entry->u.keySym, &kc)) {
-        if (warningLevel > 5) {
-            WARN("Key \"%s\" not found in symbol map\n",
-                 XkbcKeysymText(entry->u.keySym));
-            ACTION("Modifier map entry for %s not updated\n",
-                   XkbcModIndexText(entry->modifier));
+    else {
+        key = FindKeyForSymbol(keymap, entry->u.keySym);
+        if (!key) {
+            if (warningLevel > 5) {
+                WARN("Key \"%s\" not found in symbol map\n",
+                     XkbcKeysymText(entry->u.keySym));
+                ACTION("Modifier map entry for %s not updated\n",
+                       XkbcModIndexText(entry->modifier));
+            }
+            return false;
         }
-        return false;
     }
-    keymap->modmap[kc] |= (1 << entry->modifier);
+
+    key->modmap |= (1 << entry->modifier);
     return true;
 }
 
@@ -1902,9 +1889,10 @@ bool
 CompileSymbols(XkbFile *file, struct xkb_keymap *keymap,
                enum merge_mode merge)
 {
-    unsigned int i;
+    int i;
+    struct xkb_key *key;
     SymbolsInfo info;
-    KeyInfo *key;
+    KeyInfo *keyi;
 
     InitSymbolsInfo(&info, keymap, file->id);
     info.dflt.defs.merge = merge;
@@ -1917,36 +1905,7 @@ CompileSymbols(XkbFile *file, struct xkb_keymap *keymap,
     if (info.errorCount != 0)
         goto err_info;
 
-    darray_resize0(keymap->key_sym_map, keymap->max_key_code + 1);
-    keymap->modmap = calloc(keymap->max_key_code + 1,
-                            sizeof(*keymap->modmap));
-    if (!keymap->modmap)
-        goto err_info;
-
-    i = keymap->max_key_code + 1;
-    keymap->explicit = calloc(keymap->max_key_code + 1,
-                              sizeof(*keymap->explicit));
-    if (!keymap->explicit)
-        goto err_info;
-
     darray_resize0(keymap->acts, darray_size(keymap->acts) + 32 + 1);
-    darray_resize0(keymap->key_acts, keymap->max_key_code + 1);
-
-    keymap->behaviors = calloc(keymap->max_key_code + 1,
-                               sizeof(*keymap->behaviors));
-    if (!keymap->behaviors)
-        goto err_info;
-
-    keymap->vmodmap = calloc(keymap->max_key_code + 1,
-                             sizeof(*keymap->vmodmap));
-    if (!keymap->vmodmap)
-        goto err_info;
-
-    if (XkbcAllocControls(keymap) != Success) {
-        WSGO("Could not allocate controls in CompileSymbols\n");
-        ACTION("Symbols not added\n");
-        goto err_info;
-    }
 
     if (info.name)
         keymap->symbols_section_name = strdup(info.name);
@@ -1963,25 +1922,22 @@ CompileSymbols(XkbFile *file, struct xkb_keymap *keymap,
     }
 
     /* sanitize keys */
-    darray_foreach(key, info.keys)
-    PrepareKeyDef(key);
+    darray_foreach(keyi, info.keys)
+        PrepareKeyDef(keyi);
 
     /* copy! */
-    darray_foreach(key, info.keys)
-    if (!CopySymbolsDef(keymap, key, 0))
-        info.errorCount++;
+    darray_foreach(keyi, info.keys)
+        if (!CopySymbolsDef(keymap, keyi, 0))
+            info.errorCount++;
 
     if (warningLevel > 3) {
-        for (i = keymap->min_key_code; i <= keymap->max_key_code; i++) {
-            if (darray_item(keymap->key_names, i).name[0] == '\0')
+        xkb_foreach_key(key, keymap) {
+            if (key->name[0] == '\0')
                 continue;
 
-            if (XkbKeyNumGroups(keymap, i) < 1) {
-                char buf[5];
-                memcpy(buf, darray_item(keymap->key_names, i).name, 4);
-                buf[4] = '\0';
-                WARN("No symbols defined for <%s> (keycode %d)\n", buf, i);
-            }
+            if (key->num_groups < 1)
+                WARN("No symbols defined for <%.4s> (keycode %d)\n",
+                     key->name, XkbKeyGetKeycode(keymap, key));
         }
     }