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"
32 typedef struct _SymInterpInfo {
33 unsigned short defined;
35 enum merge_mode merge;
38 struct xkb_sym_interpret interp;
41 #define _SI_VirtualMod (1 << 0)
42 #define _SI_Action (1 << 1)
43 #define _SI_AutoRepeat (1 << 2)
44 #define _SI_LockingKey (1 << 3)
45 #define _SI_LevelOneOnly (1 << 4)
47 typedef struct _LEDInfo {
48 unsigned short defined;
50 enum merge_mode merge;
54 unsigned char indicator;
56 unsigned char which_mods;
57 unsigned char real_mods;
59 unsigned char which_groups;
64 #define _LED_Index (1 << 0)
65 #define _LED_Mods (1 << 1)
66 #define _LED_Groups (1 << 2)
67 #define _LED_Ctrls (1 << 3)
68 #define _LED_Explicit (1 << 4)
69 #define _LED_Automatic (1 << 5)
70 #define _LED_DrivesKbd (1 << 6)
72 #define _LED_NotBound 255
74 typedef struct _GroupCompatInfo {
76 enum merge_mode merge;
78 unsigned char real_mods;
82 typedef struct _CompatInfo {
90 GroupCompatInfo groupCompat[XkbNumKbdGroups];
94 struct xkb_keymap *keymap;
98 siText(SymInterpInfo * si, CompatInfo * info)
100 static char buf[128];
102 if (si == &info->dflt) {
103 snprintf(buf, sizeof(buf), "default");
106 snprintf(buf, sizeof(buf), "%s+%s(%s)",
107 KeysymText(si->interp.sym),
108 SIMatchText(si->interp.match),
109 ModMaskText(si->interp.mods, false));
115 ReportSINotArray(CompatInfo *info, SymInterpInfo *si, const char *field)
117 return ReportNotArray(info->keymap, "symbol interpretation", field,
122 ReportSIBadType(CompatInfo *info, SymInterpInfo *si, const char *field,
125 return ReportBadType(info->keymap, "symbol interpretation", field,
126 siText(si, info), wanted);
130 ReportIndicatorBadType(CompatInfo *info, LEDInfo *led,
131 const char *field, const char *wanted)
133 return ReportBadType(info->keymap, "indicator map", field,
134 xkb_atom_text(info->keymap->ctx, led->name),
139 ReportIndicatorNotArray(CompatInfo *info, LEDInfo *led,
142 return ReportNotArray(info->keymap, "indicator map", field,
143 xkb_atom_text(info->keymap->ctx, led->name));
147 ClearIndicatorMapInfo(struct xkb_context *ctx, LEDInfo * info)
149 info->name = xkb_atom_intern(ctx, "default");
150 info->indicator = _LED_NotBound;
151 info->flags = info->which_mods = info->real_mods = 0;
153 info->which_groups = info->groups = 0;
158 InitCompatInfo(CompatInfo *info, struct xkb_keymap *keymap, unsigned file_id)
162 info->keymap = keymap;
164 info->file_id = file_id;
165 info->errorCount = 0;
167 list_init(&info->interps);
169 info->dflt.file_id = file_id;
170 info->dflt.defined = 0;
171 info->dflt.merge = MERGE_OVERRIDE;
172 info->dflt.interp.flags = 0;
173 info->dflt.interp.virtual_mod = XkbNoModifier;
174 info->dflt.interp.act.type = XkbSA_NoAction;
175 for (i = 0; i < sizeof(info->dflt.interp.act.any.data); i++)
176 info->dflt.interp.act.any.data[i] = 0;
177 ClearIndicatorMapInfo(keymap->ctx, &info->ledDflt);
178 info->ledDflt.file_id = file_id;
179 info->ledDflt.defined = 0;
180 info->ledDflt.merge = MERGE_OVERRIDE;
181 memset(&info->groupCompat[0], 0,
182 XkbNumKbdGroups * sizeof(GroupCompatInfo));
183 list_init(&info->leds);
184 InitVModInfo(&info->vmods, keymap);
188 ClearCompatInfo(CompatInfo *info)
191 ActionInfo *next_act;
192 SymInterpInfo *si, *next_si;
193 LEDInfo *led, *next_led;
194 struct xkb_keymap *keymap = info->keymap;
198 info->dflt.defined = 0;
199 info->dflt.merge = MERGE_AUGMENT;
200 info->dflt.interp.flags = 0;
201 info->dflt.interp.virtual_mod = XkbNoModifier;
202 info->dflt.interp.act.type = XkbSA_NoAction;
203 for (i = 0; i < sizeof(info->dflt.interp.act.any.data); i++)
204 info->dflt.interp.act.any.data[i] = 0;
205 ClearIndicatorMapInfo(keymap->ctx, &info->ledDflt);
207 list_foreach_safe(si, next_si, &info->interps, entry)
209 memset(&info->groupCompat[0], 0,
210 XkbNumKbdGroups * sizeof(GroupCompatInfo));
211 list_foreach_safe(led, next_led, &info->leds, entry)
214 next_act = info->act->next;
216 info->act = next_act;
219 ClearVModInfo(&info->vmods, keymap);
222 static SymInterpInfo *
223 NextInterp(CompatInfo * info)
227 si = calloc(1, sizeof(*si));
231 list_append(&si->entry, &info->interps);
237 static SymInterpInfo *
238 FindMatchingInterp(CompatInfo * info, SymInterpInfo * new)
242 list_foreach(old, &info->interps, entry)
243 if (old->interp.sym == new->interp.sym &&
244 old->interp.mods == new->interp.mods &&
245 old->interp.match == new->interp.match)
252 UseNewInterpField(unsigned field, SymInterpInfo *old, SymInterpInfo *new,
253 int verbosity, unsigned *collide)
255 if (!(old->defined & field))
258 if (new->defined & field) {
259 if ((old->file_id == new->file_id && verbosity > 0) || verbosity > 9)
262 if (new->merge != MERGE_AUGMENT)
270 AddInterp(CompatInfo * info, SymInterpInfo * new)
275 int verbosity = xkb_get_log_verbosity(info->keymap->ctx);
278 old = FindMatchingInterp(info, new);
280 if (new->merge == MERGE_REPLACE) {
282 if ((old->file_id == new->file_id && verbosity > 0) ||
284 log_warn(info->keymap->ctx,
285 "Multiple definitions for \"%s\"; "
286 "Earlier interpretation ignored\n",
293 if (UseNewInterpField(_SI_VirtualMod, old, new, verbosity,
295 old->interp.virtual_mod = new->interp.virtual_mod;
296 old->defined |= _SI_VirtualMod;
298 if (UseNewInterpField(_SI_Action, old, new, verbosity,
300 old->interp.act = new->interp.act;
301 old->defined |= _SI_Action;
303 if (UseNewInterpField(_SI_AutoRepeat, old, new, verbosity,
305 old->interp.flags &= ~XkbSI_AutoRepeat;
306 old->interp.flags |= (new->interp.flags & XkbSI_AutoRepeat);
307 old->defined |= _SI_AutoRepeat;
309 if (UseNewInterpField(_SI_LockingKey, old, new, verbosity,
311 old->interp.flags &= ~XkbSI_LockingKey;
312 old->interp.flags |= (new->interp.flags & XkbSI_LockingKey);
313 old->defined |= _SI_LockingKey;
315 if (UseNewInterpField(_SI_LevelOneOnly, old, new, verbosity,
317 old->interp.match &= ~XkbSI_LevelOneOnly;
318 old->interp.match |= (new->interp.match & XkbSI_LevelOneOnly);
319 old->defined |= _SI_LevelOneOnly;
323 log_warn(info->keymap->ctx,
324 "Multiple interpretations of \"%s\"; "
325 "Using %s definition for duplicate fields\n",
327 (new->merge != MERGE_AUGMENT ? "last" : "first"));
334 if ((new = NextInterp(info)) == NULL)
343 AddGroupCompat(CompatInfo *info, xkb_group_index_t group, GroupCompatInfo *new)
346 int verbosity = xkb_get_log_verbosity(info->keymap->ctx);
348 gc = &info->groupCompat[group];
349 if (gc->real_mods == new->real_mods && gc->vmods == new->vmods)
352 if ((gc->file_id == new->file_id && verbosity > 0) || verbosity > 9)
353 log_warn(info->keymap->ctx,
354 "Compat map for group %u redefined; "
355 "Using %s definition\n",
356 group + 1, (new->merge == MERGE_AUGMENT ? "old" : "new"));
358 if (new->defined && (new->merge != MERGE_AUGMENT || !gc->defined))
364 /***====================================================================***/
367 ResolveStateAndPredicate(ExprDef * expr,
369 xkb_mod_mask_t *mods_rtrn, CompatInfo * info)
372 *pred_rtrn = XkbSI_AnyOfOrNone;
377 *pred_rtrn = XkbSI_Exactly;
378 if (expr->op == EXPR_ACTION_DECL) {
379 const char *pred_txt = xkb_atom_text(info->keymap->ctx,
380 expr->value.action.name);
381 if (istreq(pred_txt, "noneof"))
382 *pred_rtrn = XkbSI_NoneOf;
383 else if (istreq(pred_txt, "anyofornone"))
384 *pred_rtrn = XkbSI_AnyOfOrNone;
385 else if (istreq(pred_txt, "anyof"))
386 *pred_rtrn = XkbSI_AnyOf;
387 else if (istreq(pred_txt, "allof"))
388 *pred_rtrn = XkbSI_AllOf;
389 else if (istreq(pred_txt, "exactly"))
390 *pred_rtrn = XkbSI_Exactly;
392 log_err(info->keymap->ctx,
393 "Illegal modifier predicate \"%s\"; Ignored\n", pred_txt);
396 expr = expr->value.action.args;
398 else if (expr->op == EXPR_IDENT) {
399 const char *pred_txt = xkb_atom_text(info->keymap->ctx,
401 if (pred_txt && istreq(pred_txt, "any")) {
402 *pred_rtrn = XkbSI_AnyOf;
408 return ExprResolveModMask(info->keymap->ctx, expr, mods_rtrn);
411 /***====================================================================***/
414 UseNewLEDField(unsigned field, LEDInfo *old, LEDInfo *new,
415 int verbosity, unsigned *collide)
417 if (!(old->defined & field))
420 if (new->defined & field) {
421 if ((old->file_id == new->file_id && verbosity > 0) || verbosity > 9)
424 if (new->merge != MERGE_AUGMENT)
432 AddIndicatorMap(CompatInfo *info, LEDInfo *new)
436 struct xkb_context *ctx = info->keymap->ctx;
437 int verbosity = xkb_get_log_verbosity(ctx);
439 list_foreach(old, &info->leds, entry) {
440 if (old->name == new->name) {
441 if ((old->real_mods == new->real_mods) &&
442 (old->vmods == new->vmods) &&
443 (old->groups == new->groups) &&
444 (old->ctrls == new->ctrls) &&
445 (old->which_mods == new->which_mods) &&
446 (old->which_groups == new->which_groups)) {
447 old->defined |= new->defined;
451 if (new->merge == MERGE_REPLACE) {
452 struct list entry = old->entry;
453 if ((old->file_id == new->file_id && verbosity > 0) ||
455 log_warn(info->keymap->ctx,
456 "Map for indicator %s redefined; "
457 "Earlier definition ignored\n",
458 xkb_atom_text(ctx, old->name));
465 if (UseNewLEDField(_LED_Index, old, new, verbosity,
467 old->indicator = new->indicator;
468 old->defined |= _LED_Index;
470 if (UseNewLEDField(_LED_Mods, old, new, verbosity,
472 old->which_mods = new->which_mods;
473 old->real_mods = new->real_mods;
474 old->vmods = new->vmods;
475 old->defined |= _LED_Mods;
477 if (UseNewLEDField(_LED_Groups, old, new, verbosity,
479 old->which_groups = new->which_groups;
480 old->groups = new->groups;
481 old->defined |= _LED_Groups;
483 if (UseNewLEDField(_LED_Ctrls, old, new, verbosity,
485 old->ctrls = new->ctrls;
486 old->defined |= _LED_Ctrls;
488 if (UseNewLEDField(_LED_Explicit, old, new, verbosity,
490 old->flags &= ~XkbIM_NoExplicit;
491 old->flags |= (new->flags & XkbIM_NoExplicit);
492 old->defined |= _LED_Explicit;
494 if (UseNewLEDField(_LED_Automatic, old, new, verbosity,
496 old->flags &= ~XkbIM_NoAutomatic;
497 old->flags |= (new->flags & XkbIM_NoAutomatic);
498 old->defined |= _LED_Automatic;
500 if (UseNewLEDField(_LED_DrivesKbd, old, new, verbosity,
502 old->flags &= ~XkbIM_LEDDrivesKB;
503 old->flags |= (new->flags & XkbIM_LEDDrivesKB);
504 old->defined |= _LED_DrivesKbd;
508 log_warn(info->keymap->ctx,
509 "Map for indicator %s redefined; "
510 "Using %s definition for duplicate fields\n",
511 xkb_atom_text(ctx, old->name),
512 (new->merge == MERGE_AUGMENT ? "first" : "last"));
520 old = malloc(sizeof(*old));
522 log_wsgo(info->keymap->ctx,
523 "Couldn't allocate indicator map; "
524 "Map for indicator %s not compiled\n",
525 xkb_atom_text(ctx, new->name));
530 list_append(&old->entry, &info->leds);
536 MergeIncludedCompatMaps(CompatInfo * into, CompatInfo * from,
537 enum merge_mode merge)
540 LEDInfo *led, *next_led;
541 GroupCompatInfo *gcm;
544 if (from->errorCount > 0) {
545 into->errorCount += from->errorCount;
548 if (into->name == NULL) {
549 into->name = from->name;
553 list_foreach(si, &from->interps, entry) {
554 if (merge != MERGE_DEFAULT)
556 if (!AddInterp(into, si))
560 for (i = 0, gcm = &from->groupCompat[0]; i < XkbNumKbdGroups;
562 if (merge != MERGE_DEFAULT)
564 if (!AddGroupCompat(into, i, gcm))
568 list_foreach_safe(led, next_led, &from->leds, entry) {
569 led->merge = (merge == MERGE_DEFAULT ? led->merge : merge);
570 if (!AddIndicatorMap(into, led))
576 HandleCompatMapFile(CompatInfo *info, XkbFile *file, enum merge_mode merge);
579 HandleIncludeCompatMap(CompatInfo *info, IncludeStmt *stmt)
581 enum merge_mode merge = MERGE_DEFAULT;
583 CompatInfo included, next_incl;
585 InitCompatInfo(&included, info->keymap, info->file_id);
588 included.name = stmt->stmt;
592 for (; stmt; stmt = stmt->next_incl) {
593 if (!ProcessIncludeFile(info->keymap->ctx, stmt, FILE_TYPE_COMPAT,
595 info->errorCount += 10;
596 ClearCompatInfo(&included);
600 InitCompatInfo(&next_incl, info->keymap, rtrn->id);
601 next_incl.file_id = rtrn->id;
602 next_incl.dflt = info->dflt;
603 next_incl.dflt.file_id = rtrn->id;
604 next_incl.dflt.merge = merge;
605 next_incl.ledDflt.file_id = rtrn->id;
606 next_incl.ledDflt.merge = merge;
607 next_incl.act = info->act;
609 HandleCompatMapFile(&next_incl, rtrn, MERGE_OVERRIDE);
611 MergeIncludedCompatMaps(&included, &next_incl, merge);
613 next_incl.act = NULL;
615 ClearCompatInfo(&next_incl);
619 MergeIncludedCompatMaps(info, &included, merge);
620 ClearCompatInfo(&included);
622 return (info->errorCount == 0);
625 static const LookupEntry useModMapValues[] = {
634 SetInterpField(CompatInfo *info, SymInterpInfo *si, const char *field,
635 ExprDef *arrayNdx, ExprDef *value)
637 struct xkb_keymap *keymap = info->keymap;
640 if (istreq(field, "action")) {
642 return ReportSINotArray(info, si, field);
644 if (!HandleActionDef(value, keymap, &si->interp.act.any, info->act))
647 si->defined |= _SI_Action;
649 else if (istreq(field, "virtualmodifier") ||
650 istreq(field, "virtualmod")) {
652 return ReportSINotArray(info, si, field);
654 if (!ResolveVirtualModifier(value, keymap, &tmp, &info->vmods))
655 return ReportSIBadType(info, si, field, "virtual modifier");
657 si->interp.virtual_mod = tmp.uval;
658 si->defined |= _SI_VirtualMod;
660 else if (istreq(field, "repeat")) {
664 return ReportSINotArray(info, si, field);
666 if (!ExprResolveBoolean(keymap->ctx, value, &set))
667 return ReportSIBadType(info, si, field, "boolean");
670 si->interp.flags |= XkbSI_AutoRepeat;
672 si->interp.flags &= ~XkbSI_AutoRepeat;
674 si->defined |= _SI_AutoRepeat;
676 else if (istreq(field, "locking")) {
680 return ReportSINotArray(info, si, field);
682 if (!ExprResolveBoolean(keymap->ctx, value, &set))
683 return ReportSIBadType(info, si, field, "boolean");
686 si->interp.flags |= XkbSI_LockingKey;
688 si->interp.flags &= ~XkbSI_LockingKey;
690 si->defined |= _SI_LockingKey;
692 else if (istreq(field, "usemodmap") ||
693 istreq(field, "usemodmapmods")) {
697 return ReportSINotArray(info, si, field);
699 if (!ExprResolveEnum(keymap->ctx, value, &val, useModMapValues))
700 return ReportSIBadType(info, si, field, "level specification");
703 si->interp.match |= XkbSI_LevelOneOnly;
705 si->interp.match &= ~XkbSI_LevelOneOnly;
707 si->defined |= _SI_LevelOneOnly;
710 return ReportBadField(keymap, "symbol interpretation", field,
717 static const LookupEntry modComponentNames[] = {
718 {"base", XkbIM_UseBase},
719 {"latched", XkbIM_UseLatched},
720 {"locked", XkbIM_UseLocked},
721 {"effective", XkbIM_UseEffective},
722 {"compat", XkbIM_UseCompat},
723 {"any", XkbIM_UseAnyMods},
727 static const LookupEntry groupComponentNames[] = {
728 {"base", XkbIM_UseBase},
729 {"latched", XkbIM_UseLatched},
730 {"locked", XkbIM_UseLocked},
731 {"effective", XkbIM_UseEffective},
732 {"any", XkbIM_UseAnyGroup},
737 static const LookupEntry groupNames[] = {
752 SetIndicatorMapField(CompatInfo *info, LEDInfo *led,
753 const char *field, ExprDef *arrayNdx, ExprDef *value)
757 struct xkb_keymap *keymap = info->keymap;
759 if (istreq(field, "modifiers") || istreq(field, "mods")) {
763 return ReportIndicatorNotArray(info, led, field);
765 if (!ExprResolveVModMask(keymap, value, &mask))
766 return ReportIndicatorBadType(info, led, field, "modifier mask");
768 led->real_mods = mask & 0xff;
769 led->vmods = (mask >> 8) & 0xff;
770 led->defined |= _LED_Mods;
772 else if (istreq(field, "groups")) {
776 return ReportIndicatorNotArray(info, led, field);
778 if (!ExprResolveMask(keymap->ctx, value, &mask, groupNames))
779 return ReportIndicatorBadType(info, led, field, "group mask");
782 led->defined |= _LED_Groups;
784 else if (istreq(field, "controls") || istreq(field, "ctrls")) {
788 return ReportIndicatorNotArray(info, led, field);
790 if (!ExprResolveMask(keymap->ctx, value, &mask, ctrlNames))
791 return ReportIndicatorBadType(info, led, field,
795 led->defined |= _LED_Ctrls;
797 else if (istreq(field, "allowexplicit")) {
801 return ReportIndicatorNotArray(info, led, field);
803 if (!ExprResolveBoolean(keymap->ctx, value, &set))
804 return ReportIndicatorBadType(info, led, field, "boolean");
807 led->flags &= ~XkbIM_NoExplicit;
809 led->flags |= XkbIM_NoExplicit;
811 led->defined |= _LED_Explicit;
813 else if (istreq(field, "whichmodstate") ||
814 istreq(field, "whichmodifierstate")) {
818 return ReportIndicatorNotArray(info, led, field);
820 if (!ExprResolveMask(keymap->ctx, value, &mask, modComponentNames))
821 return ReportIndicatorBadType(info, led, field,
822 "mask of modifier state components");
824 led->which_mods = mask;
826 else if (istreq(field, "whichgroupstate")) {
830 return ReportIndicatorNotArray(info, led, field);
832 if (!ExprResolveMask(keymap->ctx, value, &mask, groupComponentNames))
833 return ReportIndicatorBadType(info, led, field,
834 "mask of group state components");
836 led->which_groups = mask;
838 else if (istreq(field, "driveskbd") ||
839 istreq(field, "driveskeyboard") ||
840 istreq(field, "leddriveskbd") ||
841 istreq(field, "leddriveskeyboard") ||
842 istreq(field, "indicatordriveskbd") ||
843 istreq(field, "indicatordriveskeyboard")) {
847 return ReportIndicatorNotArray(info, led, field);
849 if (!ExprResolveBoolean(keymap->ctx, value, &set))
850 return ReportIndicatorBadType(info, led, field, "boolean");
853 led->flags |= XkbIM_LEDDrivesKB;
855 led->flags &= ~XkbIM_LEDDrivesKB;
857 led->defined |= _LED_DrivesKbd;
859 else if (istreq(field, "index")) {
863 return ReportIndicatorNotArray(info, led, field);
865 if (!ExprResolveInteger(keymap->ctx, value, &ndx))
866 return ReportIndicatorBadType(info, led, field,
869 if (ndx < 1 || ndx > 32) {
870 log_err(info->keymap->ctx,
871 "Illegal indicator index %d (range 1..%d); "
872 "Index definition for %s indicator ignored\n",
873 rtrn.uval, XkbNumIndicators,
874 xkb_atom_text(keymap->ctx, led->name));
878 led->indicator = (unsigned char) ndx;
879 led->defined |= _LED_Index;
882 log_err(info->keymap->ctx,
883 "Unknown field %s in map for %s indicator; "
884 "Definition ignored\n",
885 field, xkb_atom_text(keymap->ctx, led->name));
893 HandleInterpVar(CompatInfo *info, VarDef *stmt)
895 const char *elem, *field;
899 if (!ExprResolveLhs(info->keymap->ctx, stmt->name, &elem, &field, &ndx))
900 ret = 0; /* internal error, already reported */
901 else if (elem && istreq(elem, "interpret"))
902 ret = SetInterpField(info, &info->dflt, field, ndx, stmt->value);
903 else if (elem && istreq(elem, "indicator"))
904 ret = SetIndicatorMapField(info, &info->ledDflt, field, ndx,
907 ret = SetActionField(info->keymap, elem, field, ndx, stmt->value,
913 HandleInterpBody(CompatInfo *info, VarDef *def, SymInterpInfo *si)
916 const char *elem, *field;
919 for (; def != NULL; def = (VarDef *) def->common.next) {
920 if (def->name && def->name->op == EXPR_FIELD_REF) {
921 ok = HandleInterpVar(info, def);
924 ok = ExprResolveLhs(info->keymap->ctx, def->name, &elem, &field,
927 ok = SetInterpField(info, si, field, arrayNdx, def->value);
934 HandleInterpDef(CompatInfo *info, InterpDef *def, enum merge_mode merge)
939 if (!ResolveStateAndPredicate(def->match, &pred, &mods, info)) {
940 log_err(info->keymap->ctx,
941 "Couldn't determine matching modifiers; "
942 "Symbol interpretation ignored\n");
945 if (def->merge != MERGE_DEFAULT)
950 if (!LookupKeysym(def->sym, &si.interp.sym)) {
951 log_err(info->keymap->ctx,
952 "Could not resolve keysym %s; "
953 "Symbol interpretation ignored\n",
957 si.interp.match = pred & XkbSI_OpMask;
958 si.interp.mods = mods;
959 if (!HandleInterpBody(info, def->def, &si)) {
964 if (!AddInterp(info, &si)) {
972 HandleGroupCompatDef(CompatInfo *info, GroupCompatDef *def,
973 enum merge_mode merge)
978 merge = (def->merge == MERGE_DEFAULT ? merge : def->merge);
980 if (def->group < 1 || def->group > XkbNumKbdGroups) {
981 log_err(info->keymap->ctx,
982 "Keyboard group must be in the range 1..%u; "
983 "Compatibility map for illegal group %u ignored\n",
984 XkbNumKbdGroups, def->group);
988 tmp.file_id = info->file_id;
991 if (!ExprResolveVModMask(info->keymap, def->def, &mask)) {
992 log_err(info->keymap->ctx,
993 "Expected a modifier mask in group compatibility definition; "
994 "Ignoring illegal compatibility map for group %u\n",
999 tmp.real_mods = mask & 0xff;
1000 tmp.vmods = (mask >> 8) & 0xffff;
1002 return AddGroupCompat(info, def->group - 1, &tmp);
1006 HandleIndicatorMapDef(CompatInfo *info, IndicatorMapDef *def,
1007 enum merge_mode merge)
1013 if (def->merge != MERGE_DEFAULT)
1016 led = info->ledDflt;
1018 led.name = def->name;
1021 for (var = def->body; var != NULL; var = (VarDef *) var->common.next) {
1022 const char *elem, *field;
1024 if (!ExprResolveLhs(info->keymap->ctx, var->name, &elem, &field,
1031 log_err(info->keymap->ctx,
1032 "Cannot set defaults for \"%s\" element in indicator map; "
1033 "Assignment to %s.%s ignored\n", elem, elem, field);
1037 ok = SetIndicatorMapField(info, &led, field, arrayNdx,
1043 return AddIndicatorMap(info, &led);
1049 HandleCompatMapFile(CompatInfo *info, XkbFile *file, enum merge_mode merge)
1053 if (merge == MERGE_DEFAULT)
1054 merge = MERGE_AUGMENT;
1056 info->name = strdup_safe(file->name);
1060 switch (stmt->type) {
1062 if (!HandleIncludeCompatMap(info, (IncludeStmt *) stmt))
1066 if (!HandleInterpDef(info, (InterpDef *) stmt, merge))
1069 case STMT_GROUP_COMPAT:
1070 if (!HandleGroupCompatDef(info, (GroupCompatDef *) stmt, merge))
1073 case STMT_INDICATOR_MAP:
1074 if (!HandleIndicatorMapDef(info, (IndicatorMapDef *) stmt, merge))
1078 if (!HandleInterpVar(info, (VarDef *) stmt))
1082 if (!HandleVModDef((VModDef *) stmt, info->keymap, merge,
1087 log_err(info->keymap->ctx,
1088 "Interpretation files may not include other types; "
1089 "Ignoring definition of key name\n");
1093 log_wsgo(info->keymap->ctx,
1094 "Unexpected statement type %d in HandleCompatMapFile\n",
1099 if (info->errorCount > 10) {
1100 log_err(info->keymap->ctx,
1101 "Abandoning compatibility map \"%s\"\n", file->topName);
1108 CopyInterps(CompatInfo *info, bool needSymbol, unsigned pred)
1112 list_foreach(si, &info->interps, entry) {
1113 if (((si->interp.match & XkbSI_OpMask) != pred) ||
1114 (needSymbol && si->interp.sym == XKB_KEY_NoSymbol) ||
1115 (!needSymbol && si->interp.sym != XKB_KEY_NoSymbol))
1118 darray_append(info->keymap->sym_interpret, si->interp);
1123 BindIndicators(CompatInfo *info, struct list *unbound_leds)
1126 LEDInfo *led, *next_led;
1127 struct xkb_indicator_map *map;
1128 struct xkb_keymap *keymap = info->keymap;
1130 list_foreach(led, unbound_leds, entry) {
1131 if (led->indicator == _LED_NotBound) {
1132 for (i = 0; i < XkbNumIndicators; i++) {
1133 if (keymap->indicator_names[i] &&
1134 streq(keymap->indicator_names[i],
1135 xkb_atom_text(keymap->ctx, led->name))) {
1136 led->indicator = i + 1;
1143 list_foreach(led, unbound_leds, entry) {
1144 if (led->indicator == _LED_NotBound) {
1145 for (i = 0; i < XkbNumIndicators; i++) {
1146 if (keymap->indicator_names[i] == NULL) {
1147 keymap->indicator_names[i] =
1148 xkb_atom_text(keymap->ctx, led->name);
1149 led->indicator = i + 1;
1154 if (led->indicator == _LED_NotBound) {
1155 log_err(info->keymap->ctx,
1156 "No unnamed indicators found; "
1157 "Virtual indicator map \"%s\" not bound\n",
1158 xkb_atom_text(keymap->ctx, led->name));
1164 list_foreach_safe(led, next_led, unbound_leds, entry) {
1165 if (led->indicator == _LED_NotBound) {
1170 if (!streq(keymap->indicator_names[led->indicator - 1],
1171 xkb_atom_text(keymap->ctx, led->name))) {
1172 const char *old = keymap->indicator_names[led->indicator - 1];
1173 log_err(info->keymap->ctx,
1174 "Multiple names bound to indicator %d; "
1175 "Using %s, ignoring %s\n",
1176 led->indicator, old,
1177 xkb_atom_text(keymap->ctx, led->name));
1182 map = &keymap->indicators[led->indicator - 1];
1183 map->flags = led->flags;
1184 map->which_groups = led->which_groups;
1185 map->groups = led->groups;
1186 map->which_mods = led->which_mods;
1187 map->mods.mask = led->real_mods;
1188 map->mods.real_mods = led->real_mods;
1189 map->mods.vmods = led->vmods;
1190 map->ctrls = led->ctrls;
1194 list_init(unbound_leds);
1198 CopyIndicatorMapDefs(CompatInfo *info)
1200 LEDInfo *led, *next_led;
1201 struct list unbound_leds;
1202 struct xkb_indicator_map *im;
1203 struct xkb_keymap *keymap = info->keymap;
1205 list_init(&unbound_leds);
1207 list_foreach_safe(led, next_led, &info->leds, entry) {
1208 if (led->groups != 0 && led->which_groups == 0)
1209 led->which_groups = XkbIM_UseEffective;
1211 if (led->which_mods == 0 && (led->real_mods || led->vmods))
1212 led->which_mods = XkbIM_UseEffective;
1214 if (led->indicator == _LED_NotBound) {
1215 list_append(&led->entry, &unbound_leds);
1219 im = &keymap->indicators[led->indicator - 1];
1220 im->flags = led->flags;
1221 im->which_groups = led->which_groups;
1222 im->groups = led->groups;
1223 im->which_mods = led->which_mods;
1224 im->mods.mask = led->real_mods;
1225 im->mods.real_mods = led->real_mods;
1226 im->mods.vmods = led->vmods;
1227 im->ctrls = led->ctrls;
1228 keymap->indicator_names[led->indicator - 1] =
1229 xkb_atom_text(keymap->ctx, led->name);
1232 list_init(&info->leds);
1234 BindIndicators(info, &unbound_leds);
1240 CompileCompatMap(XkbFile *file, struct xkb_keymap *keymap,
1241 enum merge_mode merge)
1243 xkb_group_index_t i;
1245 GroupCompatInfo *gcm;
1247 InitCompatInfo(&info, keymap, file->id);
1248 info.dflt.merge = merge;
1249 info.ledDflt.merge = merge;
1251 HandleCompatMapFile(&info, file, merge);
1253 if (info.errorCount != 0)
1256 darray_init(keymap->sym_interpret);
1257 darray_growalloc(keymap->sym_interpret, info.nInterps);
1260 keymap->compat_section_name = strdup(info.name);
1262 if (info.nInterps > 0) {
1263 CopyInterps(&info, true, XkbSI_Exactly);
1264 CopyInterps(&info, true, XkbSI_AllOf | XkbSI_NoneOf);
1265 CopyInterps(&info, true, XkbSI_AnyOf);
1266 CopyInterps(&info, true, XkbSI_AnyOfOrNone);
1267 CopyInterps(&info, false, XkbSI_Exactly);
1268 CopyInterps(&info, false, XkbSI_AllOf | XkbSI_NoneOf);
1269 CopyInterps(&info, false, XkbSI_AnyOf);
1270 CopyInterps(&info, false, XkbSI_AnyOfOrNone);
1273 for (i = 0, gcm = &info.groupCompat[0]; i < XkbNumKbdGroups;
1275 if (gcm->file_id != 0 || gcm->real_mods != 0 || gcm->vmods != 0) {
1276 keymap->groups[i].mask = gcm->real_mods;
1277 keymap->groups[i].real_mods = gcm->real_mods;
1278 keymap->groups[i].vmods = gcm->vmods;
1282 if (!CopyIndicatorMapDefs(&info))
1285 ClearCompatInfo(&info);
1289 ClearCompatInfo(&info);
1294 VModsToReal(struct xkb_keymap *keymap, xkb_mod_mask_t vmodmask)
1296 xkb_mod_mask_t ret = 0;
1302 for (i = 0; i < XkbNumVirtualMods; i++) {
1303 if (!(vmodmask & (1 << i)))
1305 ret |= keymap->vmods[i];
1312 UpdateActionMods(struct xkb_keymap *keymap, union xkb_action *act,
1313 xkb_mod_mask_t rmodmask)
1315 switch (act->type) {
1317 case XkbSA_LatchMods:
1318 case XkbSA_LockMods:
1319 if (act->mods.flags & XkbSA_UseModMapMods)
1320 act->mods.real_mods = rmodmask;
1321 act->mods.mask = act->mods.real_mods;
1322 act->mods.mask |= VModsToReal(keymap, act->mods.vmods);
1326 if (act->iso.flags & XkbSA_UseModMapMods)
1327 act->iso.real_mods = rmodmask;
1328 act->iso.mask = act->iso.real_mods;
1329 act->iso.mask |= VModsToReal(keymap, act->iso.vmods);
1338 * Find an interpretation which applies to this particular level, either by
1339 * finding an exact match for the symbol and modifier combination, or a
1340 * generic XKB_KEY_NoSymbol match.
1342 static struct xkb_sym_interpret *
1343 FindInterpForKey(struct xkb_keymap *keymap, struct xkb_key *key,
1344 xkb_group_index_t group, uint32_t level)
1346 struct xkb_sym_interpret *ret = NULL;
1347 struct xkb_sym_interpret *interp;
1348 const xkb_keysym_t *syms;
1351 num_syms = xkb_key_get_syms_by_level(keymap, key, group, level, &syms);
1355 darray_foreach(interp, keymap->sym_interpret) {
1359 if ((num_syms > 1 || interp->sym != syms[0]) &&
1360 interp->sym != XKB_KEY_NoSymbol)
1363 if (level == 0 || !(interp->match & XkbSI_LevelOneOnly))
1368 switch (interp->match & XkbSI_OpMask) {
1370 found = !(interp->mods & mods);
1372 case XkbSI_AnyOfOrNone:
1373 found = (!mods || (interp->mods & mods));
1376 found = !!(interp->mods & mods);
1379 found = ((interp->mods & mods) == interp->mods);
1382 found = (interp->mods == mods);
1389 if (found && interp->sym != XKB_KEY_NoSymbol)
1391 else if (found && !ret)
1401 ApplyInterpsToKey(struct xkb_keymap *keymap, struct xkb_key *key)
1403 #define INTERP_SIZE (8 * 4)
1404 struct xkb_sym_interpret *interps[INTERP_SIZE];
1405 union xkb_action *acts;
1406 xkb_mod_mask_t vmodmask = 0;
1408 xkb_group_index_t group;
1412 /* If we've been told not to bind interps to this key, then don't. */
1413 if (key->explicit & XkbExplicitInterpretMask)
1416 for (i = 0; i < INTERP_SIZE; i++)
1419 for (group = 0; group < key->num_groups; group++) {
1420 for (level = 0; level < XkbKeyGroupWidth(keymap, key, group);
1422 i = (group * key->width) + level;
1423 if (i >= INTERP_SIZE) /* XXX FIXME */
1425 interps[i] = FindInterpForKey(keymap, key, group, level);
1432 num_acts = key->num_groups * key->width;
1433 acts = ResizeKeyActions(keymap, key, num_acts);
1434 if (num_acts && !acts)
1437 for (group = 0; group < key->num_groups; group++) {
1438 for (level = 0; level < XkbKeyGroupWidth(keymap, key, group);
1440 struct xkb_sym_interpret *interp;
1442 i = (group * key->width) + level;
1443 interp = interps[i];
1445 /* Infer default key behaviours from the base level. */
1446 if (group == 0 && level == 0) {
1447 if (!(key->explicit & XkbExplicitAutoRepeatMask) &&
1448 (!interp || (interp->flags & XkbSI_AutoRepeat)))
1449 key->repeats = true;
1450 if (!(key->explicit & XkbExplicitBehaviorMask) &&
1451 interp && (interp->flags & XkbSI_LockingKey))
1452 key->behavior.type = XkbKB_Lock;
1458 if ((group == 0 && level == 0) ||
1459 !(interp->match & XkbSI_LevelOneOnly)) {
1460 if (interp->virtual_mod != XkbNoModifier)
1461 vmodmask |= (1 << interp->virtual_mod);
1463 acts[i] = interp->act;
1467 if (!(key->explicit & XkbExplicitVModMapMask))
1468 key->vmodmap = vmodmask;
1475 * This collects a bunch of disparate functions which was done in the server
1476 * at various points that really should've been done within xkbcomp. Turns out
1477 * your actions and types are a lot more useful when any of your modifiers
1478 * other than Shift actually do something ...
1481 UpdateModifiersFromCompat(struct xkb_keymap *keymap)
1483 xkb_mod_index_t vmod;
1484 xkb_group_index_t grp;
1485 xkb_led_index_t led;
1487 struct xkb_key *key;
1488 struct xkb_key_type *type;
1489 struct xkb_kt_map_entry *entry;
1491 /* Find all the interprets for the key and bind them to actions,
1492 * which will also update the vmodmap. */
1493 xkb_foreach_key(key, keymap)
1494 if (!ApplyInterpsToKey(keymap, key))
1497 /* Update keymap->vmods, the virtual -> real mod mapping. */
1498 for (vmod = 0; vmod < XkbNumVirtualMods; vmod++)
1499 keymap->vmods[vmod] = 0;
1501 xkb_foreach_key(key, keymap) {
1505 for (vmod = 0; vmod < XkbNumVirtualMods; vmod++) {
1506 if (!(key->vmodmap & (1 << vmod)))
1508 keymap->vmods[vmod] |= key->modmap;
1512 /* Now update the level masks for all the types to reflect the vmods. */
1513 darray_foreach(type, keymap->types) {
1514 xkb_mod_mask_t mask = 0;
1515 type->mods.mask = type->mods.real_mods;
1516 type->mods.mask |= VModsToReal(keymap, type->mods.vmods);
1518 /* FIXME: We compute the mask with doing anything with it? */
1519 for (vmod = 0; vmod < XkbNumVirtualMods; vmod++) {
1520 if (!(type->mods.vmods & (1 << vmod)))
1522 mask |= keymap->vmods[vmod];
1525 darray_foreach(entry, type->map)
1526 entry->mods.mask = entry->mods.real_mods |
1527 VModsToReal(keymap, entry->mods.vmods);
1530 /* Update action modifiers. */
1531 xkb_foreach_key(key, keymap) {
1532 union xkb_action *acts = XkbKeyActionsPtr(keymap, key);
1533 for (i = 0; i < XkbKeyNumActions(key); i++) {
1534 if (acts[i].any.type == XkbSA_NoAction)
1536 UpdateActionMods(keymap, &acts[i], key->modmap);
1540 /* Update group modifiers. */
1541 for (grp = 0; grp < XkbNumKbdGroups; grp++) {
1542 struct xkb_mods *group = &keymap->groups[grp];
1543 group->mask = group->real_mods | VModsToReal(keymap, group->vmods);
1546 /* Update vmod -> indicator maps. */
1547 for (led = 0; led < XkbNumIndicators; led++) {
1548 struct xkb_mods *mods = &keymap->indicators[led].mods;
1549 mods->mask = mods->real_mods | VModsToReal(keymap, mods->vmods);