action: convert action field type to enum
[platform/upstream/libxkbcommon.git] / src / xkbcomp / compat.c
1 /************************************************************
2  * Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
3  *
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.
15  *
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.
24  *
25  ********************************************************/
26
27 #include "xkbcomp-priv.h"
28 #include "text.h"
29 #include "expr.h"
30 #include "action.h"
31 #include "vmod.h"
32 #include "include.h"
33
34 enum si_field {
35     SI_FIELD_VIRTUAL_MOD    = (1 << 0),
36     SI_FIELD_ACTION         = (1 << 1),
37     SI_FIELD_AUTO_REPEAT    = (1 << 2),
38     SI_FIELD_LOCKING_KEY    = (1 << 3),
39     SI_FIELD_LEVEL_ONE_ONLY = (1 << 4),
40 };
41
42 typedef struct _SymInterpInfo {
43     enum si_field defined;
44     unsigned file_id;
45     enum merge_mode merge;
46     struct list entry;
47
48     struct xkb_sym_interpret interp;
49 } SymInterpInfo;
50
51 enum led_field {
52     LED_FIELD_INDEX      = (1 << 0),
53     LED_FIELD_MODS       = (1 << 1),
54     LED_FIELD_GROUPS     = (1 << 2),
55     LED_FIELD_CTRLS      = (1 << 3),
56     LED_FIELD_EXPLICIT   = (1 << 4),
57     LED_FIELD_AUTOMATIC  = (1 << 5),
58     LED_FIELD_DRIVES_KBD = (1 << 6),
59 };
60
61 typedef struct _LEDInfo {
62     enum led_field defined;
63     unsigned file_id;
64     enum merge_mode merge;
65     struct list entry;
66
67     xkb_atom_t name;
68     xkb_led_index_t indicator;
69     unsigned char flags;
70     unsigned char which_mods;
71     xkb_mod_mask_t mods;
72     unsigned char which_groups;
73     uint32_t groups;
74     unsigned int ctrls;
75 } LEDInfo;
76
77 typedef struct _GroupCompatInfo {
78     unsigned file_id;
79     enum merge_mode merge;
80     bool defined;
81     xkb_mod_mask_t mods;
82 } GroupCompatInfo;
83
84 typedef struct _CompatInfo {
85     char *name;
86     unsigned file_id;
87     int errorCount;
88     int nInterps;
89     struct list interps;
90     SymInterpInfo dflt;
91     LEDInfo ledDflt;
92     GroupCompatInfo groupCompat[XkbNumKbdGroups];
93     struct list leds;
94     VModInfo vmods;
95     ActionInfo *act;
96     struct xkb_keymap *keymap;
97 } CompatInfo;
98
99 static const char *
100 siText(SymInterpInfo * si, CompatInfo * info)
101 {
102     static char buf[128];
103
104     if (si == &info->dflt) {
105         snprintf(buf, sizeof(buf), "default");
106     }
107     else {
108         snprintf(buf, sizeof(buf), "%s+%s(%s)",
109                  KeysymText(si->interp.sym),
110                  SIMatchText(si->interp.match),
111                  ModMaskText(si->interp.mods));
112     }
113     return buf;
114 }
115
116 static inline bool
117 ReportSINotArray(CompatInfo *info, SymInterpInfo *si, const char *field)
118 {
119     return ReportNotArray(info->keymap, "symbol interpretation", field,
120                           siText(si, info));
121 }
122
123 static inline bool
124 ReportSIBadType(CompatInfo *info, SymInterpInfo *si, const char *field,
125                 const char *wanted)
126 {
127     return ReportBadType(info->keymap->ctx, "symbol interpretation", field,
128                          siText(si, info), wanted);
129 }
130
131 static inline bool
132 ReportIndicatorBadType(CompatInfo *info, LEDInfo *led,
133                        const char *field, const char *wanted)
134 {
135     return ReportBadType(info->keymap->ctx, "indicator map", field,
136                          xkb_atom_text(info->keymap->ctx, led->name),
137                          wanted);
138 }
139
140 static inline bool
141 ReportIndicatorNotArray(CompatInfo *info, LEDInfo *led,
142                         const char *field)
143 {
144     return ReportNotArray(info->keymap, "indicator map", field,
145                           xkb_atom_text(info->keymap->ctx, led->name));
146 }
147
148 static void
149 ClearIndicatorMapInfo(struct xkb_context *ctx, LEDInfo * info)
150 {
151     info->name = xkb_atom_intern(ctx, "default");
152     info->indicator = XKB_LED_INVALID;
153     info->flags = 0;
154     info->which_mods = 0;
155     info->mods = 0;
156     info->which_groups = info->groups = 0;
157     info->ctrls = 0;
158 }
159
160 static void
161 InitCompatInfo(CompatInfo *info, struct xkb_keymap *keymap, unsigned file_id)
162 {
163     info->keymap = keymap;
164     info->name = NULL;
165     info->file_id = file_id;
166     info->errorCount = 0;
167     info->nInterps = 0;
168     list_init(&info->interps);
169     info->act = NULL;
170     info->dflt.file_id = file_id;
171     info->dflt.defined = 0;
172     info->dflt.merge = MERGE_OVERRIDE;
173     info->dflt.interp.flags = 0;
174     info->dflt.interp.virtual_mod = XkbNoModifier;
175     memset(&info->dflt.interp.act, 0, sizeof(info->dflt.interp.act));
176     info->dflt.interp.act.type = XkbSA_NoAction;
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);
185 }
186
187 static void
188 ClearCompatInfo(CompatInfo *info)
189 {
190     SymInterpInfo *si, *next_si;
191     LEDInfo *led, *next_led;
192     struct xkb_keymap *keymap = info->keymap;
193
194     free(info->name);
195     info->name = NULL;
196     info->dflt.defined = 0;
197     info->dflt.merge = MERGE_AUGMENT;
198     info->dflt.interp.flags = 0;
199     info->dflt.interp.virtual_mod = XkbNoModifier;
200     memset(&info->dflt.interp.act, 0, sizeof(info->dflt.interp.act));
201     info->dflt.interp.act.type = XkbSA_NoAction;
202     ClearIndicatorMapInfo(keymap->ctx, &info->ledDflt);
203     info->nInterps = 0;
204     list_foreach_safe(si, next_si, &info->interps, entry)
205         free(si);
206     memset(&info->groupCompat[0], 0,
207            XkbNumKbdGroups * sizeof(GroupCompatInfo));
208     list_foreach_safe(led, next_led, &info->leds, entry)
209         free(led);
210     FreeActionInfo(info->act);
211     info->act = NULL;
212     info->keymap = NULL;
213     ClearVModInfo(&info->vmods, keymap);
214 }
215
216 static SymInterpInfo *
217 NextInterp(CompatInfo * info)
218 {
219     SymInterpInfo *si;
220
221     si = calloc(1, sizeof(*si));
222     if (!si)
223         return NULL;
224
225     list_append(&si->entry, &info->interps);
226     info->nInterps++;
227
228     return si;
229 }
230
231 static SymInterpInfo *
232 FindMatchingInterp(CompatInfo * info, SymInterpInfo * new)
233 {
234     SymInterpInfo *old;
235
236     list_foreach(old, &info->interps, entry)
237         if (old->interp.sym == new->interp.sym &&
238             old->interp.mods == new->interp.mods &&
239             old->interp.match == new->interp.match)
240             return old;
241
242     return NULL;
243 }
244
245 static bool
246 UseNewInterpField(enum si_field field, SymInterpInfo *old, SymInterpInfo *new,
247                   int verbosity, enum si_field *collide)
248 {
249     if (!(old->defined & field))
250         return true;
251
252     if (new->defined & field) {
253         if ((old->file_id == new->file_id && verbosity > 0) || verbosity > 9)
254             *collide |= field;
255
256         if (new->merge != MERGE_AUGMENT)
257             return true;
258     }
259
260     return false;
261 }
262
263 static bool
264 AddInterp(CompatInfo * info, SymInterpInfo * new)
265 {
266     enum si_field collide;
267     SymInterpInfo *old;
268     struct list entry;
269     int verbosity = xkb_get_log_verbosity(info->keymap->ctx);
270
271     collide = 0;
272     old = FindMatchingInterp(info, new);
273     if (old != NULL) {
274         if (new->merge == MERGE_REPLACE) {
275             entry = old->entry;
276             if ((old->file_id == new->file_id && verbosity > 0) ||
277                 verbosity > 9)
278                 log_warn(info->keymap->ctx,
279                          "Multiple definitions for \"%s\"; "
280                          "Earlier interpretation ignored\n",
281                          siText(new, info));
282             *old = *new;
283             old->entry = entry;
284             return true;
285         }
286
287         if (UseNewInterpField(SI_FIELD_VIRTUAL_MOD, old, new, verbosity,
288                               &collide)) {
289             old->interp.virtual_mod = new->interp.virtual_mod;
290             old->defined |= SI_FIELD_VIRTUAL_MOD;
291         }
292         if (UseNewInterpField(SI_FIELD_ACTION, old, new, verbosity,
293                               &collide)) {
294             old->interp.act = new->interp.act;
295             old->defined |= SI_FIELD_ACTION;
296         }
297         if (UseNewInterpField(SI_FIELD_AUTO_REPEAT, old, new, verbosity,
298                               &collide)) {
299             old->interp.flags &= ~XkbSI_AutoRepeat;
300             old->interp.flags |= (new->interp.flags & XkbSI_AutoRepeat);
301             old->defined |= SI_FIELD_AUTO_REPEAT;
302         }
303         if (UseNewInterpField(SI_FIELD_LOCKING_KEY, old, new, verbosity,
304                               &collide)) {
305             old->interp.flags &= ~XkbSI_LockingKey;
306             old->interp.flags |= (new->interp.flags & XkbSI_LockingKey);
307             old->defined |= SI_FIELD_LOCKING_KEY;
308         }
309         if (UseNewInterpField(SI_FIELD_LEVEL_ONE_ONLY, old, new, verbosity,
310                               &collide)) {
311             old->interp.match &= ~XkbSI_LevelOneOnly;
312             old->interp.match |= (new->interp.match & XkbSI_LevelOneOnly);
313             old->defined |= SI_FIELD_LEVEL_ONE_ONLY;
314         }
315
316         if (collide) {
317             log_warn(info->keymap->ctx,
318                      "Multiple interpretations of \"%s\"; "
319                      "Using %s definition for duplicate fields\n",
320                      siText(new, info),
321                      (new->merge != MERGE_AUGMENT ? "last" : "first"));
322         }
323
324         return true;
325     }
326
327     old = new;
328     if ((new = NextInterp(info)) == NULL)
329         return false;
330     entry = new->entry;
331     *new = *old;
332     new->entry = entry;
333     return true;
334 }
335
336 static bool
337 AddGroupCompat(CompatInfo *info, xkb_group_index_t group, GroupCompatInfo *new)
338 {
339     GroupCompatInfo *gc;
340     int verbosity = xkb_get_log_verbosity(info->keymap->ctx);
341
342     gc = &info->groupCompat[group];
343     if (gc->mods == new->mods)
344         return true;
345
346     if ((gc->file_id == new->file_id && verbosity > 0) || verbosity > 9)
347         log_warn(info->keymap->ctx,
348                  "Compat map for group %u redefined; "
349                  "Using %s definition\n",
350                  group + 1, (new->merge == MERGE_AUGMENT ? "old" : "new"));
351
352     if (new->defined && (new->merge != MERGE_AUGMENT || !gc->defined))
353         *gc = *new;
354
355     return true;
356 }
357
358 /***====================================================================***/
359
360 static bool
361 ResolveStateAndPredicate(ExprDef * expr,
362                          unsigned *pred_rtrn,
363                          xkb_mod_mask_t *mods_rtrn, CompatInfo * info)
364 {
365     if (expr == NULL) {
366         *pred_rtrn = XkbSI_AnyOfOrNone;
367         *mods_rtrn = ~0;
368         return true;
369     }
370
371     *pred_rtrn = XkbSI_Exactly;
372     if (expr->op == EXPR_ACTION_DECL) {
373         const char *pred_txt = xkb_atom_text(info->keymap->ctx,
374                                              expr->value.action.name);
375         if (istreq(pred_txt, "noneof"))
376             *pred_rtrn = XkbSI_NoneOf;
377         else if (istreq(pred_txt, "anyofornone"))
378             *pred_rtrn = XkbSI_AnyOfOrNone;
379         else if (istreq(pred_txt, "anyof"))
380             *pred_rtrn = XkbSI_AnyOf;
381         else if (istreq(pred_txt, "allof"))
382             *pred_rtrn = XkbSI_AllOf;
383         else if (istreq(pred_txt, "exactly"))
384             *pred_rtrn = XkbSI_Exactly;
385         else {
386             log_err(info->keymap->ctx,
387                     "Illegal modifier predicate \"%s\"; Ignored\n", pred_txt);
388             return false;
389         }
390         expr = expr->value.action.args;
391     }
392     else if (expr->op == EXPR_IDENT) {
393         const char *pred_txt = xkb_atom_text(info->keymap->ctx,
394                                              expr->value.str);
395         if (pred_txt && istreq(pred_txt, "any")) {
396             *pred_rtrn = XkbSI_AnyOf;
397             *mods_rtrn = 0xff;
398             return true;
399         }
400     }
401
402     return ExprResolveModMask(info->keymap->ctx, expr, mods_rtrn);
403 }
404
405 /***====================================================================***/
406
407 static bool
408 UseNewLEDField(enum led_field field, LEDInfo *old, LEDInfo *new,
409                int verbosity, enum led_field *collide)
410 {
411     if (!(old->defined & field))
412         return true;
413
414     if (new->defined & field) {
415         if ((old->file_id == new->file_id && verbosity > 0) || verbosity > 9)
416             *collide |= field;
417
418         if (new->merge != MERGE_AUGMENT)
419             return true;
420     }
421
422     return false;
423 }
424
425 static bool
426 AddIndicatorMap(CompatInfo *info, LEDInfo *new)
427 {
428     LEDInfo *old;
429     enum led_field collide;
430     struct xkb_context *ctx = info->keymap->ctx;
431     int verbosity = xkb_get_log_verbosity(ctx);
432
433     list_foreach(old, &info->leds, entry) {
434         if (old->name == new->name) {
435             if ((old->mods == new->mods) &&
436                 (old->groups == new->groups) &&
437                 (old->ctrls == new->ctrls) &&
438                 (old->which_mods == new->which_mods) &&
439                 (old->which_groups == new->which_groups)) {
440                 old->defined |= new->defined;
441                 return true;
442             }
443
444             if (new->merge == MERGE_REPLACE) {
445                 struct list entry = old->entry;
446                 if ((old->file_id == new->file_id && verbosity > 0) ||
447                     verbosity > 9)
448                     log_warn(info->keymap->ctx,
449                              "Map for indicator %s redefined; "
450                              "Earlier definition ignored\n",
451                              xkb_atom_text(ctx, old->name));
452                 *old = *new;
453                 old->entry = entry;
454                 return true;
455             }
456
457             collide = 0;
458             if (UseNewLEDField(LED_FIELD_INDEX, old, new, verbosity,
459                                &collide)) {
460                 old->indicator = new->indicator;
461                 old->defined |= LED_FIELD_INDEX;
462             }
463             if (UseNewLEDField(LED_FIELD_MODS, old, new, verbosity,
464                                &collide)) {
465                 old->which_mods = new->which_mods;
466                 old->mods = new->mods;
467                 old->defined |= LED_FIELD_MODS;
468             }
469             if (UseNewLEDField(LED_FIELD_GROUPS, old, new, verbosity,
470                                &collide)) {
471                 old->which_groups = new->which_groups;
472                 old->groups = new->groups;
473                 old->defined |= LED_FIELD_GROUPS;
474             }
475             if (UseNewLEDField(LED_FIELD_CTRLS, old, new, verbosity,
476                                &collide)) {
477                 old->ctrls = new->ctrls;
478                 old->defined |= LED_FIELD_CTRLS;
479             }
480             if (UseNewLEDField(LED_FIELD_EXPLICIT, old, new, verbosity,
481                                &collide)) {
482                 old->flags &= ~XkbIM_NoExplicit;
483                 old->flags |= (new->flags & XkbIM_NoExplicit);
484                 old->defined |= LED_FIELD_EXPLICIT;
485             }
486             if (UseNewLEDField(LED_FIELD_AUTOMATIC, old, new, verbosity,
487                                &collide)) {
488                 old->flags &= ~XkbIM_NoAutomatic;
489                 old->flags |= (new->flags & XkbIM_NoAutomatic);
490                 old->defined |= LED_FIELD_AUTOMATIC;
491             }
492             if (UseNewLEDField(LED_FIELD_DRIVES_KBD, old, new, verbosity,
493                                &collide)) {
494                 old->flags &= ~XkbIM_LEDDrivesKB;
495                 old->flags |= (new->flags & XkbIM_LEDDrivesKB);
496                 old->defined |= LED_FIELD_DRIVES_KBD;
497             }
498
499             if (collide) {
500                 log_warn(info->keymap->ctx,
501                          "Map for indicator %s redefined; "
502                          "Using %s definition for duplicate fields\n",
503                          xkb_atom_text(ctx, old->name),
504                          (new->merge == MERGE_AUGMENT ? "first" : "last"));
505             }
506
507             return true;
508         }
509     }
510
511     /* new definition */
512     old = malloc(sizeof(*old));
513     if (!old) {
514         log_wsgo(info->keymap->ctx,
515                  "Couldn't allocate indicator map; "
516                  "Map for indicator %s not compiled\n",
517                  xkb_atom_text(ctx, new->name));
518         return false;
519     }
520
521     *old = *new;
522     list_append(&old->entry, &info->leds);
523
524     return true;
525 }
526
527 static void
528 MergeIncludedCompatMaps(CompatInfo * into, CompatInfo * from,
529                         enum merge_mode merge)
530 {
531     SymInterpInfo *si;
532     LEDInfo *led, *next_led;
533     GroupCompatInfo *gcm;
534     xkb_group_index_t i;
535
536     if (from->errorCount > 0) {
537         into->errorCount += from->errorCount;
538         return;
539     }
540     if (into->name == NULL) {
541         into->name = from->name;
542         from->name = NULL;
543     }
544
545     list_foreach(si, &from->interps, entry) {
546         if (merge != MERGE_DEFAULT)
547             si->merge = merge;
548         if (!AddInterp(into, si))
549             into->errorCount++;
550     }
551
552     for (i = 0, gcm = &from->groupCompat[0]; i < XkbNumKbdGroups;
553          i++, gcm++) {
554         if (merge != MERGE_DEFAULT)
555             gcm->merge = merge;
556         if (!AddGroupCompat(into, i, gcm))
557             into->errorCount++;
558     }
559
560     list_foreach_safe(led, next_led, &from->leds, entry) {
561         led->merge = (merge == MERGE_DEFAULT ? led->merge : merge);
562         if (!AddIndicatorMap(into, led))
563             into->errorCount++;
564     }
565 }
566
567 static void
568 HandleCompatMapFile(CompatInfo *info, XkbFile *file, enum merge_mode merge);
569
570 static bool
571 HandleIncludeCompatMap(CompatInfo *info, IncludeStmt *stmt)
572 {
573     enum merge_mode merge = MERGE_DEFAULT;
574     XkbFile *rtrn;
575     CompatInfo included, next_incl;
576
577     InitCompatInfo(&included, info->keymap, info->file_id);
578     if (stmt->stmt) {
579         free(included.name);
580         included.name = stmt->stmt;
581         stmt->stmt = NULL;
582     }
583
584     for (; stmt; stmt = stmt->next_incl) {
585         if (!ProcessIncludeFile(info->keymap->ctx, stmt, FILE_TYPE_COMPAT,
586                                 &rtrn, &merge)) {
587             info->errorCount += 10;
588             ClearCompatInfo(&included);
589             return false;
590         }
591
592         InitCompatInfo(&next_incl, info->keymap, rtrn->id);
593         next_incl.file_id = rtrn->id;
594         next_incl.dflt = info->dflt;
595         next_incl.dflt.file_id = rtrn->id;
596         next_incl.dflt.merge = merge;
597         next_incl.ledDflt.file_id = rtrn->id;
598         next_incl.ledDflt.merge = merge;
599         next_incl.act = info->act;
600
601         HandleCompatMapFile(&next_incl, rtrn, MERGE_OVERRIDE);
602
603         MergeIncludedCompatMaps(&included, &next_incl, merge);
604         if (info->act)
605             next_incl.act = NULL;
606
607         ClearCompatInfo(&next_incl);
608         FreeXkbFile(rtrn);
609     }
610
611     MergeIncludedCompatMaps(info, &included, merge);
612     ClearCompatInfo(&included);
613
614     return (info->errorCount == 0);
615 }
616
617 static const LookupEntry useModMapValues[] = {
618     { "levelone", 1 },
619     { "level1", 1 },
620     { "anylevel", 0 },
621     { "any", 0 },
622     { NULL, 0 }
623 };
624
625 static int
626 SetInterpField(CompatInfo *info, SymInterpInfo *si, const char *field,
627                ExprDef *arrayNdx, ExprDef *value)
628 {
629     struct xkb_keymap *keymap = info->keymap;
630     xkb_mod_index_t ndx;
631
632     if (istreq(field, "action")) {
633         if (arrayNdx)
634             return ReportSINotArray(info, si, field);
635
636         if (!HandleActionDef(value, keymap, &si->interp.act, info->act))
637             return false;
638
639         si->defined |= SI_FIELD_ACTION;
640     }
641     else if (istreq(field, "virtualmodifier") ||
642              istreq(field, "virtualmod")) {
643         if (arrayNdx)
644             return ReportSINotArray(info, si, field);
645
646         if (!ResolveVirtualModifier(value, keymap, &ndx, &info->vmods))
647             return ReportSIBadType(info, si, field, "virtual modifier");
648
649         si->interp.virtual_mod = ndx;
650         si->defined |= SI_FIELD_VIRTUAL_MOD;
651     }
652     else if (istreq(field, "repeat")) {
653         bool set;
654
655         if (arrayNdx)
656             return ReportSINotArray(info, si, field);
657
658         if (!ExprResolveBoolean(keymap->ctx, value, &set))
659             return ReportSIBadType(info, si, field, "boolean");
660
661         if (set)
662             si->interp.flags |= XkbSI_AutoRepeat;
663         else
664             si->interp.flags &= ~XkbSI_AutoRepeat;
665
666         si->defined |= SI_FIELD_AUTO_REPEAT;
667     }
668     else if (istreq(field, "locking")) {
669         bool set;
670
671         if (arrayNdx)
672             return ReportSINotArray(info, si, field);
673
674         if (!ExprResolveBoolean(keymap->ctx, value, &set))
675             return ReportSIBadType(info, si, field, "boolean");
676
677         if (set)
678             si->interp.flags |= XkbSI_LockingKey;
679         else
680             si->interp.flags &= ~XkbSI_LockingKey;
681
682         si->defined |= SI_FIELD_LOCKING_KEY;
683     }
684     else if (istreq(field, "usemodmap") ||
685              istreq(field, "usemodmapmods")) {
686         unsigned int val;
687
688         if (arrayNdx)
689             return ReportSINotArray(info, si, field);
690
691         if (!ExprResolveEnum(keymap->ctx, value, &val, useModMapValues))
692             return ReportSIBadType(info, si, field, "level specification");
693
694         if (val)
695             si->interp.match |= XkbSI_LevelOneOnly;
696         else
697             si->interp.match &= ~XkbSI_LevelOneOnly;
698
699         si->defined |= SI_FIELD_LEVEL_ONE_ONLY;
700     }
701     else {
702         return ReportBadField(keymap, "symbol interpretation", field,
703                               siText(si, info));
704     }
705
706     return true;
707 }
708
709 static const LookupEntry modComponentNames[] = {
710     {"base", XkbIM_UseBase},
711     {"latched", XkbIM_UseLatched},
712     {"locked", XkbIM_UseLocked},
713     {"effective", XkbIM_UseEffective},
714     {"compat", XkbIM_UseCompat},
715     {"any", XkbIM_UseAnyMods},
716     {"none", 0},
717     {NULL, 0}
718 };
719 static const LookupEntry groupComponentNames[] = {
720     {"base", XkbIM_UseBase},
721     {"latched", XkbIM_UseLatched},
722     {"locked", XkbIM_UseLocked},
723     {"effective", XkbIM_UseEffective},
724     {"any", XkbIM_UseAnyGroup},
725     {"none", 0},
726     {NULL, 0}
727 };
728
729 static const LookupEntry groupNames[] = {
730     {"group1", 0x01},
731     {"group2", 0x02},
732     {"group3", 0x04},
733     {"group4", 0x08},
734     {"group5", 0x10},
735     {"group6", 0x20},
736     {"group7", 0x40},
737     {"group8", 0x80},
738     {"none", 0x00},
739     {"all", 0xff},
740     {NULL, 0}
741 };
742
743 static int
744 SetIndicatorMapField(CompatInfo *info, LEDInfo *led,
745                      const char *field, ExprDef *arrayNdx, ExprDef *value)
746 {
747     bool ok = true;
748     struct xkb_keymap *keymap = info->keymap;
749
750     if (istreq(field, "modifiers") || istreq(field, "mods")) {
751         if (arrayNdx)
752             return ReportIndicatorNotArray(info, led, field);
753
754         if (!ExprResolveVModMask(keymap, value, &led->mods))
755             return ReportIndicatorBadType(info, led, field, "modifier mask");
756
757         led->defined |= LED_FIELD_MODS;
758     }
759     else if (istreq(field, "groups")) {
760         unsigned int mask;
761
762         if (arrayNdx)
763             return ReportIndicatorNotArray(info, led, field);
764
765         if (!ExprResolveMask(keymap->ctx, value, &mask, groupNames))
766             return ReportIndicatorBadType(info, led, field, "group mask");
767
768         led->groups = mask;
769         led->defined |= LED_FIELD_GROUPS;
770     }
771     else if (istreq(field, "controls") || istreq(field, "ctrls")) {
772         unsigned int mask;
773
774         if (arrayNdx)
775             return ReportIndicatorNotArray(info, led, field);
776
777         if (!ExprResolveMask(keymap->ctx, value, &mask, ctrlNames))
778             return ReportIndicatorBadType(info, led, field,
779                                           "controls mask");
780
781         led->ctrls = mask;
782         led->defined |= LED_FIELD_CTRLS;
783     }
784     else if (istreq(field, "allowexplicit")) {
785         bool set;
786
787         if (arrayNdx)
788             return ReportIndicatorNotArray(info, led, field);
789
790         if (!ExprResolveBoolean(keymap->ctx, value, &set))
791             return ReportIndicatorBadType(info, led, field, "boolean");
792
793         if (set)
794             led->flags &= ~XkbIM_NoExplicit;
795         else
796             led->flags |= XkbIM_NoExplicit;
797
798         led->defined |= LED_FIELD_EXPLICIT;
799     }
800     else if (istreq(field, "whichmodstate") ||
801              istreq(field, "whichmodifierstate")) {
802         unsigned int mask;
803
804         if (arrayNdx)
805             return ReportIndicatorNotArray(info, led, field);
806
807         if (!ExprResolveMask(keymap->ctx, value, &mask, modComponentNames))
808             return ReportIndicatorBadType(info, led, field,
809                                           "mask of modifier state components");
810
811         led->which_mods = mask;
812     }
813     else if (istreq(field, "whichgroupstate")) {
814         unsigned mask;
815
816         if (arrayNdx)
817             return ReportIndicatorNotArray(info, led, field);
818
819         if (!ExprResolveMask(keymap->ctx, value, &mask, groupComponentNames))
820             return ReportIndicatorBadType(info, led, field,
821                                           "mask of group state components");
822
823         led->which_groups = mask;
824     }
825     else if (istreq(field, "driveskbd") ||
826              istreq(field, "driveskeyboard") ||
827              istreq(field, "leddriveskbd") ||
828              istreq(field, "leddriveskeyboard") ||
829              istreq(field, "indicatordriveskbd") ||
830              istreq(field, "indicatordriveskeyboard")) {
831         bool set;
832
833         if (arrayNdx)
834             return ReportIndicatorNotArray(info, led, field);
835
836         if (!ExprResolveBoolean(keymap->ctx, value, &set))
837             return ReportIndicatorBadType(info, led, field, "boolean");
838
839         if (set)
840             led->flags |= XkbIM_LEDDrivesKB;
841         else
842             led->flags &= ~XkbIM_LEDDrivesKB;
843
844         led->defined |= LED_FIELD_DRIVES_KBD;
845     }
846     else if (istreq(field, "index")) {
847         int ndx;
848
849         if (arrayNdx)
850             return ReportIndicatorNotArray(info, led, field);
851
852         if (!ExprResolveInteger(keymap->ctx, value, &ndx))
853             return ReportIndicatorBadType(info, led, field,
854                                           "indicator index");
855
856         if (ndx < 1 || ndx > 32) {
857             log_err(info->keymap->ctx,
858                     "Illegal indicator index %d (range 1..%d); "
859                     "Index definition for %s indicator ignored\n",
860                     ndx, XkbNumIndicators,
861                     xkb_atom_text(keymap->ctx, led->name));
862             return false;
863         }
864
865         led->indicator = (xkb_led_index_t) ndx;
866         led->defined |= LED_FIELD_INDEX;
867     }
868     else {
869         log_err(info->keymap->ctx,
870                 "Unknown field %s in map for %s indicator; "
871                 "Definition ignored\n",
872                 field, xkb_atom_text(keymap->ctx, led->name));
873         ok = false;
874     }
875
876     return ok;
877 }
878
879 static int
880 HandleInterpVar(CompatInfo *info, VarDef *stmt)
881 {
882     const char *elem, *field;
883     ExprDef *ndx;
884     int ret;
885
886     if (!ExprResolveLhs(info->keymap->ctx, stmt->name, &elem, &field, &ndx))
887         ret = 0;               /* internal error, already reported */
888     else if (elem && istreq(elem, "interpret"))
889         ret = SetInterpField(info, &info->dflt, field, ndx, stmt->value);
890     else if (elem && istreq(elem, "indicator"))
891         ret = SetIndicatorMapField(info, &info->ledDflt, field, ndx,
892                                    stmt->value);
893     else
894         ret = SetActionField(info->keymap, elem, field, ndx, stmt->value,
895                              &info->act);
896     return ret;
897 }
898
899 static int
900 HandleInterpBody(CompatInfo *info, VarDef *def, SymInterpInfo *si)
901 {
902     int ok = 1;
903     const char *elem, *field;
904     ExprDef *arrayNdx;
905
906     for (; def != NULL; def = (VarDef *) def->common.next) {
907         if (def->name && def->name->op == EXPR_FIELD_REF) {
908             ok = HandleInterpVar(info, def);
909             continue;
910         }
911         ok = ExprResolveLhs(info->keymap->ctx, def->name, &elem, &field,
912                             &arrayNdx);
913         if (ok) {
914             ok = SetInterpField(info, si, field, arrayNdx, def->value);
915         }
916     }
917     return ok;
918 }
919
920 static int
921 HandleInterpDef(CompatInfo *info, InterpDef *def, enum merge_mode merge)
922 {
923     unsigned pred, mods;
924     SymInterpInfo si;
925
926     if (!ResolveStateAndPredicate(def->match, &pred, &mods, info)) {
927         log_err(info->keymap->ctx,
928                 "Couldn't determine matching modifiers; "
929                 "Symbol interpretation ignored\n");
930         return false;
931     }
932     if (def->merge != MERGE_DEFAULT)
933         merge = def->merge;
934
935     si = info->dflt;
936     si.merge = merge;
937     if (!LookupKeysym(def->sym, &si.interp.sym)) {
938         log_err(info->keymap->ctx,
939                 "Could not resolve keysym %s; "
940                 "Symbol interpretation ignored\n",
941                 def->sym);
942         return false;
943     }
944     si.interp.match = pred & XkbSI_OpMask;
945     si.interp.mods = mods;
946     if (!HandleInterpBody(info, def->def, &si)) {
947         info->errorCount++;
948         return false;
949     }
950
951     if (!AddInterp(info, &si)) {
952         info->errorCount++;
953         return false;
954     }
955     return true;
956 }
957
958 static int
959 HandleGroupCompatDef(CompatInfo *info, GroupCompatDef *def,
960                      enum merge_mode merge)
961 {
962     GroupCompatInfo tmp;
963
964     merge = (def->merge == MERGE_DEFAULT ? merge : def->merge);
965
966     if (def->group < 1 || def->group > XkbNumKbdGroups) {
967         log_err(info->keymap->ctx,
968                 "Keyboard group must be in the range 1..%u; "
969                 "Compatibility map for illegal group %u ignored\n",
970                 XkbNumKbdGroups, def->group);
971         return false;
972     }
973
974     tmp.file_id = info->file_id;
975     tmp.merge = merge;
976
977     if (!ExprResolveVModMask(info->keymap, def->def, &tmp.mods)) {
978         log_err(info->keymap->ctx,
979                 "Expected a modifier mask in group compatibility definition; "
980                 "Ignoring illegal compatibility map for group %u\n",
981                 def->group);
982         return false;
983     }
984
985     tmp.defined = true;
986     return AddGroupCompat(info, def->group - 1, &tmp);
987 }
988
989 static bool
990 HandleIndicatorMapDef(CompatInfo *info, IndicatorMapDef *def,
991                       enum merge_mode merge)
992 {
993     LEDInfo led;
994     VarDef *var;
995     bool ok;
996
997     if (def->merge != MERGE_DEFAULT)
998         merge = def->merge;
999
1000     led = info->ledDflt;
1001     led.merge = merge;
1002     led.name = def->name;
1003
1004     ok = true;
1005     for (var = def->body; var != NULL; var = (VarDef *) var->common.next) {
1006         const char *elem, *field;
1007         ExprDef *arrayNdx;
1008         if (!ExprResolveLhs(info->keymap->ctx, var->name, &elem, &field,
1009                             &arrayNdx)) {
1010             ok = false;
1011             continue;
1012         }
1013
1014         if (elem) {
1015             log_err(info->keymap->ctx,
1016                     "Cannot set defaults for \"%s\" element in indicator map; "
1017                     "Assignment to %s.%s ignored\n", elem, elem, field);
1018             ok = false;
1019         }
1020         else {
1021             ok = SetIndicatorMapField(info, &led, field, arrayNdx,
1022                                       var->value) && ok;
1023         }
1024     }
1025
1026     if (ok)
1027         return AddIndicatorMap(info, &led);
1028
1029     return false;
1030 }
1031
1032 static void
1033 HandleCompatMapFile(CompatInfo *info, XkbFile *file, enum merge_mode merge)
1034 {
1035     bool ok;
1036     ParseCommon *stmt;
1037
1038     merge = (merge == MERGE_DEFAULT ? MERGE_AUGMENT : merge);
1039
1040     free(info->name);
1041     info->name = strdup_safe(file->name);
1042
1043     for (stmt = file->defs; stmt; stmt = stmt->next) {
1044         switch (stmt->type) {
1045         case STMT_INCLUDE:
1046             ok = HandleIncludeCompatMap(info, (IncludeStmt *) stmt);
1047             break;
1048         case STMT_INTERP:
1049             ok = HandleInterpDef(info, (InterpDef *) stmt, merge);
1050             break;
1051         case STMT_GROUP_COMPAT:
1052             ok = HandleGroupCompatDef(info, (GroupCompatDef *) stmt, merge);
1053             break;
1054         case STMT_INDICATOR_MAP:
1055             ok = HandleIndicatorMapDef(info, (IndicatorMapDef *) stmt, merge);
1056             break;
1057         case STMT_VAR:
1058             ok = HandleInterpVar(info, (VarDef *) stmt);
1059             break;
1060         case STMT_VMOD:
1061             ok = HandleVModDef((VModDef *) stmt, info->keymap, merge,
1062                                &info->vmods);
1063             break;
1064         default:
1065             log_err(info->keymap->ctx,
1066                     "Interpretation files may not include other types; "
1067                     "Ignoring %s\n", StmtTypeToString(stmt->type));
1068             ok = false;
1069             break;
1070         }
1071
1072         if (!ok)
1073             info->errorCount++;
1074
1075         if (info->errorCount > 10) {
1076             log_err(info->keymap->ctx,
1077                     "Abandoning compatibility map \"%s\"\n", file->topName);
1078             break;
1079         }
1080     }
1081 }
1082
1083 static void
1084 CopyInterps(CompatInfo *info, bool needSymbol, unsigned pred)
1085 {
1086     SymInterpInfo *si;
1087
1088     list_foreach(si, &info->interps, entry) {
1089         if (((si->interp.match & XkbSI_OpMask) != pred) ||
1090             (needSymbol && si->interp.sym == XKB_KEY_NoSymbol) ||
1091             (!needSymbol && si->interp.sym != XKB_KEY_NoSymbol))
1092             continue;
1093
1094         darray_append(info->keymap->sym_interpret, si->interp);
1095     }
1096 }
1097
1098 static void
1099 BindIndicators(CompatInfo *info, struct list *unbound_leds)
1100 {
1101     xkb_led_index_t i;
1102     LEDInfo *led, *next_led;
1103     struct xkb_indicator_map *map;
1104     struct xkb_keymap *keymap = info->keymap;
1105
1106     list_foreach(led, unbound_leds, entry) {
1107         if (led->indicator == XKB_LED_INVALID) {
1108             for (i = 0; i < XkbNumIndicators; i++) {
1109                 if (keymap->indicator_names[i] &&
1110                     streq(keymap->indicator_names[i],
1111                           xkb_atom_text(keymap->ctx, led->name))) {
1112                     led->indicator = i + 1;
1113                     break;
1114                 }
1115             }
1116         }
1117     }
1118
1119     list_foreach(led, unbound_leds, entry) {
1120         if (led->indicator == XKB_LED_INVALID) {
1121             for (i = 0; i < XkbNumIndicators; i++) {
1122                 if (keymap->indicator_names[i] == NULL) {
1123                     keymap->indicator_names[i] =
1124                         xkb_atom_text(keymap->ctx, led->name);
1125                     led->indicator = i + 1;
1126                     break;
1127                 }
1128             }
1129
1130             if (led->indicator == XKB_LED_INVALID) {
1131                 log_err(info->keymap->ctx,
1132                         "No unnamed indicators found; "
1133                         "Virtual indicator map \"%s\" not bound\n",
1134                         xkb_atom_text(keymap->ctx, led->name));
1135                 continue;
1136             }
1137         }
1138     }
1139
1140     list_foreach_safe(led, next_led, unbound_leds, entry) {
1141         if (led->indicator == XKB_LED_INVALID) {
1142             free(led);
1143             continue;
1144         }
1145
1146         if (!streq(keymap->indicator_names[led->indicator - 1],
1147                    xkb_atom_text(keymap->ctx, led->name))) {
1148             const char *old = keymap->indicator_names[led->indicator - 1];
1149             log_err(info->keymap->ctx,
1150                     "Multiple names bound to indicator %d; "
1151                     "Using %s, ignoring %s\n",
1152                     led->indicator, old,
1153                     xkb_atom_text(keymap->ctx, led->name));
1154             free(led);
1155             continue;
1156         }
1157
1158         map = &keymap->indicators[led->indicator - 1];
1159         map->flags = led->flags;
1160         map->which_groups = led->which_groups;
1161         map->groups = led->groups;
1162         map->which_mods = led->which_mods;
1163         map->mods.mods = led->mods;
1164         map->ctrls = led->ctrls;
1165         free(led);
1166     }
1167
1168     list_init(unbound_leds);
1169 }
1170
1171 static bool
1172 CopyIndicatorMapDefs(CompatInfo *info)
1173 {
1174     LEDInfo *led, *next_led;
1175     struct list unbound_leds;
1176     struct xkb_indicator_map *im;
1177     struct xkb_keymap *keymap = info->keymap;
1178
1179     list_init(&unbound_leds);
1180
1181     list_foreach_safe(led, next_led, &info->leds, entry) {
1182         if (led->groups != 0 && led->which_groups == 0)
1183             led->which_groups = XkbIM_UseEffective;
1184
1185         if (led->which_mods == 0 && led->mods)
1186             led->which_mods = XkbIM_UseEffective;
1187
1188         if (led->indicator == XKB_LED_INVALID) {
1189             list_append(&led->entry, &unbound_leds);
1190             continue;
1191         }
1192
1193         im = &keymap->indicators[led->indicator - 1];
1194         im->flags = led->flags;
1195         im->which_groups = led->which_groups;
1196         im->groups = led->groups;
1197         im->which_mods = led->which_mods;
1198         im->mods.mods = led->mods;
1199         im->ctrls = led->ctrls;
1200         keymap->indicator_names[led->indicator - 1] =
1201             xkb_atom_text(keymap->ctx, led->name);
1202         free(led);
1203     }
1204     list_init(&info->leds);
1205
1206     BindIndicators(info, &unbound_leds);
1207
1208     return true;
1209 }
1210
1211 bool
1212 CompileCompatMap(XkbFile *file, struct xkb_keymap *keymap,
1213                  enum merge_mode merge)
1214 {
1215     xkb_group_index_t i;
1216     CompatInfo info;
1217     GroupCompatInfo *gcm;
1218
1219     InitCompatInfo(&info, keymap, file->id);
1220     info.dflt.merge = merge;
1221     info.ledDflt.merge = merge;
1222
1223     HandleCompatMapFile(&info, file, merge);
1224
1225     if (info.errorCount != 0)
1226         goto err_info;
1227
1228     darray_init(keymap->sym_interpret);
1229     darray_growalloc(keymap->sym_interpret, info.nInterps);
1230
1231     if (info.name)
1232         keymap->compat_section_name = strdup(info.name);
1233
1234     if (info.nInterps > 0) {
1235         CopyInterps(&info, true, XkbSI_Exactly);
1236         CopyInterps(&info, true, XkbSI_AllOf | XkbSI_NoneOf);
1237         CopyInterps(&info, true, XkbSI_AnyOf);
1238         CopyInterps(&info, true, XkbSI_AnyOfOrNone);
1239         CopyInterps(&info, false, XkbSI_Exactly);
1240         CopyInterps(&info, false, XkbSI_AllOf | XkbSI_NoneOf);
1241         CopyInterps(&info, false, XkbSI_AnyOf);
1242         CopyInterps(&info, false, XkbSI_AnyOfOrNone);
1243     }
1244
1245     for (i = 0, gcm = &info.groupCompat[0]; i < XkbNumKbdGroups;
1246          i++, gcm++) {
1247         if (gcm->file_id != 0 || gcm->mods != 0)
1248             keymap->groups[i].mods = gcm->mods;
1249     }
1250
1251     if (!CopyIndicatorMapDefs(&info))
1252         info.errorCount++;
1253
1254     ClearCompatInfo(&info);
1255     return true;
1256
1257 err_info:
1258     ClearCompatInfo(&info);
1259     return false;
1260 }
1261
1262 static void
1263 ComputeEffectiveMask(struct xkb_keymap *keymap, struct xkb_mods *mods)
1264 {
1265     xkb_mod_index_t i;
1266     xkb_mod_mask_t vmask = mods->mods >> XkbNumModifiers;
1267
1268     /* The effective mask is only real mods for now. */
1269     mods->mask = mods->mods & 0xff;
1270
1271     for (i = 0; i < XkbNumVirtualMods; i++) {
1272         if (!(vmask & (1 << i)))
1273             continue;
1274         mods->mask |= keymap->vmods[i];
1275     }
1276 }
1277
1278 static void
1279 UpdateActionMods(struct xkb_keymap *keymap, union xkb_action *act,
1280                  xkb_mod_mask_t rmodmask)
1281 {
1282     unsigned int flags;
1283     struct xkb_mods *mods;
1284
1285     switch (act->type) {
1286     case XkbSA_SetMods:
1287     case XkbSA_LatchMods:
1288     case XkbSA_LockMods:
1289         flags = act->mods.flags;
1290         mods = &act->mods.mods;
1291         break;
1292
1293     case XkbSA_ISOLock:
1294         flags = act->iso.flags;
1295         mods = &act->iso.mods;
1296         break;
1297
1298     default:
1299         return;
1300     }
1301
1302     if (flags & XkbSA_UseModMapMods) {
1303         /* XXX: what's that. */
1304         mods->mods &= 0xff;
1305         mods->mods |= rmodmask;
1306     }
1307     ComputeEffectiveMask(keymap, mods);
1308 }
1309
1310 /**
1311  * Find an interpretation which applies to this particular level, either by
1312  * finding an exact match for the symbol and modifier combination, or a
1313  * generic XKB_KEY_NoSymbol match.
1314  */
1315 static struct xkb_sym_interpret *
1316 FindInterpForKey(struct xkb_keymap *keymap, struct xkb_key *key,
1317                  xkb_group_index_t group, xkb_level_index_t level)
1318 {
1319     struct xkb_sym_interpret *ret = NULL;
1320     struct xkb_sym_interpret *interp;
1321     const xkb_keysym_t *syms;
1322     int num_syms;
1323
1324     num_syms = xkb_key_get_syms_by_level(keymap, key, group, level, &syms);
1325     if (num_syms == 0)
1326         return NULL;
1327
1328     darray_foreach(interp, keymap->sym_interpret) {
1329         uint32_t mods;
1330         bool found;
1331
1332         if ((num_syms > 1 || interp->sym != syms[0]) &&
1333             interp->sym != XKB_KEY_NoSymbol)
1334             continue;
1335
1336         if (level == 0 || !(interp->match & XkbSI_LevelOneOnly))
1337             mods = key->modmap;
1338         else
1339             mods = 0;
1340
1341         switch (interp->match & XkbSI_OpMask) {
1342         case XkbSI_NoneOf:
1343             found = !(interp->mods & mods);
1344             break;
1345         case XkbSI_AnyOfOrNone:
1346             found = (!mods || (interp->mods & mods));
1347             break;
1348         case XkbSI_AnyOf:
1349             found = !!(interp->mods & mods);
1350             break;
1351         case XkbSI_AllOf:
1352             found = ((interp->mods & mods) == interp->mods);
1353             break;
1354         case XkbSI_Exactly:
1355             found = (interp->mods == mods);
1356             break;
1357         default:
1358             found = false;
1359             break;
1360         }
1361
1362         if (found && interp->sym != XKB_KEY_NoSymbol)
1363             return interp;
1364         else if (found && !ret)
1365             ret = interp;
1366     }
1367
1368     return ret;
1369 }
1370
1371 /**
1372  */
1373 static bool
1374 ApplyInterpsToKey(struct xkb_keymap *keymap, struct xkb_key *key)
1375 {
1376 #define INTERP_SIZE (8 * 4)
1377     struct xkb_sym_interpret *interps[INTERP_SIZE];
1378     xkb_mod_mask_t vmodmask = 0;
1379     int num_acts = 0;
1380     xkb_group_index_t group;
1381     xkb_level_index_t level;
1382     unsigned int i;
1383
1384     /* If we've been told not to bind interps to this key, then don't. */
1385     if (key->explicit & XkbExplicitInterpretMask)
1386         return true;
1387
1388     for (i = 0; i < INTERP_SIZE; i++)
1389         interps[i] = NULL;
1390
1391     for (group = 0; group < key->num_groups; group++) {
1392         for (level = 0; level < XkbKeyGroupWidth(keymap, key, group);
1393              level++) {
1394             i = (group * key->width) + level;
1395             if (i >= INTERP_SIZE) /* XXX FIXME */
1396                 return false;
1397             interps[i] = FindInterpForKey(keymap, key, group, level);
1398             if (interps[i])
1399                 num_acts++;
1400         }
1401     }
1402
1403     if (num_acts && !key->actions) {
1404         key->actions = calloc(key->num_groups * key->width,
1405                               sizeof(*key->actions));
1406         if (!key->actions)
1407             return false;
1408     }
1409
1410     for (group = 0; group < key->num_groups; group++) {
1411         for (level = 0; level < XkbKeyGroupWidth(keymap, key, group);
1412              level++) {
1413             struct xkb_sym_interpret *interp;
1414
1415             i = (group * key->width) + level;
1416             interp = interps[i];
1417
1418             /* Infer default key behaviours from the base level. */
1419             if (group == 0 && level == 0) {
1420                 if (!(key->explicit & XkbExplicitAutoRepeatMask) &&
1421                     (!interp || (interp->flags & XkbSI_AutoRepeat)))
1422                     key->repeats = true;
1423             }
1424
1425             if (!interp)
1426                 continue;
1427
1428             if ((group == 0 && level == 0) ||
1429                 !(interp->match & XkbSI_LevelOneOnly)) {
1430                 if (interp->virtual_mod != XkbNoModifier)
1431                     vmodmask |= (1 << interp->virtual_mod);
1432             }
1433
1434             key->actions[i] = interp->act;
1435         }
1436     }
1437
1438     if (!(key->explicit & XkbExplicitVModMapMask))
1439         key->vmodmap = vmodmask;
1440
1441     return true;
1442 #undef INTERP_SIZE
1443 }
1444
1445 /**
1446  * This collects a bunch of disparate functions which was done in the server
1447  * at various points that really should've been done within xkbcomp.  Turns out
1448  * your actions and types are a lot more useful when any of your modifiers
1449  * other than Shift actually do something ...
1450  */
1451 bool
1452 UpdateModifiersFromCompat(struct xkb_keymap *keymap)
1453 {
1454     xkb_mod_index_t vmod;
1455     xkb_group_index_t grp;
1456     xkb_led_index_t led;
1457     unsigned int i, j;
1458     struct xkb_key *key;
1459
1460     /* Find all the interprets for the key and bind them to actions,
1461      * which will also update the vmodmap. */
1462     xkb_foreach_key(key, keymap)
1463         if (!ApplyInterpsToKey(keymap, key))
1464             return false;
1465
1466     /* Update keymap->vmods, the virtual -> real mod mapping. */
1467     for (vmod = 0; vmod < XkbNumVirtualMods; vmod++)
1468         keymap->vmods[vmod] = 0;
1469
1470     xkb_foreach_key(key, keymap) {
1471         if (!key->vmodmap)
1472             continue;
1473
1474         for (vmod = 0; vmod < XkbNumVirtualMods; vmod++) {
1475             if (!(key->vmodmap & (1 << vmod)))
1476                 continue;
1477             keymap->vmods[vmod] |= key->modmap;
1478         }
1479     }
1480
1481     /* Now update the level masks for all the types to reflect the vmods. */
1482     for (i = 0; i < keymap->num_types; i++) {
1483         ComputeEffectiveMask(keymap, &keymap->types[i].mods);
1484
1485         for (j = 0; j < keymap->types[i].num_entries; j++) {
1486             ComputeEffectiveMask(keymap, &keymap->types[i].map[j].mods);
1487             ComputeEffectiveMask(keymap, &keymap->types[i].map[j].preserve);
1488         }
1489     }
1490
1491     /* Update action modifiers. */
1492     xkb_foreach_key(key, keymap) {
1493         if (!key->actions)
1494             continue;
1495
1496         for (i = 0; i < key->num_groups * key->width; i++)
1497             UpdateActionMods(keymap, &key->actions[i], key->modmap);
1498     }
1499
1500     /* Update group modifiers. */
1501     for (grp = 0; grp < XkbNumKbdGroups; grp++)
1502         ComputeEffectiveMask(keymap, &keymap->groups[grp]);
1503
1504     /* Update vmod -> indicator maps. */
1505     for (led = 0; led < XkbNumIndicators; led++)
1506         ComputeEffectiveMask(keymap, &keymap->indicators[led].mods);
1507
1508     return true;
1509 }