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)
36 xkb_mod_mask_t vmask = mods->mods >> XKB_NUM_CORE_MODS;
38 /* The effective mask is only real mods for now. */
39 mods->mask = mods->mods & 0xff;
41 for (i = 0; i < XKB_NUM_VIRTUAL_MODS; i++) {
42 if (!(vmask & (1 << i)))
44 mods->mask |= keymap->vmods[i];
49 UpdateActionMods(struct xkb_keymap *keymap, union xkb_action *act,
50 xkb_mod_mask_t rmodmask)
53 struct xkb_mods *mods;
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;
67 if (flags & ACTION_MODS_LOOKUP_MODMAP) {
68 /* XXX: what's that. */
70 mods->mods |= rmodmask;
72 ComputeEffectiveMask(keymap, mods);
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.
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)
84 struct xkb_sym_interpret *interp;
85 const xkb_keysym_t *syms;
88 num_syms = xkb_key_get_syms_by_level(keymap, key, group, level, &syms);
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.
98 darray_foreach(interp, keymap->sym_interpret) {
102 if ((num_syms > 1 || interp->sym != syms[0]) &&
103 interp->sym != XKB_KEY_NoSymbol)
106 if (level == 0 || !(interp->match & MATCH_LEVEL_ONE_ONLY))
111 switch (interp->match & MATCH_OP_MASK) {
113 found = !(interp->mods & mods);
115 case MATCH_ANY_OR_NONE:
116 found = (!mods || (interp->mods & mods));
119 found = !!(interp->mods & mods);
122 found = ((interp->mods & mods) == interp->mods);
125 found = (interp->mods == mods);
140 ApplyInterpsToKey(struct xkb_keymap *keymap, struct xkb_key *key)
142 xkb_mod_mask_t vmodmask = 0;
143 xkb_group_index_t group;
144 xkb_level_index_t width, level;
146 /* If we've been told not to bind interps to this key, then don't. */
147 if (key->explicit & EXPLICIT_INTERP)
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;
155 interp = FindInterpForKey(keymap, key, group, level);
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))
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);
173 if (interp->act.type != ACTION_TYPE_NONE) {
175 key->actions = calloc(key->num_groups * key->width,
176 sizeof(*key->actions));
181 *XkbKeyActionEntry(key, group, level) = interp->act;
186 if (!(key->explicit & EXPLICIT_VMODMAP))
187 key->vmodmap = vmodmask;
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 ...
199 UpdateDerivedKeymapFields(struct xkb_keymap *keymap)
201 xkb_mod_index_t vmod;
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))
212 /* Update keymap->vmods, the virtual -> real mod mapping. */
213 for (vmod = 0; vmod < XKB_NUM_VIRTUAL_MODS; vmod++)
214 keymap->vmods[vmod] = 0;
216 xkb_foreach_key(key, keymap) {
220 for (vmod = 0; vmod < XKB_NUM_VIRTUAL_MODS; vmod++) {
221 if (!(key->vmodmap & (1 << vmod)))
223 keymap->vmods[vmod] |= key->modmap;
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);
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);
237 /* Update action modifiers. */
238 xkb_foreach_key(key, keymap) {
242 for (i = 0; i < key->num_groups * key->width; i++)
243 UpdateActionMods(keymap, &key->actions[i], key->modmap);
246 /* Update vmod -> indicator maps. */
247 for (led = 0; led < XKB_NUM_INDICATORS; led++)
248 ComputeEffectiveMask(keymap, &keymap->indicators[led].mods);
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);
257 typedef bool (*compile_file_fn)(XkbFile *file,
258 struct xkb_keymap *keymap,
259 enum merge_mode merge);
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,
269 CompileKeymap(XkbFile *file, struct xkb_keymap *keymap, enum merge_mode merge)
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;
277 main_name = file->name ? file->name : "(unnamed)";
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));
289 if (files[file->file_type]) {
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));
297 if (!file->topName) {
299 file->topName = strdup(main_name);
302 files[file->file_type] = file;
306 * Check that all required section were provided.
307 * Report everything before failing.
310 for (type = FIRST_KEYMAP_FILE_TYPE;
311 type <= LAST_KEYMAP_FILE_TYPE;
313 if (files[type] == NULL) {
314 log_err(ctx, "Required section %s missing from keymap\n",
315 xkb_file_type_to_string(type));
322 /* Compile sections. */
323 for (type = FIRST_KEYMAP_FILE_TYPE;
324 type <= LAST_KEYMAP_FILE_TYPE;
326 log_dbg(ctx, "Compiling %s \"%s\"\n",
327 xkb_file_type_to_string(type), files[type]->topName);
329 ok = compile_file_fns[type](files[type], keymap, merge);
331 log_err(ctx, "Failed to compile %s\n",
332 xkb_file_type_to_string(type));
337 return UpdateDerivedKeymapFields(keymap);