2 * Copyright © 2009 Dan Nicholson
3 * Copyright © 2012 Intel Corporation
4 * Copyright © 2012 Ran Benita <ran234@gmail.com>
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:
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
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.
25 * Author: Dan Nicholson <dbn.lists@gmail.com>
26 * Daniel Stone <daniel@fooishbar.org>
27 * Ran Benita <ran234@gmail.com>
30 #include "xkbcomp-priv.h"
33 ComputeEffectiveMask(struct xkb_keymap *keymap, struct xkb_mods *mods)
35 const struct xkb_mod *mod;
38 /* The effective mask is only real mods for now. */
39 mods->mask = mods->mods & MOD_REAL_MASK_ALL;
41 darray_enumerate(i, mod, keymap->mods)
42 if (mods->mods & (1 << i))
43 mods->mask |= mod->mapping;
47 UpdateActionMods(struct xkb_keymap *keymap, union xkb_action *act,
48 xkb_mod_mask_t modmap)
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);
63 static const struct xkb_sym_interpret default_interpret = {
64 .sym = XKB_KEY_NoSymbol,
66 .match = MATCH_ANY_OR_NONE,
68 .virtual_mod = XKB_MOD_INVALID,
69 .action = { .type = ACTION_TYPE_NONE },
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.
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)
81 const struct xkb_sym_interpret *interp;
82 const xkb_keysym_t *syms;
85 num_syms = xkb_keymap_key_get_syms_by_level(keymap, key->keycode, group,
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_interprets array from the most specific to the least specific,
94 * such that when we find a match we return immediately.
96 darray_foreach(interp, keymap->sym_interprets) {
100 if ((num_syms > 1 || interp->sym != syms[0]) &&
101 interp->sym != XKB_KEY_NoSymbol)
104 if (interp->level_one_only && level != 0)
109 switch (interp->match) {
111 found = !(interp->mods & mods);
113 case MATCH_ANY_OR_NONE:
114 found = (!mods || (interp->mods & mods));
117 found = !!(interp->mods & mods);
120 found = ((interp->mods & mods) == interp->mods);
123 found = (interp->mods == mods);
131 return &default_interpret;
135 ApplyInterpsToKey(struct xkb_keymap *keymap, struct xkb_key *key)
137 xkb_mod_mask_t vmodmap = 0;
138 xkb_layout_index_t group;
139 xkb_level_index_t level;
141 /* If we've been told not to bind interps to this key, then don't. */
142 if (key->explicit & EXPLICIT_INTERP)
145 for (group = 0; group < key->num_groups; group++) {
146 for (level = 0; level < XkbKeyGroupWidth(key, group); level++) {
147 const struct xkb_sym_interpret *interp;
149 interp = FindInterpForKey(keymap, key, group, level);
153 /* Infer default key behaviours from the base level. */
154 if (group == 0 && level == 0)
155 if (!(key->explicit & EXPLICIT_REPEAT) && interp->repeat)
158 if ((group == 0 && level == 0) || !interp->level_one_only)
159 if (interp->virtual_mod != XKB_MOD_INVALID)
160 vmodmap |= (1 << interp->virtual_mod);
162 if (interp->action.type != ACTION_TYPE_NONE)
163 key->groups[group].levels[level].action = interp->action;
167 if (!(key->explicit & EXPLICIT_VMODMAP))
168 key->vmodmap = vmodmap;
174 * This collects a bunch of disparate functions which was done in the server
175 * at various points that really should've been done within xkbcomp. Turns out
176 * your actions and types are a lot more useful when any of your modifiers
177 * other than Shift actually do something ...
180 UpdateDerivedKeymapFields(struct xkb_keymap *keymap)
187 /* Find all the interprets for the key and bind them to actions,
188 * which will also update the vmodmap. */
189 xkb_foreach_key(key, keymap)
190 if (!ApplyInterpsToKey(keymap, key))
193 /* Update keymap->mods, the virtual -> real mod mapping. */
194 xkb_foreach_key(key, keymap)
195 darray_enumerate(i, mod, keymap->mods)
196 if (key->vmodmap & (1 << i))
197 mod->mapping |= key->modmap;
199 /* Now update the level masks for all the types to reflect the vmods. */
200 for (i = 0; i < keymap->num_types; i++) {
201 ComputeEffectiveMask(keymap, &keymap->types[i].mods);
203 for (j = 0; j < keymap->types[i].num_entries; j++) {
204 ComputeEffectiveMask(keymap, &keymap->types[i].map[j].mods);
205 ComputeEffectiveMask(keymap, &keymap->types[i].map[j].preserve);
209 /* Update action modifiers. */
210 xkb_foreach_key(key, keymap)
211 for (i = 0; i < key->num_groups; i++)
212 for (j = 0; j < XkbKeyGroupWidth(key, i); j++)
213 UpdateActionMods(keymap, &key->groups[i].levels[j].action,
216 /* Update vmod -> led maps. */
217 darray_foreach(led, keymap->leds)
218 ComputeEffectiveMask(keymap, &led->mods);
220 /* Find maximum number of groups out of all keys in the keymap. */
221 xkb_foreach_key(key, keymap)
222 keymap->num_groups = MAX(keymap->num_groups, key->num_groups);
228 UpdateBuiltinKeymapFields(struct xkb_keymap *keymap)
230 struct xkb_context *ctx = keymap->ctx;
233 * Add predefined (AKA real, core, X11) modifiers.
234 * The order is important!
236 darray_appends_t(keymap->mods, struct xkb_mod,
237 { .name = xkb_atom_intern(ctx, "Shift"), .type = MOD_REAL },
238 { .name = xkb_atom_intern(ctx, "Lock"), .type = MOD_REAL },
239 { .name = xkb_atom_intern(ctx, "Control"), .type = MOD_REAL },
240 { .name = xkb_atom_intern(ctx, "Mod1"), .type = MOD_REAL },
241 { .name = xkb_atom_intern(ctx, "Mod2"), .type = MOD_REAL },
242 { .name = xkb_atom_intern(ctx, "Mod3"), .type = MOD_REAL },
243 { .name = xkb_atom_intern(ctx, "Mod4"), .type = MOD_REAL },
244 { .name = xkb_atom_intern(ctx, "Mod5"), .type = MOD_REAL });
249 typedef bool (*compile_file_fn)(XkbFile *file,
250 struct xkb_keymap *keymap,
251 enum merge_mode merge);
253 static const compile_file_fn compile_file_fns[LAST_KEYMAP_FILE_TYPE + 1] = {
254 [FILE_TYPE_KEYCODES] = CompileKeycodes,
255 [FILE_TYPE_TYPES] = CompileKeyTypes,
256 [FILE_TYPE_COMPAT] = CompileCompatMap,
257 [FILE_TYPE_SYMBOLS] = CompileSymbols,
261 CompileKeymap(XkbFile *file, struct xkb_keymap *keymap, enum merge_mode merge)
264 const char *main_name;
265 XkbFile *files[LAST_KEYMAP_FILE_TYPE + 1] = { NULL };
266 enum xkb_file_type type;
267 struct xkb_context *ctx = keymap->ctx;
269 main_name = file->name ? file->name : "(unnamed)";
271 /* Collect section files and check for duplicates. */
272 for (file = (XkbFile *) file->defs; file;
273 file = (XkbFile *) file->common.next) {
274 if (file->file_type < FIRST_KEYMAP_FILE_TYPE ||
275 file->file_type > LAST_KEYMAP_FILE_TYPE) {
276 log_err(ctx, "Cannot define %s in a keymap file\n",
277 xkb_file_type_to_string(file->file_type));
281 if (files[file->file_type]) {
283 "More than one %s section in keymap file; "
284 "All sections after the first ignored\n",
285 xkb_file_type_to_string(file->file_type));
289 if (!file->topName) {
291 file->topName = strdup(main_name);
294 files[file->file_type] = file;
298 * Check that all required section were provided.
299 * Report everything before failing.
302 for (type = FIRST_KEYMAP_FILE_TYPE;
303 type <= LAST_KEYMAP_FILE_TYPE;
305 if (files[type] == NULL) {
306 log_err(ctx, "Required section %s missing from keymap\n",
307 xkb_file_type_to_string(type));
314 if (!UpdateBuiltinKeymapFields(keymap))
317 /* Compile sections. */
318 for (type = FIRST_KEYMAP_FILE_TYPE;
319 type <= LAST_KEYMAP_FILE_TYPE;
321 log_dbg(ctx, "Compiling %s \"%s\"\n",
322 xkb_file_type_to_string(type), files[type]->topName);
324 ok = compile_file_fns[type](files[type], keymap, merge);
326 log_err(ctx, "Failed to compile %s\n",
327 xkb_file_type_to_string(type));
332 return UpdateDerivedKeymapFields(keymap);