1 /************************************************************
2 * Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
4 * Permission to use, copy, modify, and distribute this
5 * software and its documentation for any purpose and without
6 * fee is hereby granted, provided that the above copyright
7 * notice appear in all copies and that both that copyright
8 * notice and this permission notice appear in supporting
9 * documentation, and that the name of Silicon Graphics not be
10 * used in advertising or publicity pertaining to distribution
11 * of the software without specific prior written permission.
12 * Silicon Graphics makes no representation about the suitability
13 * of this software for any purpose. It is provided "as is"
14 * without any express or implied warranty.
16 * SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18 * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19 * GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
23 * THE USE OR PERFORMANCE OF THIS SOFTWARE.
25 ********************************************************/
27 #include "xkbcomp-priv.h"
28 #include "parseutils.h"
30 #include "indicators.h"
33 typedef struct _SymInterpInfo {
35 struct xkb_sym_interpret interp;
38 #define _SI_VirtualMod (1 << 0)
39 #define _SI_Action (1 << 1)
40 #define _SI_AutoRepeat (1 << 2)
41 #define _SI_LockingKey (1 << 3)
42 #define _SI_LevelOneOnly (1 << 4)
44 typedef struct _GroupCompatInfo {
46 enum merge_mode merge;
48 unsigned char real_mods;
52 typedef struct _CompatInfo {
57 SymInterpInfo *interps;
60 GroupCompatInfo groupCompat[XkbNumKbdGroups];
64 struct xkb_keymap *keymap;
68 siText(SymInterpInfo * si, CompatInfo * info)
72 if (si == &info->dflt) {
73 snprintf(buf, sizeof(buf), "default");
76 snprintf(buf, sizeof(buf), "%s+%s(%s)",
77 XkbcKeysymText(si->interp.sym),
78 XkbcSIMatchText(si->interp.match),
79 XkbcModMaskText(si->interp.mods, false));
85 ReportSINotArray(SymInterpInfo *si, const char *field, CompatInfo *info)
87 return ReportNotArray("symbol interpretation", field, siText(si, info));
91 ReportSIBadType(SymInterpInfo *si, const char *field, const char *wanted,
94 return ReportBadType("symbol interpretation", field, siText(si, info),
99 InitCompatInfo(CompatInfo *info, struct xkb_keymap *keymap, unsigned file_id)
103 info->keymap = keymap;
105 info->file_id = file_id;
106 info->errorCount = 0;
108 info->interps = NULL;
110 info->dflt.defs.file_id = file_id;
111 info->dflt.defs.defined = 0;
112 info->dflt.defs.merge = MERGE_OVERRIDE;
113 info->dflt.interp.flags = 0;
114 info->dflt.interp.virtual_mod = XkbNoModifier;
115 info->dflt.interp.act.type = XkbSA_NoAction;
116 for (i = 0; i < sizeof(info->dflt.interp.act.any.data); i++)
117 info->dflt.interp.act.any.data[i] = 0;
118 ClearIndicatorMapInfo(keymap->ctx, &info->ledDflt);
119 info->ledDflt.defs.file_id = file_id;
120 info->ledDflt.defs.defined = 0;
121 info->ledDflt.defs.merge = MERGE_OVERRIDE;
122 memset(&info->groupCompat[0], 0,
123 XkbNumKbdGroups * sizeof(GroupCompatInfo));
125 InitVModInfo(&info->vmods, keymap);
129 ClearCompatInfo(CompatInfo *info, struct xkb_keymap *keymap)
136 info->dflt.defs.defined = 0;
137 info->dflt.defs.merge = MERGE_AUGMENT;
138 info->dflt.interp.flags = 0;
139 info->dflt.interp.virtual_mod = XkbNoModifier;
140 info->dflt.interp.act.type = XkbSA_NoAction;
141 for (i = 0; i < sizeof(info->dflt.interp.act.any.data); i++)
142 info->dflt.interp.act.any.data[i] = 0;
143 ClearIndicatorMapInfo(keymap->ctx, &info->ledDflt);
145 info->interps = ClearCommonInfo(&info->interps->defs);
146 memset(&info->groupCompat[0], 0,
147 XkbNumKbdGroups * sizeof(GroupCompatInfo));
148 info->leds = ClearCommonInfo(&info->leds->defs);
150 next = info->act->next;
154 ClearVModInfo(&info->vmods, keymap);
157 static SymInterpInfo *
158 NextInterp(CompatInfo * info)
162 si = uTypedAlloc(SymInterpInfo);
164 memset(si, 0, sizeof(SymInterpInfo));
165 info->interps = AddCommonInfo(&info->interps->defs, &si->defs);
171 static SymInterpInfo *
172 FindMatchingInterp(CompatInfo * info, SymInterpInfo * new)
176 for (old = info->interps; old != NULL;
177 old = (SymInterpInfo *) old->defs.next) {
178 if ((old->interp.sym == new->interp.sym) &&
179 (old->interp.mods == new->interp.mods) &&
180 (old->interp.match == new->interp.match)) {
188 AddInterp(CompatInfo * info, SymInterpInfo * new)
194 old = FindMatchingInterp(info, new);
196 if (new->defs.merge == MERGE_REPLACE) {
197 SymInterpInfo *next = (SymInterpInfo *) old->defs.next;
198 if (((old->defs.file_id == new->defs.file_id)
199 && (warningLevel > 0)) || (warningLevel > 9)) {
200 WARN("Multiple definitions for \"%s\"\n", siText(new, info));
201 ACTION("Earlier interpretation ignored\n");
204 old->defs.next = &next->defs;
207 if (UseNewField(_SI_VirtualMod, &old->defs, &new->defs, &collide)) {
208 old->interp.virtual_mod = new->interp.virtual_mod;
209 old->defs.defined |= _SI_VirtualMod;
211 if (UseNewField(_SI_Action, &old->defs, &new->defs, &collide)) {
212 old->interp.act = new->interp.act;
213 old->defs.defined |= _SI_Action;
215 if (UseNewField(_SI_AutoRepeat, &old->defs, &new->defs, &collide)) {
216 old->interp.flags &= ~XkbSI_AutoRepeat;
217 old->interp.flags |= (new->interp.flags & XkbSI_AutoRepeat);
218 old->defs.defined |= _SI_AutoRepeat;
220 if (UseNewField(_SI_LockingKey, &old->defs, &new->defs, &collide)) {
221 old->interp.flags &= ~XkbSI_LockingKey;
222 old->interp.flags |= (new->interp.flags & XkbSI_LockingKey);
223 old->defs.defined |= _SI_LockingKey;
225 if (UseNewField(_SI_LevelOneOnly, &old->defs, &new->defs,
227 old->interp.match &= ~XkbSI_LevelOneOnly;
228 old->interp.match |= (new->interp.match & XkbSI_LevelOneOnly);
229 old->defs.defined |= _SI_LevelOneOnly;
232 WARN("Multiple interpretations of \"%s\"\n", siText(new, info));
233 ACTION("Using %s definition for duplicate fields\n",
234 (new->defs.merge != MERGE_AUGMENT ? "last" : "first"));
239 if ((new = NextInterp(info)) == NULL)
242 new->defs.next = NULL;
247 AddGroupCompat(CompatInfo * info, unsigned group, GroupCompatInfo * newGC)
250 enum merge_mode merge;
252 merge = newGC->merge;
253 gc = &info->groupCompat[group];
254 if (((gc->real_mods == newGC->real_mods) &&
255 (gc->vmods == newGC->vmods))) {
258 if (((gc->file_id == newGC->file_id) && (warningLevel > 0))
259 || (warningLevel > 9)) {
260 WARN("Compat map for group %d redefined\n", group + 1);
261 ACTION("Using %s definition\n",
262 (merge == MERGE_AUGMENT ? "old" : "new"));
264 if (newGC->defined && (merge != MERGE_AUGMENT || !gc->defined))
269 /***====================================================================***/
272 ResolveStateAndPredicate(ExprDef * expr,
274 unsigned *mods_rtrn, CompatInfo * info)
279 *pred_rtrn = XkbSI_AnyOfOrNone;
284 *pred_rtrn = XkbSI_Exactly;
285 if (expr->op == ExprActionDecl) {
286 const char *pred_txt = xkb_atom_text(info->keymap->ctx,
287 expr->value.action.name);
288 if (strcasecmp(pred_txt, "noneof") == 0)
289 *pred_rtrn = XkbSI_NoneOf;
290 else if (strcasecmp(pred_txt, "anyofornone") == 0)
291 *pred_rtrn = XkbSI_AnyOfOrNone;
292 else if (strcasecmp(pred_txt, "anyof") == 0)
293 *pred_rtrn = XkbSI_AnyOf;
294 else if (strcasecmp(pred_txt, "allof") == 0)
295 *pred_rtrn = XkbSI_AllOf;
296 else if (strcasecmp(pred_txt, "exactly") == 0)
297 *pred_rtrn = XkbSI_Exactly;
299 ERROR("Illegal modifier predicate \"%s\"\n", pred_txt);
303 expr = expr->value.action.args;
305 else if (expr->op == ExprIdent) {
306 const char *pred_txt = xkb_atom_text(info->keymap->ctx,
308 if ((pred_txt) && (strcasecmp(pred_txt, "any") == 0)) {
309 *pred_rtrn = XkbSI_AnyOf;
315 if (ExprResolveModMask(info->keymap->ctx, expr, &result)) {
316 *mods_rtrn = result.uval;
322 /***====================================================================***/
325 MergeIncludedCompatMaps(CompatInfo * into, CompatInfo * from,
326 enum merge_mode merge)
329 LEDInfo *led, *rtrn, *next;
330 GroupCompatInfo *gcm;
333 if (from->errorCount > 0) {
334 into->errorCount += from->errorCount;
337 if (into->name == NULL) {
338 into->name = from->name;
341 for (si = from->interps; si; si = (SymInterpInfo *) si->defs.next) {
342 if (merge != MERGE_DEFAULT)
343 si->defs.merge = merge;
344 if (!AddInterp(into, si))
347 for (i = 0, gcm = &from->groupCompat[0]; i < XkbNumKbdGroups; i++,
349 if (merge != MERGE_DEFAULT)
351 if (!AddGroupCompat(into, i, gcm))
354 for (led = from->leds; led != NULL; led = next) {
355 next = (LEDInfo *) led->defs.next;
356 if (merge != MERGE_DEFAULT)
357 led->defs.merge = merge;
358 rtrn = AddIndicatorMap(from->keymap, into->leds, led);
367 HandleCompatMapFile(XkbFile *file, struct xkb_keymap *keymap,
368 enum merge_mode merge,
372 HandleIncludeCompatMap(IncludeStmt *stmt, struct xkb_keymap *keymap,
375 enum merge_mode newMerge;
381 if ((stmt->file == NULL) && (stmt->map == NULL)) {
384 memset(info, 0, sizeof(CompatInfo));
386 else if (ProcessIncludeFile(keymap->ctx, stmt, FILE_TYPE_COMPAT, &rtrn,
388 InitCompatInfo(&included, keymap, rtrn->id);
389 included.dflt = info->dflt;
390 included.dflt.defs.merge = newMerge;
391 included.ledDflt.defs.merge = newMerge;
392 included.act = info->act;
393 HandleCompatMapFile(rtrn, keymap, MERGE_OVERRIDE, &included);
394 if (stmt->stmt != NULL) {
396 included.name = stmt->stmt;
399 if (info->act != NULL)
404 info->errorCount += 10;
407 if ((stmt->next != NULL) && (included.errorCount < 1)) {
410 CompatInfo next_incl;
412 for (next = stmt->next; next != NULL; next = next->next) {
413 if ((next->file == NULL) && (next->map == NULL)) {
415 MergeIncludedCompatMaps(&included, info, next->merge);
416 ClearCompatInfo(info, keymap);
418 else if (ProcessIncludeFile(keymap->ctx, next, FILE_TYPE_COMPAT,
420 InitCompatInfo(&next_incl, keymap, rtrn->id);
421 next_incl.file_id = rtrn->id;
422 next_incl.dflt = info->dflt;
423 next_incl.dflt.defs.file_id = rtrn->id;
424 next_incl.dflt.defs.merge = op;
425 next_incl.ledDflt.defs.file_id = rtrn->id;
426 next_incl.ledDflt.defs.merge = op;
427 next_incl.act = info->act;
428 HandleCompatMapFile(rtrn, keymap, MERGE_OVERRIDE, &next_incl);
429 MergeIncludedCompatMaps(&included, &next_incl, op);
430 if (info->act != NULL)
431 next_incl.act = NULL;
432 ClearCompatInfo(&next_incl, keymap);
436 info->errorCount += 10;
444 MergeIncludedCompatMaps(info, &included, newMerge);
445 ClearCompatInfo(&included, keymap);
447 return (info->errorCount == 0);
450 static const LookupEntry useModMapValues[] = {
459 SetInterpField(SymInterpInfo *si, struct xkb_keymap *keymap, char *field,
460 ExprDef *arrayNdx, ExprDef *value, CompatInfo *info)
465 if (strcasecmp(field, "action") == 0) {
466 if (arrayNdx != NULL)
467 return ReportSINotArray(si, field, info);
468 ok = HandleActionDef(value, keymap, &si->interp.act.any, info->act);
470 si->defs.defined |= _SI_Action;
472 else if ((strcasecmp(field, "virtualmodifier") == 0) ||
473 (strcasecmp(field, "virtualmod") == 0)) {
474 if (arrayNdx != NULL)
475 return ReportSINotArray(si, field, info);
476 ok = ResolveVirtualModifier(value, keymap, &tmp, &info->vmods);
478 si->interp.virtual_mod = tmp.uval;
479 si->defs.defined |= _SI_VirtualMod;
482 return ReportSIBadType(si, field, "virtual modifier", info);
484 else if (strcasecmp(field, "repeat") == 0) {
485 if (arrayNdx != NULL)
486 return ReportSINotArray(si, field, info);
487 ok = ExprResolveBoolean(keymap->ctx, value, &tmp);
490 si->interp.flags |= XkbSI_AutoRepeat;
492 si->interp.flags &= ~XkbSI_AutoRepeat;
493 si->defs.defined |= _SI_AutoRepeat;
496 return ReportSIBadType(si, field, "boolean", info);
498 else if (strcasecmp(field, "locking") == 0) {
499 if (arrayNdx != NULL)
500 return ReportSINotArray(si, field, info);
501 ok = ExprResolveBoolean(keymap->ctx, value, &tmp);
504 si->interp.flags |= XkbSI_LockingKey;
506 si->interp.flags &= ~XkbSI_LockingKey;
507 si->defs.defined |= _SI_LockingKey;
510 return ReportSIBadType(si, field, "boolean", info);
512 else if ((strcasecmp(field, "usemodmap") == 0) ||
513 (strcasecmp(field, "usemodmapmods") == 0)) {
514 if (arrayNdx != NULL)
515 return ReportSINotArray(si, field, info);
516 ok = ExprResolveEnum(keymap->ctx, value, &tmp, useModMapValues);
519 si->interp.match |= XkbSI_LevelOneOnly;
521 si->interp.match &= ~XkbSI_LevelOneOnly;
522 si->defs.defined |= _SI_LevelOneOnly;
525 return ReportSIBadType(si, field, "level specification", info);
528 ok = ReportBadField("symbol interpretation", field, siText(si, info));
534 HandleInterpVar(VarDef * stmt, struct xkb_keymap *keymap, CompatInfo * info)
536 ExprResult elem, field;
540 if (ExprResolveLhs(keymap, stmt->name, &elem, &field, &ndx) == 0)
541 ret = 0; /* internal error, already reported */
542 else if (elem.str && (strcasecmp(elem.str, "interpret") == 0))
543 ret = SetInterpField(&info->dflt, keymap, field.str, ndx, stmt->value,
545 else if (elem.str && (strcasecmp(elem.str, "indicator") == 0))
546 ret = SetIndicatorMapField(&info->ledDflt, keymap, field.str, ndx,
549 ret = SetActionField(keymap, elem.str, field.str, ndx, stmt->value,
557 HandleInterpBody(VarDef *def, struct xkb_keymap *keymap, SymInterpInfo *si,
561 ExprResult tmp, field;
564 for (; def != NULL; def = (VarDef *) def->common.next) {
565 if ((def->name) && (def->name->type == ExprFieldRef)) {
566 ok = HandleInterpVar(def, keymap, info);
569 ok = ExprResolveLhs(keymap, def->name, &tmp, &field, &arrayNdx);
571 ok = SetInterpField(si, keymap, field.str, arrayNdx, def->value,
580 HandleInterpDef(InterpDef *def, struct xkb_keymap *keymap,
581 enum merge_mode merge,
587 if (!ResolveStateAndPredicate(def->match, &pred, &mods, info)) {
588 ERROR("Couldn't determine matching modifiers\n");
589 ACTION("Symbol interpretation ignored\n");
592 if (def->merge != MERGE_DEFAULT)
596 si.defs.merge = merge;
597 if (!LookupKeysym(def->sym, &si.interp.sym)) {
598 ERROR("Could not resolve keysym %s\n", def->sym);
599 ACTION("Symbol interpretation ignored\n");
602 si.interp.match = pred & XkbSI_OpMask;
603 si.interp.mods = mods;
604 if (!HandleInterpBody(def->def, keymap, &si, info)) {
609 if (!AddInterp(info, &si)) {
617 HandleGroupCompatDef(GroupCompatDef *def, struct xkb_keymap *keymap,
618 enum merge_mode merge, CompatInfo *info)
623 if (def->merge != MERGE_DEFAULT)
625 if (!XkbIsLegalGroup(def->group - 1)) {
626 ERROR("Keyboard group must be in the range 1..%d\n",
627 XkbNumKbdGroups + 1);
628 ACTION("Compatibility map for illegal group %d ignored\n",
632 tmp.file_id = info->file_id;
634 if (!ExprResolveVModMask(def->def, &val, keymap)) {
635 ERROR("Expected a modifier mask in group compatibility definition\n");
636 ACTION("Ignoring illegal compatibility map for group %d\n",
640 tmp.real_mods = val.uval & 0xff;
641 tmp.vmods = (val.uval >> 8) & 0xffff;
643 return AddGroupCompat(info, def->group - 1, &tmp);
647 HandleCompatMapFile(XkbFile *file, struct xkb_keymap *keymap,
648 enum merge_mode merge,
654 if (merge == MERGE_DEFAULT)
655 merge = MERGE_AUGMENT;
657 info->name = uDupString(file->name);
661 switch (stmt->stmtType) {
663 if (!HandleIncludeCompatMap((IncludeStmt *) stmt, keymap, info))
667 if (!HandleInterpDef((InterpDef *) stmt, keymap, merge, info))
670 case StmtGroupCompatDef:
671 if (!HandleGroupCompatDef
672 ((GroupCompatDef *) stmt, keymap, merge, info))
675 case StmtIndicatorMapDef:
676 leds = HandleIndicatorMapDef((IndicatorMapDef *) stmt, keymap,
677 &info->ledDflt, info->leds, merge);
684 if (!HandleInterpVar((VarDef *) stmt, keymap, info))
688 if (!HandleVModDef((VModDef *) stmt, keymap, merge, &info->vmods))
692 ERROR("Interpretation files may not include other types\n");
693 ACTION("Ignoring definition of key name\n");
697 WSGO("Unexpected statement type %d in HandleCompatMapFile\n",
702 if (info->errorCount > 10) {
704 ERROR("Too many errors\n");
706 ACTION("Abandoning compatibility map \"%s\"\n", file->topName);
713 CopyInterps(CompatInfo *info, struct xkb_keymap *keymap,
714 bool needSymbol, unsigned pred)
718 for (si = info->interps; si; si = (SymInterpInfo *) si->defs.next) {
719 if (((si->interp.match & XkbSI_OpMask) != pred) ||
720 (needSymbol && (si->interp.sym == XKB_KEY_NoSymbol)) ||
721 ((!needSymbol) && (si->interp.sym != XKB_KEY_NoSymbol)))
723 darray_append(keymap->sym_interpret, si->interp);
728 CompileCompatMap(XkbFile *file, struct xkb_keymap *keymap,
729 enum merge_mode merge)
733 GroupCompatInfo *gcm;
735 InitCompatInfo(&info, keymap, file->id);
736 info.dflt.defs.merge = merge;
737 info.ledDflt.defs.merge = merge;
739 HandleCompatMapFile(file, keymap, merge, &info);
741 if (info.errorCount != 0)
744 darray_init(keymap->sym_interpret);
745 darray_growalloc(keymap->sym_interpret, info.nInterps);
748 keymap->compat_section_name = strdup(info.name);
750 if (info.nInterps > 0) {
751 CopyInterps(&info, keymap, true, XkbSI_Exactly);
752 CopyInterps(&info, keymap, true, XkbSI_AllOf | XkbSI_NoneOf);
753 CopyInterps(&info, keymap, true, XkbSI_AnyOf);
754 CopyInterps(&info, keymap, true, XkbSI_AnyOfOrNone);
755 CopyInterps(&info, keymap, false, XkbSI_Exactly);
756 CopyInterps(&info, keymap, false, XkbSI_AllOf | XkbSI_NoneOf);
757 CopyInterps(&info, keymap, false, XkbSI_AnyOf);
758 CopyInterps(&info, keymap, false, XkbSI_AnyOfOrNone);
761 for (i = 0, gcm = &info.groupCompat[0]; i < XkbNumKbdGroups;
763 if (gcm->file_id != 0 || gcm->real_mods != 0 || gcm->vmods != 0) {
764 keymap->groups[i].mask = gcm->real_mods;
765 keymap->groups[i].real_mods = gcm->real_mods;
766 keymap->groups[i].vmods = gcm->vmods;
770 if (info.leds != NULL) {
771 if (!CopyIndicatorMapDefs(keymap, info.leds))
776 ClearCompatInfo(&info, keymap);
780 ClearCompatInfo(&info, keymap);
785 VModsToReal(struct xkb_keymap *keymap, uint32_t vmodmask)
793 for (i = 0; i < XkbNumVirtualMods; i++) {
794 if (!(vmodmask & (1 << i)))
796 ret |= keymap->vmods[i];
803 UpdateActionMods(struct xkb_keymap *keymap, union xkb_action *act,
808 case XkbSA_LatchMods:
810 if (act->mods.flags & XkbSA_UseModMapMods)
811 act->mods.real_mods = rmodmask;
812 act->mods.mask = act->mods.real_mods;
813 act->mods.mask |= VModsToReal(keymap, act->mods.vmods);
817 if (act->iso.flags & XkbSA_UseModMapMods)
818 act->iso.real_mods = rmodmask;
819 act->iso.mask = act->iso.real_mods;
820 act->iso.mask |= VModsToReal(keymap, act->iso.vmods);
829 * Find an interpretation which applies to this particular level, either by
830 * finding an exact match for the symbol and modifier combination, or a
831 * generic XKB_KEY_NoSymbol match.
833 static struct xkb_sym_interpret *
834 FindInterpForKey(struct xkb_keymap *keymap, struct xkb_key *key,
835 uint32_t group, uint32_t level)
837 struct xkb_sym_interpret *ret = NULL;
838 struct xkb_sym_interpret *interp;
839 const xkb_keysym_t *syms;
842 num_syms = xkb_key_get_syms_by_level(keymap, key, group, level, &syms);
846 darray_foreach(interp, keymap->sym_interpret) {
850 if ((num_syms > 1 || interp->sym != syms[0]) &&
851 interp->sym != XKB_KEY_NoSymbol)
854 if (level == 0 || !(interp->match & XkbSI_LevelOneOnly))
859 switch (interp->match & XkbSI_OpMask) {
861 found = !(interp->mods & mods);
863 case XkbSI_AnyOfOrNone:
864 found = (!mods || (interp->mods & mods));
867 found = !!(interp->mods & mods);
870 found = ((interp->mods & mods) == interp->mods);
873 found = (interp->mods == mods);
880 if (found && interp->sym != XKB_KEY_NoSymbol)
882 else if (found && !ret)
892 ApplyInterpsToKey(struct xkb_keymap *keymap, struct xkb_key *key)
894 #define INTERP_SIZE (8 * 4)
895 struct xkb_sym_interpret *interps[INTERP_SIZE];
896 union xkb_action *acts;
897 uint32_t vmodmask = 0;
902 /* If we've been told not to bind interps to this key, then don't. */
903 if (key->explicit & XkbExplicitInterpretMask)
906 for (i = 0; i < INTERP_SIZE; i++)
909 for (group = 0; group < key->num_groups; group++) {
910 for (level = 0; level < XkbKeyGroupWidth(keymap, key, group);
912 i = (group * key->width) + level;
913 if (i >= INTERP_SIZE) /* XXX FIXME */
915 interps[i] = FindInterpForKey(keymap, key, group, level);
922 num_acts = key->num_groups * key->width;
923 acts = XkbcResizeKeyActions(keymap, key, num_acts);
924 if (num_acts && !acts)
927 for (group = 0; group < key->num_groups; group++) {
928 for (level = 0; level < XkbKeyGroupWidth(keymap, key, group);
930 struct xkb_sym_interpret *interp;
932 i = (group * key->width) + level;
935 /* Infer default key behaviours from the base level. */
936 if (group == 0 && level == 0) {
937 if (!(key->explicit & XkbExplicitAutoRepeatMask) &&
938 (!interp || interp->flags & XkbSI_AutoRepeat))
940 if (!(key->explicit & XkbExplicitBehaviorMask) &&
941 interp && (interp->flags & XkbSI_LockingKey))
942 key->behavior.type = XkbKB_Lock;
948 if ((group == 0 && level == 0) ||
949 !(interp->match & XkbSI_LevelOneOnly)) {
950 if (interp->virtual_mod != XkbNoModifier)
951 vmodmask |= (1 << interp->virtual_mod);
953 acts[i] = interp->act;
957 if (!(key->explicit & XkbExplicitVModMapMask))
958 key->vmodmap = vmodmask;
965 * This collects a bunch of disparate functions which was done in the server
966 * at various points that really should've been done within xkbcomp. Turns out
967 * your actions and types are a lot more useful when any of your modifiers
968 * other than Shift actually do something ...
971 UpdateModifiersFromCompat(struct xkb_keymap *keymap)
975 struct xkb_key_type *type;
976 struct xkb_kt_map_entry *entry;
978 /* Find all the interprets for the key and bind them to actions,
979 * which will also update the vmodmap. */
980 xkb_foreach_key(key, keymap)
981 if (!ApplyInterpsToKey(keymap, key))
984 /* Update keymap->vmods, the virtual -> real mod mapping. */
985 for (i = 0; i < XkbNumVirtualMods; i++)
986 keymap->vmods[i] = 0;
987 xkb_foreach_key(key, keymap) {
991 for (i = 0; i < XkbNumVirtualMods; i++) {
992 if (!(key->vmodmap & (1 << i)))
994 keymap->vmods[i] |= key->modmap;
998 /* Now update the level masks for all the types to reflect the vmods. */
999 darray_foreach(type, keymap->types) {
1002 type->mods.mask = type->mods.real_mods;
1003 type->mods.mask |= VModsToReal(keymap, type->mods.vmods);
1004 for (j = 0; j < XkbNumVirtualMods; j++) {
1005 if (!(type->mods.vmods & (1 << j)))
1007 mask |= keymap->vmods[j];
1010 darray_foreach(entry, type->map)
1011 entry->mods.mask = entry->mods.real_mods |
1012 VModsToReal(keymap, entry->mods.vmods);
1015 /* Update action modifiers. */
1016 xkb_foreach_key(key, keymap) {
1017 union xkb_action *acts = XkbKeyActionsPtr(keymap, key);
1018 for (i = 0; i < XkbKeyNumActions(key); i++) {
1019 if (acts[i].any.type == XkbSA_NoAction)
1021 UpdateActionMods(keymap, &acts[i], key->modmap);
1025 /* Update group modifiers. */
1026 for (i = 0; i < XkbNumKbdGroups; i++) {
1027 struct xkb_mods *group = &keymap->groups[i];
1028 group->mask = group->real_mods | VModsToReal(keymap, group->vmods);
1031 /* Update vmod -> indicator maps. */
1032 for (i = 0; i < XkbNumIndicators; i++) {
1033 struct xkb_mods *led = &keymap->indicators[i].mods;
1034 led->mask = led->real_mods | VModsToReal(keymap, led->vmods);