Add xkbcomp/keymap.c and move some code there
[platform/upstream/libxkbcommon.git] / src / xkbcomp / keymap.c
1 /*
2  * Copyright 2009  Dan Nicholson
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
18  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20  *
21  * Except as contained in this notice, the names of the authors or their
22  * institutions shall not be used in advertising or otherwise to promote the
23  * sale, use or other dealings in this Software without prior written
24  * authorization from the authors.
25  */
26
27 #include "xkbcomp-priv.h"
28
29 static void
30 ComputeEffectiveMask(struct xkb_keymap *keymap, struct xkb_mods *mods)
31 {
32     xkb_mod_index_t i;
33     xkb_mod_mask_t vmask = mods->mods >> XkbNumModifiers;
34
35     /* The effective mask is only real mods for now. */
36     mods->mask = mods->mods & 0xff;
37
38     for (i = 0; i < XkbNumVirtualMods; i++) {
39         if (!(vmask & (1 << i)))
40             continue;
41         mods->mask |= keymap->vmods[i];
42     }
43 }
44
45 static void
46 UpdateActionMods(struct xkb_keymap *keymap, union xkb_action *act,
47                  xkb_mod_mask_t rmodmask)
48 {
49     unsigned int flags;
50     struct xkb_mods *mods;
51
52     switch (act->type) {
53     case XkbSA_SetMods:
54     case XkbSA_LatchMods:
55     case XkbSA_LockMods:
56         flags = act->mods.flags;
57         mods = &act->mods.mods;
58         break;
59
60     case XkbSA_ISOLock:
61         flags = act->iso.flags;
62         mods = &act->iso.mods;
63         break;
64
65     default:
66         return;
67     }
68
69     if (flags & XkbSA_UseModMapMods) {
70         /* XXX: what's that. */
71         mods->mods &= 0xff;
72         mods->mods |= rmodmask;
73     }
74     ComputeEffectiveMask(keymap, mods);
75 }
76
77 /**
78  * Find an interpretation which applies to this particular level, either by
79  * finding an exact match for the symbol and modifier combination, or a
80  * generic XKB_KEY_NoSymbol match.
81  */
82 static struct xkb_sym_interpret *
83 FindInterpForKey(struct xkb_keymap *keymap, struct xkb_key *key,
84                  xkb_group_index_t group, xkb_level_index_t level)
85 {
86     struct xkb_sym_interpret *ret = NULL;
87     struct xkb_sym_interpret *interp;
88     const xkb_keysym_t *syms;
89     int num_syms;
90
91     num_syms = xkb_key_get_syms_by_level(keymap, key, group, level, &syms);
92     if (num_syms == 0)
93         return NULL;
94
95     darray_foreach(interp, keymap->sym_interpret) {
96         uint32_t mods;
97         bool found;
98
99         if ((num_syms > 1 || interp->sym != syms[0]) &&
100             interp->sym != XKB_KEY_NoSymbol)
101             continue;
102
103         if (level == 0 || !(interp->match & XkbSI_LevelOneOnly))
104             mods = key->modmap;
105         else
106             mods = 0;
107
108         switch (interp->match & XkbSI_OpMask) {
109         case XkbSI_NoneOf:
110             found = !(interp->mods & mods);
111             break;
112         case XkbSI_AnyOfOrNone:
113             found = (!mods || (interp->mods & mods));
114             break;
115         case XkbSI_AnyOf:
116             found = !!(interp->mods & mods);
117             break;
118         case XkbSI_AllOf:
119             found = ((interp->mods & mods) == interp->mods);
120             break;
121         case XkbSI_Exactly:
122             found = (interp->mods == mods);
123             break;
124         default:
125             found = false;
126             break;
127         }
128
129         if (found && interp->sym != XKB_KEY_NoSymbol)
130             return interp;
131         else if (found && !ret)
132             ret = interp;
133     }
134
135     return ret;
136 }
137
138 static bool
139 ApplyInterpsToKey(struct xkb_keymap *keymap, struct xkb_key *key)
140 {
141 #define INTERP_SIZE (8 * 4)
142     struct xkb_sym_interpret *interps[INTERP_SIZE];
143     xkb_mod_mask_t vmodmask = 0;
144     int num_acts = 0;
145     xkb_group_index_t group;
146     xkb_level_index_t level;
147     unsigned int i;
148
149     /* If we've been told not to bind interps to this key, then don't. */
150     if (key->explicit & XkbExplicitInterpretMask)
151         return true;
152
153     for (i = 0; i < INTERP_SIZE; i++)
154         interps[i] = NULL;
155
156     for (group = 0; group < key->num_groups; group++) {
157         for (level = 0; level < XkbKeyGroupWidth(keymap, key, group);
158              level++) {
159             i = (group * key->width) + level;
160             if (i >= INTERP_SIZE) /* XXX FIXME */
161                 return false;
162             interps[i] = FindInterpForKey(keymap, key, group, level);
163             if (interps[i])
164                 num_acts++;
165         }
166     }
167
168     if (num_acts && !key->actions) {
169         key->actions = calloc(key->num_groups * key->width,
170                               sizeof(*key->actions));
171         if (!key->actions)
172             return false;
173     }
174
175     for (group = 0; group < key->num_groups; group++) {
176         for (level = 0; level < XkbKeyGroupWidth(keymap, key, group);
177              level++) {
178             struct xkb_sym_interpret *interp;
179
180             i = (group * key->width) + level;
181             interp = interps[i];
182
183             /* Infer default key behaviours from the base level. */
184             if (group == 0 && level == 0) {
185                 if (!(key->explicit & XkbExplicitAutoRepeatMask) &&
186                     (!interp || (interp->flags & XkbSI_AutoRepeat)))
187                     key->repeats = true;
188             }
189
190             if (!interp)
191                 continue;
192
193             if ((group == 0 && level == 0) ||
194                 !(interp->match & XkbSI_LevelOneOnly)) {
195                 if (interp->virtual_mod != XkbNoModifier)
196                     vmodmask |= (1 << interp->virtual_mod);
197             }
198
199             key->actions[i] = interp->act;
200         }
201     }
202
203     if (!(key->explicit & XkbExplicitVModMapMask))
204         key->vmodmap = vmodmask;
205
206     return true;
207 #undef INTERP_SIZE
208 }
209
210 /**
211  * This collects a bunch of disparate functions which was done in the server
212  * at various points that really should've been done within xkbcomp.  Turns out
213  * your actions and types are a lot more useful when any of your modifiers
214  * other than Shift actually do something ...
215  */
216 static bool
217 UpdateDerivedKeymapFields(struct xkb_keymap *keymap)
218 {
219     xkb_mod_index_t vmod;
220     xkb_led_index_t led;
221     unsigned int i, j;
222     struct xkb_key *key;
223
224     /* Find all the interprets for the key and bind them to actions,
225      * which will also update the vmodmap. */
226     xkb_foreach_key(key, keymap)
227         if (!ApplyInterpsToKey(keymap, key))
228             return false;
229
230     /* Update keymap->vmods, the virtual -> real mod mapping. */
231     for (vmod = 0; vmod < XkbNumVirtualMods; vmod++)
232         keymap->vmods[vmod] = 0;
233
234     xkb_foreach_key(key, keymap) {
235         if (!key->vmodmap)
236             continue;
237
238         for (vmod = 0; vmod < XkbNumVirtualMods; vmod++) {
239             if (!(key->vmodmap & (1 << vmod)))
240                 continue;
241             keymap->vmods[vmod] |= key->modmap;
242         }
243     }
244
245     /* Now update the level masks for all the types to reflect the vmods. */
246     for (i = 0; i < keymap->num_types; i++) {
247         ComputeEffectiveMask(keymap, &keymap->types[i].mods);
248
249         for (j = 0; j < keymap->types[i].num_entries; j++) {
250             ComputeEffectiveMask(keymap, &keymap->types[i].map[j].mods);
251             ComputeEffectiveMask(keymap, &keymap->types[i].map[j].preserve);
252         }
253     }
254
255     /* Update action modifiers. */
256     xkb_foreach_key(key, keymap) {
257         if (!key->actions)
258             continue;
259
260         for (i = 0; i < key->num_groups * key->width; i++)
261             UpdateActionMods(keymap, &key->actions[i], key->modmap);
262     }
263
264     /* Update vmod -> indicator maps. */
265     for (led = 0; led < XkbNumIndicators; led++)
266         ComputeEffectiveMask(keymap, &keymap->indicators[led].mods);
267
268     /* Find maximum number of groups out of all keys in the keymap. */
269     xkb_foreach_key(key, keymap)
270         keymap->num_groups = MAX(keymap->num_groups, key->num_groups);
271
272     return true;
273 }
274
275 typedef bool (*compile_file_fn)(XkbFile *file,
276                                 struct xkb_keymap *keymap,
277                                 enum merge_mode merge);
278
279 static const compile_file_fn compile_file_fns[LAST_KEYMAP_FILE_TYPE + 1] = {
280     [FILE_TYPE_KEYCODES] = CompileKeycodes,
281     [FILE_TYPE_TYPES] = CompileKeyTypes,
282     [FILE_TYPE_COMPAT] = CompileCompatMap,
283     [FILE_TYPE_SYMBOLS] = CompileSymbols,
284 };
285
286 bool
287 CompileKeymap(XkbFile *file, struct xkb_keymap *keymap, enum merge_mode merge)
288 {
289     bool ok;
290     const char *main_name;
291     XkbFile *files[LAST_KEYMAP_FILE_TYPE + 1] = { NULL };
292     enum xkb_file_type type;
293     struct xkb_context *ctx = keymap->ctx;
294
295     main_name = file->name ? file->name : "(unnamed)";
296
297     /* Collect section files and check for duplicates. */
298     for (file = (XkbFile *) file->defs; file;
299          file = (XkbFile *) file->common.next) {
300         if (file->file_type < FIRST_KEYMAP_FILE_TYPE ||
301             file->file_type > LAST_KEYMAP_FILE_TYPE) {
302             log_err(ctx, "Cannot define %s in a keymap file\n",
303                     xkb_file_type_to_string(file->file_type));
304             continue;
305         }
306
307         if (files[file->file_type]) {
308             log_err(ctx,
309                     "More than one %s section in keymap file; "
310                     "All sections after the first ignored\n",
311                     xkb_file_type_to_string(file->file_type));
312             continue;
313         }
314
315         if (!file->topName) {
316             free(file->topName);
317             file->topName = strdup(main_name);
318         }
319
320         files[file->file_type] = file;
321     }
322
323     /*
324      * Check that all required section were provided.
325      * Report everything before failing.
326      */
327     ok = true;
328     for (type = FIRST_KEYMAP_FILE_TYPE;
329          type <= LAST_KEYMAP_FILE_TYPE;
330          type++) {
331         if (files[type] == NULL) {
332             log_err(ctx, "Required section %s missing from keymap\n",
333                     xkb_file_type_to_string(type));
334             ok = false;
335         }
336     }
337     if (!ok)
338         return false;
339
340     /* Compile sections. */
341     for (type = FIRST_KEYMAP_FILE_TYPE;
342          type <= LAST_KEYMAP_FILE_TYPE;
343          type++) {
344         log_dbg(ctx, "Compiling %s \"%s\"\n",
345                 xkb_file_type_to_string(type), files[type]->topName);
346
347         ok = compile_file_fns[type](files[type], keymap, merge);
348         if (!ok) {
349             log_err(ctx, "Failed to compile %s\n",
350                     xkb_file_type_to_string(type));
351             return false;
352         }
353     }
354
355     return UpdateDerivedKeymapFields(keymap);
356 }