compat: reject interpret modifier predicate with more than one value
[platform/upstream/libxkbcommon.git] / src / xkbcomp / keymap.c
1 /*
2  * Copyright © 2009 Dan Nicholson
3  * Copyright © 2012 Intel Corporation
4  * Copyright © 2012 Ran Benita <ran234@gmail.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the next
14  * paragraph) shall be included in all copies or substantial portions of the
15  * Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23  * DEALINGS IN THE SOFTWARE.
24  *
25  * Author: Dan Nicholson <dbn.lists@gmail.com>
26  *         Daniel Stone <daniel@fooishbar.org>
27  *         Ran Benita <ran234@gmail.com>
28  */
29
30 #include "xkbcomp-priv.h"
31
32 static void
33 ComputeEffectiveMask(struct xkb_keymap *keymap, struct xkb_mods *mods)
34 {
35     mods->mask = mod_mask_get_effective(keymap, mods->mods);
36 }
37
38 static void
39 UpdateActionMods(struct xkb_keymap *keymap, union xkb_action *act,
40                  xkb_mod_mask_t modmap)
41 {
42     switch (act->type) {
43     case ACTION_TYPE_MOD_SET:
44     case ACTION_TYPE_MOD_LATCH:
45     case ACTION_TYPE_MOD_LOCK:
46         if (act->mods.flags & ACTION_MODS_LOOKUP_MODMAP)
47             act->mods.mods.mods = modmap;
48         ComputeEffectiveMask(keymap, &act->mods.mods);
49         break;
50     default:
51         break;
52     }
53 }
54
55 static const struct xkb_sym_interpret default_interpret = {
56     .sym = XKB_KEY_NoSymbol,
57     .repeat = true,
58     .match = MATCH_ANY_OR_NONE,
59     .mods = 0,
60     .virtual_mod = XKB_MOD_INVALID,
61     .action = { .type = ACTION_TYPE_NONE },
62 };
63
64 /**
65  * Find an interpretation which applies to this particular level, either by
66  * finding an exact match for the symbol and modifier combination, or a
67  * generic XKB_KEY_NoSymbol match.
68  */
69 static const struct xkb_sym_interpret *
70 FindInterpForKey(struct xkb_keymap *keymap, const struct xkb_key *key,
71                  xkb_layout_index_t group, xkb_level_index_t level)
72 {
73     const xkb_keysym_t *syms;
74     int num_syms;
75
76     num_syms = xkb_keymap_key_get_syms_by_level(keymap, key->keycode, group,
77                                                 level, &syms);
78     if (num_syms == 0)
79         return NULL;
80
81     /*
82      * There may be multiple matchings interprets; we should always return
83      * the most specific. Here we rely on compat.c to set up the
84      * sym_interprets array from the most specific to the least specific,
85      * such that when we find a match we return immediately.
86      */
87     for (unsigned i = 0; i < keymap->num_sym_interprets; i++) {
88         const struct xkb_sym_interpret *interp = &keymap->sym_interprets[i];
89
90         xkb_mod_mask_t mods;
91         bool found = false;
92
93         if ((num_syms > 1 || interp->sym != syms[0]) &&
94             interp->sym != XKB_KEY_NoSymbol)
95             continue;
96
97         if (interp->level_one_only && level != 0)
98             mods = 0;
99         else
100             mods = key->modmap;
101
102         switch (interp->match) {
103         case MATCH_NONE:
104             found = !(interp->mods & mods);
105             break;
106         case MATCH_ANY_OR_NONE:
107             found = (!mods || (interp->mods & mods));
108             break;
109         case MATCH_ANY:
110             found = (interp->mods & mods);
111             break;
112         case MATCH_ALL:
113             found = ((interp->mods & mods) == interp->mods);
114             break;
115         case MATCH_EXACTLY:
116             found = (interp->mods == mods);
117             break;
118         }
119
120         if (found)
121             return interp;
122     }
123
124     return &default_interpret;
125 }
126
127 static bool
128 ApplyInterpsToKey(struct xkb_keymap *keymap, struct xkb_key *key)
129 {
130     xkb_mod_mask_t vmodmap = 0;
131     xkb_layout_index_t group;
132     xkb_level_index_t level;
133
134     /* If we've been told not to bind interps to this key, then don't. */
135     if (key->explicit & EXPLICIT_INTERP)
136         return true;
137
138     for (group = 0; group < key->num_groups; group++) {
139         for (level = 0; level < XkbKeyNumLevels(key, group); level++) {
140             const struct xkb_sym_interpret *interp;
141
142             interp = FindInterpForKey(keymap, key, group, level);
143             if (!interp)
144                 continue;
145
146             /* Infer default key behaviours from the base level. */
147             if (group == 0 && level == 0)
148                 if (!(key->explicit & EXPLICIT_REPEAT) && interp->repeat)
149                     key->repeats = true;
150
151             if ((group == 0 && level == 0) || !interp->level_one_only)
152                 if (interp->virtual_mod != XKB_MOD_INVALID)
153                     vmodmap |= (1u << interp->virtual_mod);
154
155             if (interp->action.type != ACTION_TYPE_NONE)
156                 key->groups[group].levels[level].action = interp->action;
157         }
158     }
159
160     if (!(key->explicit & EXPLICIT_VMODMAP))
161         key->vmodmap = vmodmap;
162
163     return true;
164 }
165
166 /**
167  * This collects a bunch of disparate functions which was done in the server
168  * at various points that really should've been done within xkbcomp.  Turns out
169  * your actions and types are a lot more useful when any of your modifiers
170  * other than Shift actually do something ...
171  */
172 static bool
173 UpdateDerivedKeymapFields(struct xkb_keymap *keymap)
174 {
175     struct xkb_key *key;
176     struct xkb_mod *mod;
177     struct xkb_led *led;
178     unsigned int i, j;
179
180     /* Find all the interprets for the key and bind them to actions,
181      * which will also update the vmodmap. */
182     xkb_keys_foreach(key, keymap)
183         if (!ApplyInterpsToKey(keymap, key))
184             return false;
185
186     /* Update keymap->mods, the virtual -> real mod mapping. */
187     xkb_keys_foreach(key, keymap)
188         xkb_mods_enumerate(i, mod, &keymap->mods)
189             if (key->vmodmap & (1u << i))
190                 mod->mapping |= key->modmap;
191
192     /* Now update the level masks for all the types to reflect the vmods. */
193     for (i = 0; i < keymap->num_types; i++) {
194         ComputeEffectiveMask(keymap, &keymap->types[i].mods);
195
196         for (j = 0; j < keymap->types[i].num_entries; j++) {
197             ComputeEffectiveMask(keymap, &keymap->types[i].entries[j].mods);
198             ComputeEffectiveMask(keymap, &keymap->types[i].entries[j].preserve);
199         }
200     }
201
202     /* Update action modifiers. */
203     xkb_keys_foreach(key, keymap)
204         for (i = 0; i < key->num_groups; i++)
205             for (j = 0; j < XkbKeyNumLevels(key, i); j++)
206                 UpdateActionMods(keymap, &key->groups[i].levels[j].action,
207                                  key->modmap);
208
209     /* Update vmod -> led maps. */
210     xkb_leds_foreach(led, keymap)
211         ComputeEffectiveMask(keymap, &led->mods);
212
213     /* Find maximum number of groups out of all keys in the keymap. */
214     xkb_keys_foreach(key, keymap)
215         keymap->num_groups = MAX(keymap->num_groups, key->num_groups);
216
217     return true;
218 }
219
220 typedef bool (*compile_file_fn)(XkbFile *file,
221                                 struct xkb_keymap *keymap,
222                                 enum merge_mode merge);
223
224 static const compile_file_fn compile_file_fns[LAST_KEYMAP_FILE_TYPE + 1] = {
225     [FILE_TYPE_KEYCODES] = CompileKeycodes,
226     [FILE_TYPE_TYPES] = CompileKeyTypes,
227     [FILE_TYPE_COMPAT] = CompileCompatMap,
228     [FILE_TYPE_SYMBOLS] = CompileSymbols,
229 };
230
231 bool
232 CompileKeymap(XkbFile *file, struct xkb_keymap *keymap, enum merge_mode merge)
233 {
234     bool ok;
235     XkbFile *files[LAST_KEYMAP_FILE_TYPE + 1] = { NULL };
236     enum xkb_file_type type;
237     struct xkb_context *ctx = keymap->ctx;
238
239     /* Collect section files and check for duplicates. */
240     for (file = (XkbFile *) file->defs; file;
241          file = (XkbFile *) file->common.next) {
242         if (file->file_type < FIRST_KEYMAP_FILE_TYPE ||
243             file->file_type > LAST_KEYMAP_FILE_TYPE) {
244             if (file->file_type == FILE_TYPE_GEOMETRY) {
245                 log_vrb(ctx, 1,
246                         "Geometry sections are not supported; ignoring\n");
247             } else {
248                 log_err(ctx, "Cannot define %s in a keymap file\n",
249                         xkb_file_type_to_string(file->file_type));
250             }
251             continue;
252         }
253
254         if (files[file->file_type]) {
255             log_err(ctx,
256                     "More than one %s section in keymap file; "
257                     "All sections after the first ignored\n",
258                     xkb_file_type_to_string(file->file_type));
259             continue;
260         }
261
262         files[file->file_type] = file;
263     }
264
265     /*
266      * Check that all required section were provided.
267      * Report everything before failing.
268      */
269     ok = true;
270     for (type = FIRST_KEYMAP_FILE_TYPE;
271          type <= LAST_KEYMAP_FILE_TYPE;
272          type++) {
273         if (files[type] == NULL) {
274             log_err(ctx, "Required section %s missing from keymap\n",
275                     xkb_file_type_to_string(type));
276             ok = false;
277         }
278     }
279     if (!ok)
280         return false;
281
282     /* Compile sections. */
283     for (type = FIRST_KEYMAP_FILE_TYPE;
284          type <= LAST_KEYMAP_FILE_TYPE;
285          type++) {
286         log_dbg(ctx, "Compiling %s \"%s\"\n",
287                 xkb_file_type_to_string(type), files[type]->name);
288
289         ok = compile_file_fns[type](files[type], keymap, merge);
290         if (!ok) {
291             log_err(ctx, "Failed to compile %s\n",
292                     xkb_file_type_to_string(type));
293             return false;
294         }
295     }
296
297     return UpdateDerivedKeymapFields(keymap);
298 }