Remove the XKB_NUM_INDICATORS limit
[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     const struct xkb_mod *mod;
36     xkb_mod_index_t i;
37
38     /* The effective mask is only real mods for now. */
39     mods->mask = mods->mods & MOD_REAL_MASK_ALL;
40
41     darray_enumerate(i, mod, keymap->mods)
42         if (mods->mods & (1 << i))
43             mods->mask |= mod->mapping;
44 }
45
46 static void
47 UpdateActionMods(struct xkb_keymap *keymap, union xkb_action *act,
48                  xkb_mod_mask_t modmap)
49 {
50     switch (act->type) {
51     case ACTION_TYPE_MOD_SET:
52     case ACTION_TYPE_MOD_LATCH:
53     case ACTION_TYPE_MOD_LOCK:
54         if (act->mods.flags & ACTION_MODS_LOOKUP_MODMAP)
55             act->mods.mods.mods = modmap;
56         ComputeEffectiveMask(keymap, &act->mods.mods);
57         break;
58     default:
59         break;
60     }
61 }
62
63 static const struct xkb_sym_interpret default_interpret = {
64     .sym = XKB_KEY_NoSymbol,
65     .repeat = true,
66     .match = MATCH_ANY_OR_NONE,
67     .mods = 0,
68     .virtual_mod = XKB_MOD_INVALID,
69     .act = { .type = ACTION_TYPE_NONE },
70 };
71
72 /**
73  * Find an interpretation which applies to this particular level, either by
74  * finding an exact match for the symbol and modifier combination, or a
75  * generic XKB_KEY_NoSymbol match.
76  */
77 static const struct xkb_sym_interpret *
78 FindInterpForKey(struct xkb_keymap *keymap, const struct xkb_key *key,
79                  xkb_layout_index_t group, xkb_level_index_t level)
80 {
81     const struct xkb_sym_interpret *interp;
82     const xkb_keysym_t *syms;
83     int num_syms;
84
85     num_syms = xkb_keymap_key_get_syms_by_level(keymap, key->keycode, group,
86                                                 level, &syms);
87     if (num_syms == 0)
88         return NULL;
89
90     /*
91      * There may be multiple matchings interprets; we should always return
92      * the most specific. Here we rely on compat.c to set up the
93      * sym_interpret array from the most specific to the least specific,
94      * such that when we find a match we return immediately.
95      */
96     darray_foreach(interp, keymap->sym_interpret) {
97         xkb_mod_mask_t mods;
98         bool found;
99
100         if ((num_syms > 1 || interp->sym != syms[0]) &&
101             interp->sym != XKB_KEY_NoSymbol)
102             continue;
103
104         if (level == 0 || !(interp->match & MATCH_LEVEL_ONE_ONLY))
105             mods = key->modmap;
106         else
107             mods = 0;
108
109         switch (interp->match & MATCH_OP_MASK) {
110         case MATCH_NONE:
111             found = !(interp->mods & mods);
112             break;
113         case MATCH_ANY_OR_NONE:
114             found = (!mods || (interp->mods & mods));
115             break;
116         case MATCH_ANY:
117             found = !!(interp->mods & mods);
118             break;
119         case MATCH_ALL:
120             found = ((interp->mods & mods) == interp->mods);
121             break;
122         case MATCH_EXACTLY:
123             found = (interp->mods == mods);
124             break;
125         default:
126             found = false;
127             break;
128         }
129
130         if (found)
131             return interp;
132     }
133
134     return &default_interpret;
135 }
136
137 static bool
138 ApplyInterpsToKey(struct xkb_keymap *keymap, struct xkb_key *key)
139 {
140     xkb_mod_mask_t vmodmap = 0;
141     xkb_layout_index_t group;
142     xkb_level_index_t level;
143
144     /* If we've been told not to bind interps to this key, then don't. */
145     if (key->explicit & EXPLICIT_INTERP)
146         return true;
147
148     for (group = 0; group < key->num_groups; group++) {
149         for (level = 0; level < XkbKeyGroupWidth(key, group); level++) {
150             const struct xkb_sym_interpret *interp;
151
152             interp = FindInterpForKey(keymap, key, group, level);
153             if (!interp)
154                 continue;
155
156             /* Infer default key behaviours from the base level. */
157             if (group == 0 && level == 0)
158                 if (!(key->explicit & EXPLICIT_REPEAT) && interp->repeat)
159                     key->repeats = true;
160
161             if ((group == 0 && level == 0) ||
162                 !(interp->match & MATCH_LEVEL_ONE_ONLY)) {
163                 if (interp->virtual_mod != XKB_MOD_INVALID)
164                     vmodmap |= (1 << interp->virtual_mod);
165             }
166
167             if (interp->act.type != ACTION_TYPE_NONE)
168                 key->groups[group].levels[level].action = interp->act;
169         }
170     }
171
172     if (!(key->explicit & EXPLICIT_VMODMAP))
173         key->vmodmap = vmodmap;
174
175     return true;
176 }
177
178 /**
179  * This collects a bunch of disparate functions which was done in the server
180  * at various points that really should've been done within xkbcomp.  Turns out
181  * your actions and types are a lot more useful when any of your modifiers
182  * other than Shift actually do something ...
183  */
184 static bool
185 UpdateDerivedKeymapFields(struct xkb_keymap *keymap)
186 {
187     struct xkb_mod *mod;
188     struct xkb_indicator_map *im;
189     unsigned int i, j;
190     struct xkb_key *key;
191
192     /* Find all the interprets for the key and bind them to actions,
193      * which will also update the vmodmap. */
194     xkb_foreach_key(key, keymap)
195         if (!ApplyInterpsToKey(keymap, key))
196             return false;
197
198     /* Update keymap->mods, the virtual -> real mod mapping. */
199     xkb_foreach_key(key, keymap)
200         darray_enumerate(i, mod, keymap->mods)
201             if (key->vmodmap & (1 << i))
202                 mod->mapping |= key->modmap;
203
204     /* Now update the level masks for all the types to reflect the vmods. */
205     for (i = 0; i < keymap->num_types; i++) {
206         ComputeEffectiveMask(keymap, &keymap->types[i].mods);
207
208         for (j = 0; j < keymap->types[i].num_entries; j++) {
209             ComputeEffectiveMask(keymap, &keymap->types[i].map[j].mods);
210             ComputeEffectiveMask(keymap, &keymap->types[i].map[j].preserve);
211         }
212     }
213
214     /* Update action modifiers. */
215     xkb_foreach_key(key, keymap)
216         for (i = 0; i < key->num_groups; i++)
217             for (j = 0; j < XkbKeyGroupWidth(key, i); j++)
218                 UpdateActionMods(keymap, &key->groups[i].levels[j].action,
219                                  key->modmap);
220
221     /* Update vmod -> indicator maps. */
222     darray_foreach(im, keymap->indicators)
223         ComputeEffectiveMask(keymap, &im->mods);
224
225     /* Find maximum number of groups out of all keys in the keymap. */
226     xkb_foreach_key(key, keymap)
227         keymap->num_groups = MAX(keymap->num_groups, key->num_groups);
228
229     return true;
230 }
231
232 static bool
233 UpdateBuiltinKeymapFields(struct xkb_keymap *keymap)
234 {
235     struct xkb_context *ctx = keymap->ctx;
236
237     /*
238      * Add predefined (AKA real, core, X11) modifiers.
239      * The order is important!
240      */
241     darray_appends(keymap->mods,
242         { .name = xkb_atom_intern(ctx, "Shift"),   .type = MOD_REAL },
243         { .name = xkb_atom_intern(ctx, "Lock"),    .type = MOD_REAL },
244         { .name = xkb_atom_intern(ctx, "Control"), .type = MOD_REAL },
245         { .name = xkb_atom_intern(ctx, "Mod1"),    .type = MOD_REAL },
246         { .name = xkb_atom_intern(ctx, "Mod2"),    .type = MOD_REAL },
247         { .name = xkb_atom_intern(ctx, "Mod3"),    .type = MOD_REAL },
248         { .name = xkb_atom_intern(ctx, "Mod4"),    .type = MOD_REAL },
249         { .name = xkb_atom_intern(ctx, "Mod5"),    .type = MOD_REAL });
250
251     return true;
252 }
253
254 typedef bool (*compile_file_fn)(XkbFile *file,
255                                 struct xkb_keymap *keymap,
256                                 enum merge_mode merge);
257
258 static const compile_file_fn compile_file_fns[LAST_KEYMAP_FILE_TYPE + 1] = {
259     [FILE_TYPE_KEYCODES] = CompileKeycodes,
260     [FILE_TYPE_TYPES] = CompileKeyTypes,
261     [FILE_TYPE_COMPAT] = CompileCompatMap,
262     [FILE_TYPE_SYMBOLS] = CompileSymbols,
263 };
264
265 bool
266 CompileKeymap(XkbFile *file, struct xkb_keymap *keymap, enum merge_mode merge)
267 {
268     bool ok;
269     const char *main_name;
270     XkbFile *files[LAST_KEYMAP_FILE_TYPE + 1] = { NULL };
271     enum xkb_file_type type;
272     struct xkb_context *ctx = keymap->ctx;
273
274     main_name = file->name ? file->name : "(unnamed)";
275
276     /* Collect section files and check for duplicates. */
277     for (file = (XkbFile *) file->defs; file;
278          file = (XkbFile *) file->common.next) {
279         if (file->file_type < FIRST_KEYMAP_FILE_TYPE ||
280             file->file_type > LAST_KEYMAP_FILE_TYPE) {
281             log_err(ctx, "Cannot define %s in a keymap file\n",
282                     xkb_file_type_to_string(file->file_type));
283             continue;
284         }
285
286         if (files[file->file_type]) {
287             log_err(ctx,
288                     "More than one %s section in keymap file; "
289                     "All sections after the first ignored\n",
290                     xkb_file_type_to_string(file->file_type));
291             continue;
292         }
293
294         if (!file->topName) {
295             free(file->topName);
296             file->topName = strdup(main_name);
297         }
298
299         files[file->file_type] = file;
300     }
301
302     /*
303      * Check that all required section were provided.
304      * Report everything before failing.
305      */
306     ok = true;
307     for (type = FIRST_KEYMAP_FILE_TYPE;
308          type <= LAST_KEYMAP_FILE_TYPE;
309          type++) {
310         if (files[type] == NULL) {
311             log_err(ctx, "Required section %s missing from keymap\n",
312                     xkb_file_type_to_string(type));
313             ok = false;
314         }
315     }
316     if (!ok)
317         return false;
318
319     if (!UpdateBuiltinKeymapFields(keymap))
320         return false;
321
322     /* Compile sections. */
323     for (type = FIRST_KEYMAP_FILE_TYPE;
324          type <= LAST_KEYMAP_FILE_TYPE;
325          type++) {
326         log_dbg(ctx, "Compiling %s \"%s\"\n",
327                 xkb_file_type_to_string(type), files[type]->topName);
328
329         ok = compile_file_fns[type](files[type], keymap, merge);
330         if (!ok) {
331             log_err(ctx, "Failed to compile %s\n",
332                     xkb_file_type_to_string(type));
333             return false;
334         }
335     }
336
337     return UpdateDerivedKeymapFields(keymap);
338 }