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 "config.h"
31
32 #include "xkbcomp-priv.h"
33
34 static void
ComputeEffectiveMask(struct xkb_keymap * keymap,struct xkb_mods * mods)35 ComputeEffectiveMask(struct xkb_keymap *keymap, struct xkb_mods *mods)
36 {
37 mods->mask = mod_mask_get_effective(keymap, mods->mods);
38 }
39
40 static void
UpdateActionMods(struct xkb_keymap * keymap,union xkb_action * act,xkb_mod_mask_t modmap)41 UpdateActionMods(struct xkb_keymap *keymap, union xkb_action *act,
42 xkb_mod_mask_t modmap)
43 {
44 switch (act->type) {
45 case ACTION_TYPE_MOD_SET:
46 case ACTION_TYPE_MOD_LATCH:
47 case ACTION_TYPE_MOD_LOCK:
48 if (act->mods.flags & ACTION_MODS_LOOKUP_MODMAP)
49 act->mods.mods.mods = modmap;
50 ComputeEffectiveMask(keymap, &act->mods.mods);
51 break;
52 default:
53 break;
54 }
55 }
56
57 static const struct xkb_sym_interpret default_interpret = {
58 .sym = XKB_KEY_NoSymbol,
59 .repeat = true,
60 .match = MATCH_ANY_OR_NONE,
61 .mods = 0,
62 .virtual_mod = XKB_MOD_INVALID,
63 .action = { .type = ACTION_TYPE_NONE },
64 };
65
66 /**
67 * Find an interpretation which applies to this particular level, either by
68 * finding an exact match for the symbol and modifier combination, or a
69 * generic XKB_KEY_NoSymbol match.
70 */
71 static const struct xkb_sym_interpret *
FindInterpForKey(struct xkb_keymap * keymap,const struct xkb_key * key,xkb_layout_index_t group,xkb_level_index_t level)72 FindInterpForKey(struct xkb_keymap *keymap, const struct xkb_key *key,
73 xkb_layout_index_t group, xkb_level_index_t level)
74 {
75 const xkb_keysym_t *syms;
76 int num_syms;
77
78 num_syms = xkb_keymap_key_get_syms_by_level(keymap, key->keycode, group,
79 level, &syms);
80 if (num_syms == 0)
81 return NULL;
82
83 /*
84 * There may be multiple matchings interprets; we should always return
85 * the most specific. Here we rely on compat.c to set up the
86 * sym_interprets array from the most specific to the least specific,
87 * such that when we find a match we return immediately.
88 */
89 for (unsigned i = 0; i < keymap->num_sym_interprets; i++) {
90 const struct xkb_sym_interpret *interp = &keymap->sym_interprets[i];
91
92 xkb_mod_mask_t mods;
93 bool found = false;
94
95 if ((num_syms > 1 || interp->sym != syms[0]) &&
96 interp->sym != XKB_KEY_NoSymbol)
97 continue;
98
99 if (interp->level_one_only && level != 0)
100 mods = 0;
101 else
102 mods = key->modmap;
103
104 switch (interp->match) {
105 case MATCH_NONE:
106 found = !(interp->mods & mods);
107 break;
108 case MATCH_ANY_OR_NONE:
109 found = (!mods || (interp->mods & mods));
110 break;
111 case MATCH_ANY:
112 found = (interp->mods & mods);
113 break;
114 case MATCH_ALL:
115 found = ((interp->mods & mods) == interp->mods);
116 break;
117 case MATCH_EXACTLY:
118 found = (interp->mods == mods);
119 break;
120 }
121
122 if (found)
123 return interp;
124 }
125
126 return &default_interpret;
127 }
128
129 static bool
ApplyInterpsToKey(struct xkb_keymap * keymap,struct xkb_key * key)130 ApplyInterpsToKey(struct xkb_keymap *keymap, struct xkb_key *key)
131 {
132 xkb_mod_mask_t vmodmap = 0;
133 xkb_layout_index_t group;
134 xkb_level_index_t level;
135
136 /* If we've been told not to bind interps to this key, then don't. */
137 if (key->explicit & EXPLICIT_INTERP)
138 return true;
139
140 for (group = 0; group < key->num_groups; group++) {
141 for (level = 0; level < XkbKeyNumLevels(key, group); level++) {
142 const struct xkb_sym_interpret *interp;
143
144 interp = FindInterpForKey(keymap, key, group, level);
145 if (!interp)
146 continue;
147
148 /* Infer default key behaviours from the base level. */
149 if (group == 0 && level == 0)
150 if (!(key->explicit & EXPLICIT_REPEAT) && interp->repeat)
151 key->repeats = true;
152
153 if ((group == 0 && level == 0) || !interp->level_one_only)
154 if (interp->virtual_mod != XKB_MOD_INVALID)
155 vmodmap |= (1u << interp->virtual_mod);
156
157 if (interp->action.type != ACTION_TYPE_NONE)
158 key->groups[group].levels[level].action = interp->action;
159 }
160 }
161
162 if (!(key->explicit & EXPLICIT_VMODMAP))
163 key->vmodmap = vmodmap;
164
165 return true;
166 }
167
168 /**
169 * This collects a bunch of disparate functions which was done in the server
170 * at various points that really should've been done within xkbcomp. Turns out
171 * your actions and types are a lot more useful when any of your modifiers
172 * other than Shift actually do something ...
173 */
174 static bool
UpdateDerivedKeymapFields(struct xkb_keymap * keymap)175 UpdateDerivedKeymapFields(struct xkb_keymap *keymap)
176 {
177 struct xkb_key *key;
178 struct xkb_mod *mod;
179 struct xkb_led *led;
180 unsigned int i, j;
181
182 /* Find all the interprets for the key and bind them to actions,
183 * which will also update the vmodmap. */
184 xkb_keys_foreach(key, keymap)
185 if (!ApplyInterpsToKey(keymap, key))
186 return false;
187
188 /* Update keymap->mods, the virtual -> real mod mapping. */
189 xkb_keys_foreach(key, keymap)
190 xkb_mods_enumerate(i, mod, &keymap->mods)
191 if (key->vmodmap & (1u << i))
192 mod->mapping |= key->modmap;
193
194 /* Now update the level masks for all the types to reflect the vmods. */
195 for (i = 0; i < keymap->num_types; i++) {
196 ComputeEffectiveMask(keymap, &keymap->types[i].mods);
197
198 for (j = 0; j < keymap->types[i].num_entries; j++) {
199 ComputeEffectiveMask(keymap, &keymap->types[i].entries[j].mods);
200 ComputeEffectiveMask(keymap, &keymap->types[i].entries[j].preserve);
201 }
202 }
203
204 /* Update action modifiers. */
205 xkb_keys_foreach(key, keymap)
206 for (i = 0; i < key->num_groups; i++)
207 for (j = 0; j < XkbKeyNumLevels(key, i); j++)
208 UpdateActionMods(keymap, &key->groups[i].levels[j].action,
209 key->modmap);
210
211 /* Update vmod -> led maps. */
212 xkb_leds_foreach(led, keymap)
213 ComputeEffectiveMask(keymap, &led->mods);
214
215 /* Find maximum number of groups out of all keys in the keymap. */
216 xkb_keys_foreach(key, keymap)
217 keymap->num_groups = MAX(keymap->num_groups, key->num_groups);
218
219 return true;
220 }
221
222 typedef bool (*compile_file_fn)(XkbFile *file,
223 struct xkb_keymap *keymap,
224 enum merge_mode merge);
225
226 static const compile_file_fn compile_file_fns[LAST_KEYMAP_FILE_TYPE + 1] = {
227 [FILE_TYPE_KEYCODES] = CompileKeycodes,
228 [FILE_TYPE_TYPES] = CompileKeyTypes,
229 [FILE_TYPE_COMPAT] = CompileCompatMap,
230 [FILE_TYPE_SYMBOLS] = CompileSymbols,
231 };
232
233 bool
CompileKeymap(XkbFile * file,struct xkb_keymap * keymap,enum merge_mode merge)234 CompileKeymap(XkbFile *file, struct xkb_keymap *keymap, enum merge_mode merge)
235 {
236 bool ok;
237 XkbFile *files[LAST_KEYMAP_FILE_TYPE + 1] = { NULL };
238 enum xkb_file_type type;
239 struct xkb_context *ctx = keymap->ctx;
240
241 /* Collect section files and check for duplicates. */
242 for (file = (XkbFile *) file->defs; file;
243 file = (XkbFile *) file->common.next) {
244 if (file->file_type < FIRST_KEYMAP_FILE_TYPE ||
245 file->file_type > LAST_KEYMAP_FILE_TYPE) {
246 if (file->file_type == FILE_TYPE_GEOMETRY) {
247 log_vrb(ctx, 1,
248 "Geometry sections are not supported; ignoring\n");
249 } else {
250 log_err(ctx, "Cannot define %s in a keymap file\n",
251 xkb_file_type_to_string(file->file_type));
252 }
253 continue;
254 }
255
256 if (files[file->file_type]) {
257 log_err(ctx,
258 "More than one %s section in keymap file; "
259 "All sections after the first ignored\n",
260 xkb_file_type_to_string(file->file_type));
261 continue;
262 }
263
264 files[file->file_type] = file;
265 }
266
267 /*
268 * Check that all required section were provided.
269 * Report everything before failing.
270 */
271 ok = true;
272 for (type = FIRST_KEYMAP_FILE_TYPE;
273 type <= LAST_KEYMAP_FILE_TYPE;
274 type++) {
275 if (files[type] == NULL) {
276 log_err(ctx, "Required section %s missing from keymap\n",
277 xkb_file_type_to_string(type));
278 ok = false;
279 }
280 }
281 if (!ok)
282 return false;
283
284 /* Compile sections. */
285 for (type = FIRST_KEYMAP_FILE_TYPE;
286 type <= LAST_KEYMAP_FILE_TYPE;
287 type++) {
288 log_dbg(ctx, "Compiling %s \"%s\"\n",
289 xkb_file_type_to_string(type), files[type]->name);
290
291 ok = compile_file_fns[type](files[type], keymap, merge);
292 if (!ok) {
293 log_err(ctx, "Failed to compile %s\n",
294 xkb_file_type_to_string(type));
295 return false;
296 }
297 }
298
299 return UpdateDerivedKeymapFields(keymap);
300 }
301