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