• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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