2 * Copyright 2009 Dan Nicholson
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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.
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.
27 #include "xkbcomp-priv.h"
30 ComputeEffectiveMask(struct xkb_keymap *keymap, struct xkb_mods *mods)
33 xkb_mod_mask_t vmask = mods->mods >> XkbNumModifiers;
35 /* The effective mask is only real mods for now. */
36 mods->mask = mods->mods & 0xff;
38 for (i = 0; i < XkbNumVirtualMods; i++) {
39 if (!(vmask & (1 << i)))
41 mods->mask |= keymap->vmods[i];
46 UpdateActionMods(struct xkb_keymap *keymap, union xkb_action *act,
47 xkb_mod_mask_t rmodmask)
50 struct xkb_mods *mods;
56 flags = act->mods.flags;
57 mods = &act->mods.mods;
61 flags = act->iso.flags;
62 mods = &act->iso.mods;
69 if (flags & XkbSA_UseModMapMods) {
70 /* XXX: what's that. */
72 mods->mods |= rmodmask;
74 ComputeEffectiveMask(keymap, mods);
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.
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)
86 struct xkb_sym_interpret *ret = NULL;
87 struct xkb_sym_interpret *interp;
88 const xkb_keysym_t *syms;
91 num_syms = xkb_key_get_syms_by_level(keymap, key, group, level, &syms);
95 darray_foreach(interp, keymap->sym_interpret) {
99 if ((num_syms > 1 || interp->sym != syms[0]) &&
100 interp->sym != XKB_KEY_NoSymbol)
103 if (level == 0 || !(interp->match & XkbSI_LevelOneOnly))
108 switch (interp->match & XkbSI_OpMask) {
110 found = !(interp->mods & mods);
112 case XkbSI_AnyOfOrNone:
113 found = (!mods || (interp->mods & mods));
116 found = !!(interp->mods & mods);
119 found = ((interp->mods & mods) == interp->mods);
122 found = (interp->mods == mods);
129 if (found && interp->sym != XKB_KEY_NoSymbol)
131 else if (found && !ret)
139 ApplyInterpsToKey(struct xkb_keymap *keymap, struct xkb_key *key)
141 #define INTERP_SIZE (8 * 4)
142 struct xkb_sym_interpret *interps[INTERP_SIZE];
143 xkb_mod_mask_t vmodmask = 0;
145 xkb_group_index_t group;
146 xkb_level_index_t level;
149 /* If we've been told not to bind interps to this key, then don't. */
150 if (key->explicit & XkbExplicitInterpretMask)
153 for (i = 0; i < INTERP_SIZE; i++)
156 for (group = 0; group < key->num_groups; group++) {
157 for (level = 0; level < XkbKeyGroupWidth(keymap, key, group);
159 i = (group * key->width) + level;
160 if (i >= INTERP_SIZE) /* XXX FIXME */
162 interps[i] = FindInterpForKey(keymap, key, group, level);
168 if (num_acts && !key->actions) {
169 key->actions = calloc(key->num_groups * key->width,
170 sizeof(*key->actions));
175 for (group = 0; group < key->num_groups; group++) {
176 for (level = 0; level < XkbKeyGroupWidth(keymap, key, group);
178 struct xkb_sym_interpret *interp;
180 i = (group * key->width) + level;
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)))
193 if ((group == 0 && level == 0) ||
194 !(interp->match & XkbSI_LevelOneOnly)) {
195 if (interp->virtual_mod != XkbNoModifier)
196 vmodmask |= (1 << interp->virtual_mod);
199 key->actions[i] = interp->act;
203 if (!(key->explicit & XkbExplicitVModMapMask))
204 key->vmodmap = vmodmask;
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 ...
217 UpdateDerivedKeymapFields(struct xkb_keymap *keymap)
219 xkb_mod_index_t vmod;
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))
230 /* Update keymap->vmods, the virtual -> real mod mapping. */
231 for (vmod = 0; vmod < XkbNumVirtualMods; vmod++)
232 keymap->vmods[vmod] = 0;
234 xkb_foreach_key(key, keymap) {
238 for (vmod = 0; vmod < XkbNumVirtualMods; vmod++) {
239 if (!(key->vmodmap & (1 << vmod)))
241 keymap->vmods[vmod] |= key->modmap;
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);
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);
255 /* Update action modifiers. */
256 xkb_foreach_key(key, keymap) {
260 for (i = 0; i < key->num_groups * key->width; i++)
261 UpdateActionMods(keymap, &key->actions[i], key->modmap);
264 /* Update vmod -> indicator maps. */
265 for (led = 0; led < XkbNumIndicators; led++)
266 ComputeEffectiveMask(keymap, &keymap->indicators[led].mods);
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);
275 typedef bool (*compile_file_fn)(XkbFile *file,
276 struct xkb_keymap *keymap,
277 enum merge_mode merge);
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,
287 CompileKeymap(XkbFile *file, struct xkb_keymap *keymap, enum merge_mode merge)
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;
295 main_name = file->name ? file->name : "(unnamed)";
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));
307 if (files[file->file_type]) {
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));
315 if (!file->topName) {
317 file->topName = strdup(main_name);
320 files[file->file_type] = file;
324 * Check that all required section were provided.
325 * Report everything before failing.
328 for (type = FIRST_KEYMAP_FILE_TYPE;
329 type <= LAST_KEYMAP_FILE_TYPE;
331 if (files[type] == NULL) {
332 log_err(ctx, "Required section %s missing from keymap\n",
333 xkb_file_type_to_string(type));
340 /* Compile sections. */
341 for (type = FIRST_KEYMAP_FILE_TYPE;
342 type <= LAST_KEYMAP_FILE_TYPE;
344 log_dbg(ctx, "Compiling %s \"%s\"\n",
345 xkb_file_type_to_string(type), files[type]->topName);
347 ok = compile_file_fns[type](files[type], keymap, merge);
349 log_err(ctx, "Failed to compile %s\n",
350 xkb_file_type_to_string(type));
355 return UpdateDerivedKeymapFields(keymap);