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;
67 /***====================================================================***/
69 #define ReportSINotArray(si, f, i) \
70 ReportNotArray("symbol interpretation", (f), siText((si), (i)))
71 #define ReportSIBadType(si, f, w, i) \
72 ReportBadType("symbol interpretation", (f), siText((si), (i)), (w))
74 /***====================================================================***/
77 siText(SymInterpInfo * si, CompatInfo * info)
81 if (si == &info->dflt) {
82 snprintf(buf, sizeof(buf), "default");
85 snprintf(buf, sizeof(buf), "%s+%s(%s)",
86 XkbcKeysymText(si->interp.sym),
87 XkbcSIMatchText(si->interp.match),
88 XkbcModMaskText(si->interp.mods, false));
94 InitCompatInfo(CompatInfo *info, struct xkb_keymap *keymap, unsigned file_id)
98 info->keymap = keymap;
100 info->file_id = file_id;
101 info->errorCount = 0;
103 info->interps = NULL;
105 info->dflt.defs.file_id = file_id;
106 info->dflt.defs.defined = 0;
107 info->dflt.defs.merge = MERGE_OVERRIDE;
108 info->dflt.interp.flags = 0;
109 info->dflt.interp.virtual_mod = XkbNoModifier;
110 info->dflt.interp.act.type = XkbSA_NoAction;
111 for (i = 0; i < sizeof(info->dflt.interp.act.any.data); i++)
112 info->dflt.interp.act.any.data[i] = 0;
113 ClearIndicatorMapInfo(keymap->ctx, &info->ledDflt);
114 info->ledDflt.defs.file_id = file_id;
115 info->ledDflt.defs.defined = 0;
116 info->ledDflt.defs.merge = MERGE_OVERRIDE;
117 memset(&info->groupCompat[0], 0,
118 XkbNumKbdGroups * sizeof(GroupCompatInfo));
120 InitVModInfo(&info->vmods, keymap);
124 ClearCompatInfo(CompatInfo *info, struct xkb_keymap *keymap)
131 info->dflt.defs.defined = 0;
132 info->dflt.defs.merge = MERGE_AUGMENT;
133 info->dflt.interp.flags = 0;
134 info->dflt.interp.virtual_mod = XkbNoModifier;
135 info->dflt.interp.act.type = XkbSA_NoAction;
136 for (i = 0; i < sizeof(info->dflt.interp.act.any.data); i++)
137 info->dflt.interp.act.any.data[i] = 0;
138 ClearIndicatorMapInfo(keymap->ctx, &info->ledDflt);
140 info->interps = ClearCommonInfo(&info->interps->defs);
141 memset(&info->groupCompat[0], 0,
142 XkbNumKbdGroups * sizeof(GroupCompatInfo));
143 info->leds = ClearCommonInfo(&info->leds->defs);
145 next = info->act->next;
149 ClearVModInfo(&info->vmods, keymap);
152 static SymInterpInfo *
153 NextInterp(CompatInfo * info)
157 si = uTypedAlloc(SymInterpInfo);
159 memset(si, 0, sizeof(SymInterpInfo));
160 info->interps = AddCommonInfo(&info->interps->defs, &si->defs);
166 static SymInterpInfo *
167 FindMatchingInterp(CompatInfo * info, SymInterpInfo * new)
171 for (old = info->interps; old != NULL;
172 old = (SymInterpInfo *) old->defs.next) {
173 if ((old->interp.sym == new->interp.sym) &&
174 (old->interp.mods == new->interp.mods) &&
175 (old->interp.match == new->interp.match)) {
183 AddInterp(CompatInfo * info, SymInterpInfo * new)
189 old = FindMatchingInterp(info, new);
191 if (new->defs.merge == MERGE_REPLACE) {
192 SymInterpInfo *next = (SymInterpInfo *) old->defs.next;
193 if (((old->defs.file_id == new->defs.file_id)
194 && (warningLevel > 0)) || (warningLevel > 9)) {
195 WARN("Multiple definitions for \"%s\"\n", siText(new, info));
196 ACTION("Earlier interpretation ignored\n");
199 old->defs.next = &next->defs;
202 if (UseNewField(_SI_VirtualMod, &old->defs, &new->defs, &collide)) {
203 old->interp.virtual_mod = new->interp.virtual_mod;
204 old->defs.defined |= _SI_VirtualMod;
206 if (UseNewField(_SI_Action, &old->defs, &new->defs, &collide)) {
207 old->interp.act = new->interp.act;
208 old->defs.defined |= _SI_Action;
210 if (UseNewField(_SI_AutoRepeat, &old->defs, &new->defs, &collide)) {
211 old->interp.flags &= ~XkbSI_AutoRepeat;
212 old->interp.flags |= (new->interp.flags & XkbSI_AutoRepeat);
213 old->defs.defined |= _SI_AutoRepeat;
215 if (UseNewField(_SI_LockingKey, &old->defs, &new->defs, &collide)) {
216 old->interp.flags &= ~XkbSI_LockingKey;
217 old->interp.flags |= (new->interp.flags & XkbSI_LockingKey);
218 old->defs.defined |= _SI_LockingKey;
220 if (UseNewField(_SI_LevelOneOnly, &old->defs, &new->defs,
222 old->interp.match &= ~XkbSI_LevelOneOnly;
223 old->interp.match |= (new->interp.match & XkbSI_LevelOneOnly);
224 old->defs.defined |= _SI_LevelOneOnly;
227 WARN("Multiple interpretations of \"%s\"\n", siText(new, info));
228 ACTION("Using %s definition for duplicate fields\n",
229 (new->defs.merge != MERGE_AUGMENT ? "last" : "first"));
234 if ((new = NextInterp(info)) == NULL)
237 new->defs.next = NULL;
242 AddGroupCompat(CompatInfo * info, unsigned group, GroupCompatInfo * newGC)
245 enum merge_mode merge;
247 merge = newGC->merge;
248 gc = &info->groupCompat[group];
249 if (((gc->real_mods == newGC->real_mods) &&
250 (gc->vmods == newGC->vmods))) {
253 if (((gc->file_id == newGC->file_id) && (warningLevel > 0))
254 || (warningLevel > 9)) {
255 WARN("Compat map for group %d redefined\n", group + 1);
256 ACTION("Using %s definition\n",
257 (merge == MERGE_AUGMENT ? "old" : "new"));
259 if (newGC->defined && (merge != MERGE_AUGMENT || !gc->defined))
264 /***====================================================================***/
267 ResolveStateAndPredicate(ExprDef * expr,
269 unsigned *mods_rtrn, CompatInfo * info)
274 *pred_rtrn = XkbSI_AnyOfOrNone;
279 *pred_rtrn = XkbSI_Exactly;
280 if (expr->op == ExprActionDecl) {
281 const char *pred_txt = xkb_atom_text(info->keymap->ctx,
282 expr->value.action.name);
283 if (strcasecmp(pred_txt, "noneof") == 0)
284 *pred_rtrn = XkbSI_NoneOf;
285 else if (strcasecmp(pred_txt, "anyofornone") == 0)
286 *pred_rtrn = XkbSI_AnyOfOrNone;
287 else if (strcasecmp(pred_txt, "anyof") == 0)
288 *pred_rtrn = XkbSI_AnyOf;
289 else if (strcasecmp(pred_txt, "allof") == 0)
290 *pred_rtrn = XkbSI_AllOf;
291 else if (strcasecmp(pred_txt, "exactly") == 0)
292 *pred_rtrn = XkbSI_Exactly;
294 ERROR("Illegal modifier predicate \"%s\"\n", pred_txt);
298 expr = expr->value.action.args;
300 else if (expr->op == ExprIdent) {
301 const char *pred_txt = xkb_atom_text(info->keymap->ctx,
303 if ((pred_txt) && (strcasecmp(pred_txt, "any") == 0)) {
304 *pred_rtrn = XkbSI_AnyOf;
310 if (ExprResolveModMask(info->keymap->ctx, expr, &result)) {
311 *mods_rtrn = result.uval;
317 /***====================================================================***/
320 MergeIncludedCompatMaps(CompatInfo * into, CompatInfo * from,
321 enum merge_mode merge)
324 LEDInfo *led, *rtrn, *next;
325 GroupCompatInfo *gcm;
328 if (from->errorCount > 0) {
329 into->errorCount += from->errorCount;
332 if (into->name == NULL) {
333 into->name = from->name;
336 for (si = from->interps; si; si = (SymInterpInfo *) si->defs.next) {
337 if (merge != MERGE_DEFAULT)
338 si->defs.merge = merge;
339 if (!AddInterp(into, si))
342 for (i = 0, gcm = &from->groupCompat[0]; i < XkbNumKbdGroups; i++,
344 if (merge != MERGE_DEFAULT)
346 if (!AddGroupCompat(into, i, gcm))
349 for (led = from->leds; led != NULL; led = next) {
350 next = (LEDInfo *) led->defs.next;
351 if (merge != MERGE_DEFAULT)
352 led->defs.merge = merge;
353 rtrn = AddIndicatorMap(from->keymap, into->leds, led);
362 HandleCompatMapFile(XkbFile *file, struct xkb_keymap *keymap,
363 enum merge_mode merge,
367 HandleIncludeCompatMap(IncludeStmt *stmt, struct xkb_keymap *keymap,
370 enum merge_mode newMerge;
376 if ((stmt->file == NULL) && (stmt->map == NULL)) {
379 memset(info, 0, sizeof(CompatInfo));
381 else if (ProcessIncludeFile(keymap->ctx, stmt, FILE_TYPE_COMPAT, &rtrn,
383 InitCompatInfo(&included, keymap, rtrn->id);
384 included.dflt = info->dflt;
385 included.dflt.defs.merge = newMerge;
386 included.ledDflt.defs.merge = newMerge;
387 included.act = info->act;
388 HandleCompatMapFile(rtrn, keymap, MERGE_OVERRIDE, &included);
389 if (stmt->stmt != NULL) {
391 included.name = stmt->stmt;
394 if (info->act != NULL)
399 info->errorCount += 10;
402 if ((stmt->next != NULL) && (included.errorCount < 1)) {
405 CompatInfo next_incl;
407 for (next = stmt->next; next != NULL; next = next->next) {
408 if ((next->file == NULL) && (next->map == NULL)) {
410 MergeIncludedCompatMaps(&included, info, next->merge);
411 ClearCompatInfo(info, keymap);
413 else if (ProcessIncludeFile(keymap->ctx, next, FILE_TYPE_COMPAT,
415 InitCompatInfo(&next_incl, keymap, rtrn->id);
416 next_incl.file_id = rtrn->id;
417 next_incl.dflt = info->dflt;
418 next_incl.dflt.defs.file_id = rtrn->id;
419 next_incl.dflt.defs.merge = op;
420 next_incl.ledDflt.defs.file_id = rtrn->id;
421 next_incl.ledDflt.defs.merge = op;
422 next_incl.act = info->act;
423 HandleCompatMapFile(rtrn, keymap, MERGE_OVERRIDE, &next_incl);
424 MergeIncludedCompatMaps(&included, &next_incl, op);
425 if (info->act != NULL)
426 next_incl.act = NULL;
427 ClearCompatInfo(&next_incl, keymap);
431 info->errorCount += 10;
439 MergeIncludedCompatMaps(info, &included, newMerge);
440 ClearCompatInfo(&included, keymap);
442 return (info->errorCount == 0);
445 static const LookupEntry useModMapValues[] = {
454 SetInterpField(SymInterpInfo *si, struct xkb_keymap *keymap, char *field,
455 ExprDef *arrayNdx, ExprDef *value, CompatInfo *info)
460 if (strcasecmp(field, "action") == 0) {
461 if (arrayNdx != NULL)
462 return ReportSINotArray(si, field, info);
463 ok = HandleActionDef(value, keymap, &si->interp.act.any, info->act);
465 si->defs.defined |= _SI_Action;
467 else if ((strcasecmp(field, "virtualmodifier") == 0) ||
468 (strcasecmp(field, "virtualmod") == 0)) {
469 if (arrayNdx != NULL)
470 return ReportSINotArray(si, field, info);
471 ok = ResolveVirtualModifier(value, keymap, &tmp, &info->vmods);
473 si->interp.virtual_mod = tmp.uval;
474 si->defs.defined |= _SI_VirtualMod;
477 return ReportSIBadType(si, field, "virtual modifier", info);
479 else if (strcasecmp(field, "repeat") == 0) {
480 if (arrayNdx != NULL)
481 return ReportSINotArray(si, field, info);
482 ok = ExprResolveBoolean(keymap->ctx, value, &tmp);
485 si->interp.flags |= XkbSI_AutoRepeat;
487 si->interp.flags &= ~XkbSI_AutoRepeat;
488 si->defs.defined |= _SI_AutoRepeat;
491 return ReportSIBadType(si, field, "boolean", info);
493 else if (strcasecmp(field, "locking") == 0) {
494 if (arrayNdx != NULL)
495 return ReportSINotArray(si, field, info);
496 ok = ExprResolveBoolean(keymap->ctx, value, &tmp);
499 si->interp.flags |= XkbSI_LockingKey;
501 si->interp.flags &= ~XkbSI_LockingKey;
502 si->defs.defined |= _SI_LockingKey;
505 return ReportSIBadType(si, field, "boolean", info);
507 else if ((strcasecmp(field, "usemodmap") == 0) ||
508 (strcasecmp(field, "usemodmapmods") == 0)) {
509 if (arrayNdx != NULL)
510 return ReportSINotArray(si, field, info);
511 ok = ExprResolveEnum(keymap->ctx, value, &tmp, useModMapValues);
514 si->interp.match |= XkbSI_LevelOneOnly;
516 si->interp.match &= ~XkbSI_LevelOneOnly;
517 si->defs.defined |= _SI_LevelOneOnly;
520 return ReportSIBadType(si, field, "level specification", info);
523 ok = ReportBadField("symbol interpretation", field, siText(si, info));
529 HandleInterpVar(VarDef * stmt, struct xkb_keymap *keymap, CompatInfo * info)
531 ExprResult elem, field;
535 if (ExprResolveLhs(keymap, stmt->name, &elem, &field, &ndx) == 0)
536 ret = 0; /* internal error, already reported */
537 else if (elem.str && (strcasecmp(elem.str, "interpret") == 0))
538 ret = SetInterpField(&info->dflt, keymap, field.str, ndx, stmt->value,
540 else if (elem.str && (strcasecmp(elem.str, "indicator") == 0))
541 ret = SetIndicatorMapField(&info->ledDflt, keymap, field.str, ndx,
544 ret = SetActionField(keymap, elem.str, field.str, ndx, stmt->value,
552 HandleInterpBody(VarDef *def, struct xkb_keymap *keymap, SymInterpInfo *si,
556 ExprResult tmp, field;
559 for (; def != NULL; def = (VarDef *) def->common.next) {
560 if ((def->name) && (def->name->type == ExprFieldRef)) {
561 ok = HandleInterpVar(def, keymap, info);
564 ok = ExprResolveLhs(keymap, def->name, &tmp, &field, &arrayNdx);
566 ok = SetInterpField(si, keymap, field.str, arrayNdx, def->value,
575 HandleInterpDef(InterpDef *def, struct xkb_keymap *keymap,
576 enum merge_mode merge,
582 if (!ResolveStateAndPredicate(def->match, &pred, &mods, info)) {
583 ERROR("Couldn't determine matching modifiers\n");
584 ACTION("Symbol interpretation ignored\n");
587 if (def->merge != MERGE_DEFAULT)
591 si.defs.merge = merge;
592 if (!LookupKeysym(def->sym, &si.interp.sym)) {
593 ERROR("Could not resolve keysym %s\n", def->sym);
594 ACTION("Symbol interpretation ignored\n");
597 si.interp.match = pred & XkbSI_OpMask;
598 si.interp.mods = mods;
599 if (!HandleInterpBody(def->def, keymap, &si, info)) {
604 if (!AddInterp(info, &si)) {
612 HandleGroupCompatDef(GroupCompatDef *def, struct xkb_keymap *keymap,
613 enum merge_mode merge, CompatInfo *info)
618 if (def->merge != MERGE_DEFAULT)
620 if (!XkbIsLegalGroup(def->group - 1)) {
621 ERROR("Keyboard group must be in the range 1..%d\n",
622 XkbNumKbdGroups + 1);
623 ACTION("Compatibility map for illegal group %d ignored\n",
627 tmp.file_id = info->file_id;
629 if (!ExprResolveVModMask(def->def, &val, keymap)) {
630 ERROR("Expected a modifier mask in group compatibility definition\n");
631 ACTION("Ignoring illegal compatibility map for group %d\n",
635 tmp.real_mods = val.uval & 0xff;
636 tmp.vmods = (val.uval >> 8) & 0xffff;
638 return AddGroupCompat(info, def->group - 1, &tmp);
642 HandleCompatMapFile(XkbFile *file, struct xkb_keymap *keymap,
643 enum merge_mode merge,
649 if (merge == MERGE_DEFAULT)
650 merge = MERGE_AUGMENT;
652 info->name = uDupString(file->name);
656 switch (stmt->stmtType) {
658 if (!HandleIncludeCompatMap((IncludeStmt *) stmt, keymap, info))
662 if (!HandleInterpDef((InterpDef *) stmt, keymap, merge, info))
665 case StmtGroupCompatDef:
666 if (!HandleGroupCompatDef
667 ((GroupCompatDef *) stmt, keymap, merge, info))
670 case StmtIndicatorMapDef:
671 leds = HandleIndicatorMapDef((IndicatorMapDef *) stmt, keymap,
672 &info->ledDflt, info->leds, merge);
679 if (!HandleInterpVar((VarDef *) stmt, keymap, info))
683 if (!HandleVModDef((VModDef *) stmt, keymap, merge, &info->vmods))
687 ERROR("Interpretation files may not include other types\n");
688 ACTION("Ignoring definition of key name\n");
692 WSGO("Unexpected statement type %d in HandleCompatMapFile\n",
697 if (info->errorCount > 10) {
699 ERROR("Too many errors\n");
701 ACTION("Abandoning compatibility map \"%s\"\n", file->topName);
708 CopyInterps(CompatInfo *info, struct xkb_keymap *keymap,
709 bool needSymbol, unsigned pred)
713 for (si = info->interps; si; si = (SymInterpInfo *) si->defs.next) {
714 if (((si->interp.match & XkbSI_OpMask) != pred) ||
715 (needSymbol && (si->interp.sym == XKB_KEY_NoSymbol)) ||
716 ((!needSymbol) && (si->interp.sym != XKB_KEY_NoSymbol)))
718 darray_append(keymap->sym_interpret, si->interp);
723 CompileCompatMap(XkbFile *file, struct xkb_keymap *keymap,
724 enum merge_mode merge)
728 GroupCompatInfo *gcm;
730 InitCompatInfo(&info, keymap, file->id);
731 info.dflt.defs.merge = merge;
732 info.ledDflt.defs.merge = merge;
734 HandleCompatMapFile(file, keymap, merge, &info);
736 if (info.errorCount != 0)
739 darray_init(keymap->sym_interpret);
740 darray_growalloc(keymap->sym_interpret, info.nInterps);
743 keymap->compat_section_name = strdup(info.name);
745 if (info.nInterps > 0) {
746 CopyInterps(&info, keymap, true, XkbSI_Exactly);
747 CopyInterps(&info, keymap, true, XkbSI_AllOf | XkbSI_NoneOf);
748 CopyInterps(&info, keymap, true, XkbSI_AnyOf);
749 CopyInterps(&info, keymap, true, XkbSI_AnyOfOrNone);
750 CopyInterps(&info, keymap, false, XkbSI_Exactly);
751 CopyInterps(&info, keymap, false, XkbSI_AllOf | XkbSI_NoneOf);
752 CopyInterps(&info, keymap, false, XkbSI_AnyOf);
753 CopyInterps(&info, keymap, false, XkbSI_AnyOfOrNone);
756 for (i = 0, gcm = &info.groupCompat[0]; i < XkbNumKbdGroups;
758 if (gcm->file_id != 0 || gcm->real_mods != 0 || gcm->vmods != 0) {
759 keymap->groups[i].mask = gcm->real_mods;
760 keymap->groups[i].real_mods = gcm->real_mods;
761 keymap->groups[i].vmods = gcm->vmods;
765 if (info.leds != NULL) {
766 if (!CopyIndicatorMapDefs(keymap, info.leds))
771 ClearCompatInfo(&info, keymap);
775 ClearCompatInfo(&info, keymap);
780 VModsToReal(struct xkb_keymap *keymap, uint32_t vmodmask)
788 for (i = 0; i < XkbNumVirtualMods; i++) {
789 if (!(vmodmask & (1 << i)))
791 ret |= keymap->vmods[i];
798 UpdateActionMods(struct xkb_keymap *keymap, union xkb_action *act,
803 case XkbSA_LatchMods:
805 if (act->mods.flags & XkbSA_UseModMapMods)
806 act->mods.real_mods = rmodmask;
807 act->mods.mask = act->mods.real_mods;
808 act->mods.mask |= VModsToReal(keymap, act->mods.vmods);
812 if (act->iso.flags & XkbSA_UseModMapMods)
813 act->iso.real_mods = rmodmask;
814 act->iso.mask = act->iso.real_mods;
815 act->iso.mask |= VModsToReal(keymap, act->iso.vmods);
824 * Find an interpretation which applies to this particular level, either by
825 * finding an exact match for the symbol and modifier combination, or a
826 * generic XKB_KEY_NoSymbol match.
828 static struct xkb_sym_interpret *
829 FindInterpForKey(struct xkb_keymap *keymap, struct xkb_key *key,
830 uint32_t group, uint32_t level)
832 struct xkb_sym_interpret *ret = NULL;
833 struct xkb_sym_interpret *interp;
834 const xkb_keysym_t *syms;
837 num_syms = xkb_key_get_syms_by_level(keymap, key, group, level, &syms);
841 darray_foreach(interp, keymap->sym_interpret) {
845 if ((num_syms > 1 || interp->sym != syms[0]) &&
846 interp->sym != XKB_KEY_NoSymbol)
849 if (level == 0 || !(interp->match & XkbSI_LevelOneOnly))
854 switch (interp->match & XkbSI_OpMask) {
856 found = !(interp->mods & mods);
858 case XkbSI_AnyOfOrNone:
859 found = (!mods || (interp->mods & mods));
862 found = !!(interp->mods & mods);
865 found = ((interp->mods & mods) == interp->mods);
868 found = (interp->mods == mods);
875 if (found && interp->sym != XKB_KEY_NoSymbol)
877 else if (found && !ret)
887 ApplyInterpsToKey(struct xkb_keymap *keymap, struct xkb_key *key)
889 #define INTERP_SIZE (8 * 4)
890 struct xkb_sym_interpret *interps[INTERP_SIZE];
891 union xkb_action *acts;
892 uint32_t vmodmask = 0;
897 /* If we've been told not to bind interps to this key, then don't. */
898 if (key->explicit & XkbExplicitInterpretMask)
901 for (i = 0; i < INTERP_SIZE; i++)
904 for (group = 0; group < key->num_groups; group++) {
905 for (level = 0; level < XkbKeyGroupWidth(keymap, key, group);
907 i = (group * key->width) + level;
908 if (i >= INTERP_SIZE) /* XXX FIXME */
910 interps[i] = FindInterpForKey(keymap, key, group, level);
917 num_acts = key->num_groups * key->width;
918 acts = XkbcResizeKeyActions(keymap, key, num_acts);
919 if (num_acts && !acts)
922 for (group = 0; group < key->num_groups; group++) {
923 for (level = 0; level < XkbKeyGroupWidth(keymap, key, group);
925 struct xkb_sym_interpret *interp;
927 i = (group * key->width) + level;
930 /* Infer default key behaviours from the base level. */
931 if (group == 0 && level == 0) {
932 if (!(key->explicit & XkbExplicitAutoRepeatMask) &&
933 (!interp || interp->flags & XkbSI_AutoRepeat))
935 if (!(key->explicit & XkbExplicitBehaviorMask) &&
936 interp && (interp->flags & XkbSI_LockingKey))
937 key->behavior.type = XkbKB_Lock;
943 if ((group == 0 && level == 0) ||
944 !(interp->match & XkbSI_LevelOneOnly)) {
945 if (interp->virtual_mod != XkbNoModifier)
946 vmodmask |= (1 << interp->virtual_mod);
948 acts[i] = interp->act;
952 if (!(key->explicit & XkbExplicitVModMapMask))
953 key->vmodmap = vmodmask;
960 * This collects a bunch of disparate functions which was done in the server
961 * at various points that really should've been done within xkbcomp. Turns out
962 * your actions and types are a lot more useful when any of your modifiers
963 * other than Shift actually do something ...
966 UpdateModifiersFromCompat(struct xkb_keymap *keymap)
970 struct xkb_key_type *type;
971 struct xkb_kt_map_entry *entry;
973 /* Find all the interprets for the key and bind them to actions,
974 * which will also update the vmodmap. */
975 xkb_foreach_key(key, keymap)
976 if (!ApplyInterpsToKey(keymap, key))
979 /* Update keymap->vmods, the virtual -> real mod mapping. */
980 for (i = 0; i < XkbNumVirtualMods; i++)
981 keymap->vmods[i] = 0;
982 xkb_foreach_key(key, keymap) {
986 for (i = 0; i < XkbNumVirtualMods; i++) {
987 if (!(key->vmodmap & (1 << i)))
989 keymap->vmods[i] |= key->modmap;
993 /* Now update the level masks for all the types to reflect the vmods. */
994 darray_foreach(type, keymap->types) {
997 type->mods.mask = type->mods.real_mods;
998 type->mods.mask |= VModsToReal(keymap, type->mods.vmods);
999 for (j = 0; j < XkbNumVirtualMods; j++) {
1000 if (!(type->mods.vmods & (1 << j)))
1002 mask |= keymap->vmods[j];
1005 darray_foreach(entry, type->map)
1006 entry->mods.mask = entry->mods.real_mods |
1007 VModsToReal(keymap, entry->mods.vmods);
1010 /* Update action modifiers. */
1011 xkb_foreach_key(key, keymap) {
1012 union xkb_action *acts = XkbKeyActionsPtr(keymap, key);
1013 for (i = 0; i < XkbKeyNumActions(key); i++) {
1014 if (acts[i].any.type == XkbSA_NoAction)
1016 UpdateActionMods(keymap, &acts[i], key->modmap);
1020 /* Update group modifiers. */
1021 for (i = 0; i < XkbNumKbdGroups; i++) {
1022 struct xkb_mods *group = &keymap->groups[i];
1023 group->mask = group->real_mods | VModsToReal(keymap, group->vmods);
1026 /* Update vmod -> indicator maps. */
1027 for (i = 0; i < XkbNumIndicators; i++) {
1028 struct xkb_mods *led = &keymap->indicators[i].mods;
1029 led->mask = led->real_mods | VModsToReal(keymap, led->vmods);