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
32static void
33ComputeEffectiveMask(struct xkb_keymap *keymap, struct xkb_mods *mods)
34{
35    mods->mask = mod_mask_get_effective(keymap, mods->mods);
36}
37
38static void
39UpdateActionMods(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
55static 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 */
69static const struct xkb_sym_interpret *
70FindInterpForKey(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
127static bool
128ApplyInterpsToKey(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 */
172static bool
173UpdateDerivedKeymapFields(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
220typedef bool (*compile_file_fn)(XkbFile *file,
221                                struct xkb_keymap *keymap,
222                                enum merge_mode merge);
223
224static 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
231bool
232CompileKeymap(XkbFile *file, struct xkb_keymap *keymap, enum merge_mode merge)
233{
234    bool ok;
235    const char *main_name;
236    XkbFile *files[LAST_KEYMAP_FILE_TYPE + 1] = { NULL };
237    enum xkb_file_type type;
238    struct xkb_context *ctx = keymap->ctx;
239
240    main_name = file->name ? file->name : "(unnamed)";
241
242    /* Collect section files and check for duplicates. */
243    for (file = (XkbFile *) file->defs; file;
244         file = (XkbFile *) file->common.next) {
245        if (file->file_type < FIRST_KEYMAP_FILE_TYPE ||
246            file->file_type > LAST_KEYMAP_FILE_TYPE) {
247            log_err(ctx, "Cannot define %s in a keymap file\n",
248                    xkb_file_type_to_string(file->file_type));
249            continue;
250        }
251
252        if (files[file->file_type]) {
253            log_err(ctx,
254                    "More than one %s section in keymap file; "
255                    "All sections after the first ignored\n",
256                    xkb_file_type_to_string(file->file_type));
257            continue;
258        }
259
260        if (!file->topName) {
261            free(file->topName);
262            file->topName = strdup(main_name);
263        }
264
265        files[file->file_type] = file;
266    }
267
268    /*
269     * Check that all required section were provided.
270     * Report everything before failing.
271     */
272    ok = true;
273    for (type = FIRST_KEYMAP_FILE_TYPE;
274         type <= LAST_KEYMAP_FILE_TYPE;
275         type++) {
276        if (files[type] == NULL) {
277            log_err(ctx, "Required section %s missing from keymap\n",
278                    xkb_file_type_to_string(type));
279            ok = false;
280        }
281    }
282    if (!ok)
283        return false;
284
285    /* Compile sections. */
286    for (type = FIRST_KEYMAP_FILE_TYPE;
287         type <= LAST_KEYMAP_FILE_TYPE;
288         type++) {
289        log_dbg(ctx, "Compiling %s \"%s\"\n",
290                xkb_file_type_to_string(type), files[type]->topName);
291
292        ok = compile_file_fns[type](files[type], keymap, merge);
293        if (!ok) {
294            log_err(ctx, "Failed to compile %s\n",
295                    xkb_file_type_to_string(type));
296            return false;
297        }
298    }
299
300    return UpdateDerivedKeymapFields(keymap);
301}
302