keymap: abstract a bit over the keymap format
[platform/upstream/libxkbcommon.git] / src / keymap.c
1 /**
2  * Copyright © 2012 Intel Corporation
3  * Copyright © 2012 Ran Benita <ran234@gmail.com>
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  *
24  * Author: Daniel Stone <daniel@fooishbar.org>
25  */
26
27 /************************************************************
28  * Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
29  *
30  * Permission to use, copy, modify, and distribute this
31  * software and its documentation for any purpose and without
32  * fee is hereby granted, provided that the above copyright
33  * notice appear in all copies and that both that copyright
34  * notice and this permission notice appear in supporting
35  * documentation, and that the name of Silicon Graphics not be
36  * used in advertising or publicity pertaining to distribution
37  * of the software without specific prior written permission.
38  * Silicon Graphics makes no representation about the suitability
39  * of this software for any purpose. It is provided "as is"
40  * without any express or implied warranty.
41  *
42  * SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
43  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
44  * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
45  * GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
46  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
47  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
48  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
49  * THE USE OR PERFORMANCE OF THIS SOFTWARE.
50  *
51  * ********************************************************/
52
53 #include "keymap.h"
54 #include "text.h"
55
56 static struct xkb_keymap *
57 xkb_keymap_new(struct xkb_context *ctx,
58                enum xkb_keymap_format format,
59                enum xkb_keymap_compile_flags flags)
60 {
61     struct xkb_keymap *keymap;
62
63     keymap = calloc(1, sizeof(*keymap));
64     if (!keymap)
65         return NULL;
66
67     keymap->refcnt = 1;
68     keymap->ctx = xkb_context_ref(ctx);
69
70     keymap->format = format;
71     keymap->flags = flags;
72
73     return keymap;
74 }
75
76 XKB_EXPORT struct xkb_keymap *
77 xkb_keymap_ref(struct xkb_keymap *keymap)
78 {
79     keymap->refcnt++;
80     return keymap;
81 }
82
83 XKB_EXPORT void
84 xkb_keymap_unref(struct xkb_keymap *keymap)
85 {
86     unsigned int i, j;
87     struct xkb_key *key;
88
89     if (!keymap || --keymap->refcnt > 0)
90         return;
91
92     if (keymap->keys) {
93         xkb_foreach_key(key, keymap) {
94             for (i = 0; i < key->num_groups; i++) {
95                 for (j = 0; j < XkbKeyGroupWidth(key, i); j++)
96                     if (key->groups[i].levels[j].num_syms > 1)
97                         free(key->groups[i].levels[j].u.syms);
98                 free(key->groups[i].levels);
99             }
100             free(key->groups);
101         }
102         free(keymap->keys);
103     }
104     for (i = 0; i < keymap->num_types; i++) {
105         free(keymap->types[i].map);
106         free(keymap->types[i].level_names);
107     }
108     free(keymap->types);
109     darray_free(keymap->sym_interprets);
110     darray_free(keymap->key_aliases);
111     free(keymap->group_names);
112     darray_free(keymap->mods);
113     darray_free(keymap->leds);
114     free(keymap->keycodes_section_name);
115     free(keymap->symbols_section_name);
116     free(keymap->types_section_name);
117     free(keymap->compat_section_name);
118     xkb_context_unref(keymap->ctx);
119     free(keymap);
120 }
121
122 static const struct xkb_keymap_format_ops *
123 get_keymap_format_ops(enum xkb_keymap_format format)
124 {
125     static const struct xkb_keymap_format_ops *keymap_format_ops[] = {
126         [XKB_KEYMAP_FORMAT_TEXT_V1] = &text_v1_keymap_format_ops,
127     };
128
129     if ((int) format < 0 || (int) format >= ARRAY_SIZE(keymap_format_ops))
130         return NULL;
131
132     return keymap_format_ops[format];
133 }
134
135 XKB_EXPORT struct xkb_keymap *
136 xkb_keymap_new_from_names(struct xkb_context *ctx,
137                           const struct xkb_rule_names *rmlvo_in,
138                           enum xkb_keymap_compile_flags flags)
139 {
140     struct xkb_keymap *keymap;
141     struct xkb_rule_names rmlvo;
142     const enum xkb_keymap_format format = XKB_KEYMAP_FORMAT_TEXT_V1;
143     const struct xkb_keymap_format_ops *ops;
144
145     ops = get_keymap_format_ops(format);
146     if (!ops || !ops->keymap_new_from_names) {
147         log_err_func(ctx, "unsupported keymap format: %d\n", format);
148         return NULL;
149     }
150
151     if (flags & ~(XKB_MAP_COMPILE_PLACEHOLDER)) {
152         log_err_func(ctx, "unrecognized flags: %#x\n", flags);
153         return NULL;
154     }
155
156     rmlvo = *rmlvo_in;
157     if (isempty(rmlvo.rules))
158         rmlvo.rules = DEFAULT_XKB_RULES;
159     if (isempty(rmlvo.model))
160         rmlvo.model = DEFAULT_XKB_MODEL;
161     if (isempty(rmlvo.layout))
162         rmlvo.layout = DEFAULT_XKB_LAYOUT;
163
164     keymap = xkb_keymap_new(ctx, format, flags);
165     if (!keymap)
166         return NULL;
167
168     if (!ops->keymap_new_from_names(keymap, &rmlvo)) {
169         xkb_keymap_unref(keymap);
170         return NULL;
171     }
172
173     return keymap;
174 }
175
176 XKB_EXPORT struct xkb_keymap *
177 xkb_keymap_new_from_string(struct xkb_context *ctx,
178                            const char *string,
179                            enum xkb_keymap_format format,
180                            enum xkb_keymap_compile_flags flags)
181 {
182     struct xkb_keymap *keymap;
183     const struct xkb_keymap_format_ops *ops;
184
185     ops = get_keymap_format_ops(format);
186     if (!ops || !ops->keymap_new_from_string) {
187         log_err_func(ctx, "unsupported keymap format: %d\n", format);
188         return NULL;
189     }
190
191     if (flags & ~(XKB_MAP_COMPILE_PLACEHOLDER)) {
192         log_err_func(ctx, "unrecognized flags: %#x\n", flags);
193         return NULL;
194     }
195
196     if (!string) {
197         log_err_func1(ctx, "no string specified\n");
198         return NULL;
199     }
200
201     keymap = xkb_keymap_new(ctx, format, flags);
202     if (!keymap)
203         return NULL;
204
205     if (!ops->keymap_new_from_string(keymap, string)) {
206         xkb_keymap_unref(keymap);
207         return NULL;
208     }
209
210     return keymap;
211 }
212
213 XKB_EXPORT struct xkb_keymap *
214 xkb_keymap_new_from_file(struct xkb_context *ctx,
215                          FILE *file,
216                          enum xkb_keymap_format format,
217                          enum xkb_keymap_compile_flags flags)
218 {
219     struct xkb_keymap *keymap;
220     const struct xkb_keymap_format_ops *ops;
221
222     ops = get_keymap_format_ops(format);
223     if (!ops || !ops->keymap_new_from_file) {
224         log_err_func(ctx, "unsupported keymap format: %d\n", format);
225         return NULL;
226     }
227
228     if (flags & ~(XKB_MAP_COMPILE_PLACEHOLDER)) {
229         log_err_func(ctx, "unrecognized flags: %#x\n", flags);
230         return NULL;
231     }
232
233     if (!file) {
234         log_err_func1(ctx, "no file specified\n");
235         return NULL;
236     }
237
238     keymap = xkb_keymap_new(ctx, format, flags);
239     if (!keymap)
240         return NULL;
241
242     if (!ops->keymap_new_from_file(keymap, file)) {
243         xkb_keymap_unref(keymap);
244         return NULL;
245     }
246
247     return keymap;
248 }
249
250 XKB_EXPORT char *
251 xkb_keymap_get_as_string(struct xkb_keymap *keymap,
252                          enum xkb_keymap_format format)
253 {
254     const struct xkb_keymap_format_ops *ops;
255
256     if (format == XKB_KEYMAP_USE_ORIGINAL_FORMAT)
257         format = keymap->format;
258
259     ops = get_keymap_format_ops(format);
260     if (!ops || !ops->keymap_get_as_string) {
261         log_err_func(keymap->ctx, "unsupported keymap format: %d\n", format);
262         return NULL;
263     }
264
265     return ops->keymap_get_as_string(keymap);
266 }
267
268 /**
269  * Returns the total number of modifiers active in the keymap.
270  */
271 XKB_EXPORT xkb_mod_index_t
272 xkb_keymap_num_mods(struct xkb_keymap *keymap)
273 {
274     return darray_size(keymap->mods);
275 }
276
277 /**
278  * Return the name for a given modifier.
279  */
280 XKB_EXPORT const char *
281 xkb_keymap_mod_get_name(struct xkb_keymap *keymap, xkb_mod_index_t idx)
282 {
283     if (idx >= darray_size(keymap->mods))
284         return NULL;
285
286     return xkb_atom_text(keymap->ctx, darray_item(keymap->mods, idx).name);
287 }
288
289 /**
290  * Returns the index for a named modifier.
291  */
292 XKB_EXPORT xkb_mod_index_t
293 xkb_keymap_mod_get_index(struct xkb_keymap *keymap, const char *name)
294 {
295     xkb_mod_index_t i;
296     xkb_atom_t atom;
297     const struct xkb_mod *mod;
298
299     atom = xkb_atom_lookup(keymap->ctx, name);
300     if (atom == XKB_ATOM_NONE)
301         return XKB_MOD_INVALID;
302
303     darray_enumerate(i, mod, keymap->mods)
304         if (mod->name == atom)
305             return i;
306
307     return XKB_MOD_INVALID;
308 }
309
310 /**
311  * Return the total number of active groups in the keymap.
312  */
313 XKB_EXPORT xkb_layout_index_t
314 xkb_keymap_num_layouts(struct xkb_keymap *keymap)
315 {
316     return keymap->num_groups;
317 }
318
319 /**
320  * Returns the name for a given group.
321  */
322 XKB_EXPORT const char *
323 xkb_keymap_layout_get_name(struct xkb_keymap *keymap, xkb_layout_index_t idx)
324 {
325     if (idx >= keymap->num_group_names)
326         return NULL;
327
328     return xkb_atom_text(keymap->ctx, keymap->group_names[idx]);
329 }
330
331 /**
332  * Returns the index for a named layout.
333  */
334 XKB_EXPORT xkb_layout_index_t
335 xkb_keymap_layout_get_index(struct xkb_keymap *keymap, const char *name)
336 {
337     xkb_atom_t atom = xkb_atom_lookup(keymap->ctx, name);
338     xkb_layout_index_t i;
339
340     if (atom == XKB_ATOM_NONE)
341         return XKB_LAYOUT_INVALID;
342
343     for (i = 0; i < keymap->num_group_names; i++)
344         if (keymap->group_names[i] == atom)
345             return i;
346
347     return XKB_LAYOUT_INVALID;
348 }
349
350 /**
351  * Returns the number of layouts active for a particular key.
352  */
353 XKB_EXPORT xkb_layout_index_t
354 xkb_keymap_num_layouts_for_key(struct xkb_keymap *keymap, xkb_keycode_t kc)
355 {
356     const struct xkb_key *key = XkbKey(keymap, kc);
357
358     if (!key)
359         return 0;
360
361     return key->num_groups;
362 }
363
364 /**
365  * Returns the number of levels active for a particular key and layout.
366  */
367 XKB_EXPORT xkb_level_index_t
368 xkb_keymap_num_levels_for_key(struct xkb_keymap *keymap, xkb_keycode_t kc,
369                               xkb_layout_index_t layout)
370 {
371     const struct xkb_key *key = XkbKey(keymap, kc);
372
373     if (!key)
374         return 0;
375
376     layout = wrap_group_into_range(layout, key->num_groups,
377                                    key->out_of_range_group_action,
378                                    key->out_of_range_group_number);
379     if (layout == XKB_LAYOUT_INVALID)
380         return 0;
381
382     return XkbKeyGroupWidth(key, layout);
383 }
384
385 /**
386  * Return the total number of LEDs in the keymap.
387  */
388 XKB_EXPORT xkb_led_index_t
389 xkb_keymap_num_leds(struct xkb_keymap *keymap)
390 {
391     return darray_size(keymap->leds);
392 }
393
394 /**
395  * Returns the name for a given LED.
396  */
397 XKB_EXPORT const char *
398 xkb_keymap_led_get_name(struct xkb_keymap *keymap, xkb_led_index_t idx)
399 {
400     if (idx >= darray_size(keymap->leds))
401         return NULL;
402
403     return xkb_atom_text(keymap->ctx, darray_item(keymap->leds, idx).name);
404 }
405
406 /**
407  * Returns the index for a named LED.
408  */
409 XKB_EXPORT xkb_led_index_t
410 xkb_keymap_led_get_index(struct xkb_keymap *keymap, const char *name)
411 {
412     xkb_atom_t atom = xkb_atom_lookup(keymap->ctx, name);
413     xkb_led_index_t i;
414     const struct xkb_led *led;
415
416     if (atom == XKB_ATOM_NONE)
417         return XKB_LED_INVALID;
418
419     darray_enumerate(i, led, keymap->leds)
420         if (led->name == atom)
421             return i;
422
423     return XKB_LED_INVALID;
424 }
425
426 /**
427  * As below, but takes an explicit layout/level rather than state.
428  */
429 XKB_EXPORT int
430 xkb_keymap_key_get_syms_by_level(struct xkb_keymap *keymap,
431                                  xkb_keycode_t kc,
432                                  xkb_layout_index_t layout,
433                                  xkb_level_index_t level,
434                                  const xkb_keysym_t **syms_out)
435 {
436     const struct xkb_key *key = XkbKey(keymap, kc);
437     int num_syms;
438
439     if (!key)
440         goto err;
441
442     layout = wrap_group_into_range(layout, key->num_groups,
443                                    key->out_of_range_group_action,
444                                    key->out_of_range_group_number);
445     if (layout == XKB_LAYOUT_INVALID)
446         goto err;
447
448     if (level >= XkbKeyGroupWidth(key, layout))
449         goto err;
450
451     num_syms = key->groups[layout].levels[level].num_syms;
452     if (num_syms == 0)
453         goto err;
454
455     if (num_syms == 1)
456         *syms_out = &key->groups[layout].levels[level].u.sym;
457     else
458         *syms_out = key->groups[layout].levels[level].u.syms;
459
460     return num_syms;
461
462 err:
463     *syms_out = NULL;
464     return 0;
465 }
466
467 /**
468  * Simple boolean specifying whether or not the key should repeat.
469  */
470 XKB_EXPORT int
471 xkb_keymap_key_repeats(struct xkb_keymap *keymap, xkb_keycode_t kc)
472 {
473     const struct xkb_key *key = XkbKey(keymap, kc);
474
475     if (!key)
476         return 0;
477
478     return key->repeats;
479 }