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