1 /************************************************************
2 * Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
3 *
4 * Permission to use, copy, modify, and distribute this
5 * software and its documentation for any purpose and without
6 * fee is hereby granted, provided that the above copyright
7 * notice appear in all copies and that both that copyright
8 * notice and this permission notice appear in supporting
9 * documentation, and that the name of Silicon Graphics not be
10 * used in advertising or publicity pertaining to distribution
11 * of the software without specific prior written permission.
12 * Silicon Graphics makes no representation about the suitability
13 * of this software for any purpose. It is provided "as is"
14 * without any express or implied warranty.
15 *
16 * SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18 * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19 * GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH
23 * THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 *
25 ********************************************************/
26
27 /*
28 * Copyright © 2012 Intel Corporation
29 *
30 * Permission is hereby granted, free of charge, to any person obtaining a
31 * copy of this software and associated documentation files (the "Software"),
32 * to deal in the Software without restriction, including without limitation
33 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
34 * and/or sell copies of the Software, and to permit persons to whom the
35 * Software is furnished to do so, subject to the following conditions:
36 *
37 * The above copyright notice and this permission notice (including the next
38 * paragraph) shall be included in all copies or substantial portions of the
39 * Software.
40 *
41 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
42 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
43 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
44 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
45 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
46 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
47 * DEALINGS IN THE SOFTWARE.
48 *
49 * Author: Daniel Stone <[email protected]>
50 */
51
52 #include "config.h"
53
54 #include "xkbcomp-priv.h"
55 #include "text.h"
56
57 #define BUF_CHUNK_SIZE 4096
58
59 struct buf {
60 char *buf;
61 size_t size;
62 size_t alloc;
63 };
64
65 static bool
do_realloc(struct buf * buf,size_t at_least)66 do_realloc(struct buf *buf, size_t at_least)
67 {
68 char *new;
69
70 buf->alloc += BUF_CHUNK_SIZE;
71 if (at_least >= BUF_CHUNK_SIZE)
72 buf->alloc += at_least;
73
74 new = realloc(buf->buf, buf->alloc);
75 if (!new)
76 return false;
77
78 buf->buf = new;
79 return true;
80 }
81
82 ATTR_PRINTF(2, 3) static bool
check_write_buf(struct buf * buf,const char * fmt,...)83 check_write_buf(struct buf *buf, const char *fmt, ...)
84 {
85 va_list args;
86 int printed;
87 size_t available;
88
89 available = buf->alloc - buf->size;
90 va_start(args, fmt);
91 printed = vsnprintf(buf->buf + buf->size, available, fmt, args);
92 va_end(args);
93
94 if (printed < 0)
95 goto err;
96
97 if ((size_t) printed >= available)
98 if (!do_realloc(buf, printed))
99 goto err;
100
101 /* The buffer has enough space now. */
102
103 available = buf->alloc - buf->size;
104 va_start(args, fmt);
105 printed = vsnprintf(buf->buf + buf->size, available, fmt, args);
106 va_end(args);
107
108 if (printed < 0 || (size_t) printed >= available)
109 goto err;
110
111 buf->size += printed;
112 return true;
113
114 err:
115 free(buf->buf);
116 buf->buf = NULL;
117 return false;
118 }
119
120 #define write_buf(buf, ...) do { \
121 if (!check_write_buf(buf, __VA_ARGS__)) \
122 return false; \
123 } while (0)
124
125 static bool
write_vmods(struct xkb_keymap * keymap,struct buf * buf)126 write_vmods(struct xkb_keymap *keymap, struct buf *buf)
127 {
128 const struct xkb_mod *mod;
129 xkb_mod_index_t num_vmods = 0;
130
131 xkb_mods_foreach(mod, &keymap->mods) {
132 if (mod->type != MOD_VIRT)
133 continue;
134
135 if (num_vmods == 0)
136 write_buf(buf, "\tvirtual_modifiers ");
137 else
138 write_buf(buf, ",");
139 write_buf(buf, "%s", xkb_atom_text(keymap->ctx, mod->name));
140 num_vmods++;
141 }
142
143 if (num_vmods > 0)
144 write_buf(buf, ";\n\n");
145
146 return true;
147 }
148
149 static bool
write_keycodes(struct xkb_keymap * keymap,struct buf * buf)150 write_keycodes(struct xkb_keymap *keymap, struct buf *buf)
151 {
152 const struct xkb_key *key;
153 xkb_led_index_t idx;
154 const struct xkb_led *led;
155
156 if (keymap->keycodes_section_name)
157 write_buf(buf, "xkb_keycodes \"%s\" {\n",
158 keymap->keycodes_section_name);
159 else
160 write_buf(buf, "xkb_keycodes {\n");
161
162 /* xkbcomp and X11 really want to see keymaps with a minimum of 8, and
163 * a maximum of at least 255, else XWayland really starts hating life.
164 * If this is a problem and people really need strictly bounded keymaps,
165 * we should probably control this with a flag. */
166 write_buf(buf, "\tminimum = %u;\n", MIN(keymap->min_key_code, 8));
167 write_buf(buf, "\tmaximum = %u;\n", MAX(keymap->max_key_code, 255));
168
169 xkb_keys_foreach(key, keymap) {
170 if (key->name == XKB_ATOM_NONE)
171 continue;
172
173 write_buf(buf, "\t%-20s = %u;\n",
174 KeyNameText(keymap->ctx, key->name), key->keycode);
175 }
176
177 xkb_leds_enumerate(idx, led, keymap)
178 if (led->name != XKB_ATOM_NONE)
179 write_buf(buf, "\tindicator %u = \"%s\";\n",
180 idx + 1, xkb_atom_text(keymap->ctx, led->name));
181
182
183 for (unsigned i = 0; i < keymap->num_key_aliases; i++)
184 write_buf(buf, "\talias %-14s = %s;\n",
185 KeyNameText(keymap->ctx, keymap->key_aliases[i].alias),
186 KeyNameText(keymap->ctx, keymap->key_aliases[i].real));
187
188 write_buf(buf, "};\n\n");
189 return true;
190 }
191
192 static bool
write_types(struct xkb_keymap * keymap,struct buf * buf)193 write_types(struct xkb_keymap *keymap, struct buf *buf)
194 {
195 if (keymap->types_section_name)
196 write_buf(buf, "xkb_types \"%s\" {\n",
197 keymap->types_section_name);
198 else
199 write_buf(buf, "xkb_types {\n");
200
201 write_vmods(keymap, buf);
202
203 for (unsigned i = 0; i < keymap->num_types; i++) {
204 const struct xkb_key_type *type = &keymap->types[i];
205
206 write_buf(buf, "\ttype \"%s\" {\n",
207 xkb_atom_text(keymap->ctx, type->name));
208
209 write_buf(buf, "\t\tmodifiers= %s;\n",
210 ModMaskText(keymap->ctx, &keymap->mods, type->mods.mods));
211
212 for (unsigned j = 0; j < type->num_entries; j++) {
213 const char *str;
214 const struct xkb_key_type_entry *entry = &type->entries[j];
215
216 /*
217 * Printing level 1 entries is redundant, it's the default,
218 * unless there's preserve info.
219 */
220 if (entry->level == 0 && entry->preserve.mods == 0)
221 continue;
222
223 str = ModMaskText(keymap->ctx, &keymap->mods, entry->mods.mods);
224 write_buf(buf, "\t\tmap[%s]= %u;\n",
225 str, entry->level + 1);
226
227 if (entry->preserve.mods)
228 write_buf(buf, "\t\tpreserve[%s]= %s;\n",
229 str, ModMaskText(keymap->ctx, &keymap->mods,
230 entry->preserve.mods));
231 }
232
233 for (xkb_level_index_t n = 0; n < type->num_level_names; n++)
234 if (type->level_names[n])
235 write_buf(buf, "\t\tlevel_name[%u]= \"%s\";\n", n + 1,
236 xkb_atom_text(keymap->ctx, type->level_names[n]));
237
238 write_buf(buf, "\t};\n");
239 }
240
241 write_buf(buf, "};\n\n");
242 return true;
243 }
244
245 static bool
write_led_map(struct xkb_keymap * keymap,struct buf * buf,const struct xkb_led * led)246 write_led_map(struct xkb_keymap *keymap, struct buf *buf,
247 const struct xkb_led *led)
248 {
249 write_buf(buf, "\tindicator \"%s\" {\n",
250 xkb_atom_text(keymap->ctx, led->name));
251
252 if (led->which_groups) {
253 if (led->which_groups != XKB_STATE_LAYOUT_EFFECTIVE) {
254 write_buf(buf, "\t\twhichGroupState= %s;\n",
255 LedStateMaskText(keymap->ctx, led->which_groups));
256 }
257 write_buf(buf, "\t\tgroups= 0x%02x;\n",
258 led->groups);
259 }
260
261 if (led->which_mods) {
262 if (led->which_mods != XKB_STATE_MODS_EFFECTIVE) {
263 write_buf(buf, "\t\twhichModState= %s;\n",
264 LedStateMaskText(keymap->ctx, led->which_mods));
265 }
266 write_buf(buf, "\t\tmodifiers= %s;\n",
267 ModMaskText(keymap->ctx, &keymap->mods, led->mods.mods));
268 }
269
270 if (led->ctrls) {
271 write_buf(buf, "\t\tcontrols= %s;\n",
272 ControlMaskText(keymap->ctx, led->ctrls));
273 }
274
275 write_buf(buf, "\t};\n");
276 return true;
277 }
278
279 static const char *
affect_lock_text(enum xkb_action_flags flags,bool show_both)280 affect_lock_text(enum xkb_action_flags flags, bool show_both)
281 {
282 switch (flags & (ACTION_LOCK_NO_LOCK | ACTION_LOCK_NO_UNLOCK)) {
283 case 0:
284 return show_both ? ",affect=both" : "";
285 case ACTION_LOCK_NO_UNLOCK:
286 return ",affect=lock";
287 case ACTION_LOCK_NO_LOCK:
288 return ",affect=unlock";
289 case ACTION_LOCK_NO_LOCK | ACTION_LOCK_NO_UNLOCK:
290 return ",affect=neither";
291 }
292 return "";
293 }
294
295 static bool
write_action(struct xkb_keymap * keymap,struct buf * buf,const union xkb_action * action,const char * prefix,const char * suffix)296 write_action(struct xkb_keymap *keymap, struct buf *buf,
297 const union xkb_action *action,
298 const char *prefix, const char *suffix)
299 {
300 const char *type;
301 const char *args = NULL;
302
303 if (!prefix)
304 prefix = "";
305 if (!suffix)
306 suffix = "";
307
308 type = ActionTypeText(action->type);
309
310 switch (action->type) {
311 case ACTION_TYPE_MOD_SET:
312 case ACTION_TYPE_MOD_LATCH:
313 case ACTION_TYPE_MOD_LOCK:
314 if (action->mods.flags & ACTION_MODS_LOOKUP_MODMAP)
315 args = "modMapMods";
316 else
317 args = ModMaskText(keymap->ctx, &keymap->mods,
318 action->mods.mods.mods);
319 write_buf(buf, "%s%s(modifiers=%s%s%s%s)%s", prefix, type, args,
320 (action->type != ACTION_TYPE_MOD_LOCK && (action->mods.flags & ACTION_LOCK_CLEAR)) ? ",clearLocks" : "",
321 (action->type != ACTION_TYPE_MOD_LOCK && (action->mods.flags & ACTION_LATCH_TO_LOCK)) ? ",latchToLock" : "",
322 (action->type == ACTION_TYPE_MOD_LOCK) ? affect_lock_text(action->mods.flags, false) : "",
323 suffix);
324 break;
325
326 case ACTION_TYPE_GROUP_SET:
327 case ACTION_TYPE_GROUP_LATCH:
328 case ACTION_TYPE_GROUP_LOCK:
329 write_buf(buf, "%s%s(group=%s%d%s%s)%s", prefix, type,
330 (!(action->group.flags & ACTION_ABSOLUTE_SWITCH) && action->group.group > 0) ? "+" : "",
331 (action->group.flags & ACTION_ABSOLUTE_SWITCH) ? action->group.group + 1 : action->group.group,
332 (action->type != ACTION_TYPE_GROUP_LOCK && (action->group.flags & ACTION_LOCK_CLEAR)) ? ",clearLocks" : "",
333 (action->type != ACTION_TYPE_GROUP_LOCK && (action->group.flags & ACTION_LATCH_TO_LOCK)) ? ",latchToLock" : "",
334 suffix);
335 break;
336
337 case ACTION_TYPE_TERMINATE:
338 write_buf(buf, "%s%s()%s", prefix, type, suffix);
339 break;
340
341 case ACTION_TYPE_PTR_MOVE:
342 write_buf(buf, "%s%s(x=%s%d,y=%s%d%s)%s", prefix, type,
343 (!(action->ptr.flags & ACTION_ABSOLUTE_X) && action->ptr.x >= 0) ? "+" : "",
344 action->ptr.x,
345 (!(action->ptr.flags & ACTION_ABSOLUTE_Y) && action->ptr.y >= 0) ? "+" : "",
346 action->ptr.y,
347 (action->ptr.flags & ACTION_ACCEL) ? "" : ",!accel",
348 suffix);
349 break;
350
351 case ACTION_TYPE_PTR_LOCK:
352 args = affect_lock_text(action->btn.flags, true);
353 /* fallthrough */
354 case ACTION_TYPE_PTR_BUTTON:
355 write_buf(buf, "%s%s(button=", prefix, type);
356 if (action->btn.button > 0 && action->btn.button <= 5)
357 write_buf(buf, "%d", action->btn.button);
358 else
359 write_buf(buf, "default");
360 if (action->btn.count)
361 write_buf(buf, ",count=%d", action->btn.count);
362 if (args)
363 write_buf(buf, "%s", args);
364 write_buf(buf, ")%s", suffix);
365 break;
366
367 case ACTION_TYPE_PTR_DEFAULT:
368 write_buf(buf, "%s%s(", prefix, type);
369 write_buf(buf, "affect=button,button=%s%d",
370 (!(action->dflt.flags & ACTION_ABSOLUTE_SWITCH) && action->dflt.value >= 0) ? "+" : "",
371 action->dflt.value);
372 write_buf(buf, ")%s", suffix);
373 break;
374
375 case ACTION_TYPE_SWITCH_VT:
376 write_buf(buf, "%s%s(screen=%s%d,%ssame)%s", prefix, type,
377 (!(action->screen.flags & ACTION_ABSOLUTE_SWITCH) && action->screen.screen >= 0) ? "+" : "",
378 action->screen.screen,
379 (action->screen.flags & ACTION_SAME_SCREEN) ? "" : "!",
380 suffix);
381 break;
382
383 case ACTION_TYPE_CTRL_SET:
384 case ACTION_TYPE_CTRL_LOCK:
385 write_buf(buf, "%s%s(controls=%s%s)%s", prefix, type,
386 ControlMaskText(keymap->ctx, action->ctrls.ctrls),
387 (action->type == ACTION_TYPE_CTRL_LOCK) ? affect_lock_text(action->ctrls.flags, false) : "",
388 suffix);
389 break;
390
391 case ACTION_TYPE_NONE:
392 write_buf(buf, "%sNoAction()%s", prefix, suffix);
393 break;
394
395 default:
396 write_buf(buf,
397 "%s%s(type=0x%02x,data[0]=0x%02x,data[1]=0x%02x,data[2]=0x%02x,data[3]=0x%02x,data[4]=0x%02x,data[5]=0x%02x,data[6]=0x%02x)%s",
398 prefix, type, action->type, action->priv.data[0],
399 action->priv.data[1], action->priv.data[2],
400 action->priv.data[3], action->priv.data[4],
401 action->priv.data[5], action->priv.data[6],
402 suffix);
403 break;
404 }
405
406 return true;
407 }
408
409 static bool
write_compat(struct xkb_keymap * keymap,struct buf * buf)410 write_compat(struct xkb_keymap *keymap, struct buf *buf)
411 {
412 const struct xkb_led *led;
413
414 if (keymap->compat_section_name)
415 write_buf(buf, "xkb_compatibility \"%s\" {\n",
416 keymap->compat_section_name);
417 else
418 write_buf(buf, "xkb_compatibility {\n");
419
420 write_vmods(keymap, buf);
421
422 write_buf(buf, "\tinterpret.useModMapMods= AnyLevel;\n");
423 write_buf(buf, "\tinterpret.repeat= False;\n");
424
425 for (unsigned i = 0; i < keymap->num_sym_interprets; i++) {
426 const struct xkb_sym_interpret *si = &keymap->sym_interprets[i];
427
428 write_buf(buf, "\tinterpret %s+%s(%s) {\n",
429 si->sym ? KeysymText(keymap->ctx, si->sym) : "Any",
430 SIMatchText(si->match),
431 ModMaskText(keymap->ctx, &keymap->mods, si->mods));
432
433 if (si->virtual_mod != XKB_MOD_INVALID)
434 write_buf(buf, "\t\tvirtualModifier= %s;\n",
435 ModIndexText(keymap->ctx, &keymap->mods,
436 si->virtual_mod));
437
438 if (si->level_one_only)
439 write_buf(buf, "\t\tuseModMapMods=level1;\n");
440
441 if (si->repeat)
442 write_buf(buf, "\t\trepeat= True;\n");
443
444 write_action(keymap, buf, &si->action, "\t\taction= ", ";\n");
445 write_buf(buf, "\t};\n");
446 }
447
448 xkb_leds_foreach(led, keymap)
449 if (led->which_groups || led->groups || led->which_mods ||
450 led->mods.mods || led->ctrls)
451 write_led_map(keymap, buf, led);
452
453 write_buf(buf, "};\n\n");
454
455 return true;
456 }
457
458 static bool
write_keysyms(struct xkb_keymap * keymap,struct buf * buf,const struct xkb_key * key,xkb_layout_index_t group)459 write_keysyms(struct xkb_keymap *keymap, struct buf *buf,
460 const struct xkb_key *key, xkb_layout_index_t group)
461 {
462 for (xkb_level_index_t level = 0; level < XkbKeyNumLevels(key, group);
463 level++) {
464 const xkb_keysym_t *syms;
465 int num_syms;
466
467 if (level != 0)
468 write_buf(buf, ", ");
469
470 num_syms = xkb_keymap_key_get_syms_by_level(keymap, key->keycode,
471 group, level, &syms);
472 if (num_syms == 0) {
473 write_buf(buf, "%15s", "NoSymbol");
474 }
475 else if (num_syms == 1) {
476 write_buf(buf, "%15s", KeysymText(keymap->ctx, syms[0]));
477 }
478 else {
479 write_buf(buf, "{ ");
480 for (int s = 0; s < num_syms; s++) {
481 if (s != 0)
482 write_buf(buf, ", ");
483 write_buf(buf, "%s", KeysymText(keymap->ctx, syms[s]));
484 }
485 write_buf(buf, " }");
486 }
487 }
488
489 return true;
490 }
491
492 static bool
write_key(struct xkb_keymap * keymap,struct buf * buf,const struct xkb_key * key)493 write_key(struct xkb_keymap *keymap, struct buf *buf,
494 const struct xkb_key *key)
495 {
496 xkb_layout_index_t group;
497 bool simple = true;
498 bool explicit_types = false;
499 bool multi_type = false;
500 bool show_actions;
501
502 write_buf(buf, "\tkey %-20s {", KeyNameText(keymap->ctx, key->name));
503
504 for (group = 0; group < key->num_groups; group++) {
505 if (key->groups[group].explicit_type)
506 explicit_types = true;
507
508 if (group != 0 && key->groups[group].type != key->groups[0].type)
509 multi_type = true;
510 }
511
512 if (explicit_types) {
513 const struct xkb_key_type *type;
514 simple = false;
515
516 if (multi_type) {
517 for (group = 0; group < key->num_groups; group++) {
518 if (!key->groups[group].explicit_type)
519 continue;
520
521 type = key->groups[group].type;
522 write_buf(buf, "\n\t\ttype[Group%u]= \"%s\",",
523 group + 1,
524 xkb_atom_text(keymap->ctx, type->name));
525 }
526 }
527 else {
528 type = key->groups[0].type;
529 write_buf(buf, "\n\t\ttype= \"%s\",",
530 xkb_atom_text(keymap->ctx, type->name));
531 }
532 }
533
534 if (key->explicit & EXPLICIT_REPEAT) {
535 if (key->repeats)
536 write_buf(buf, "\n\t\trepeat= Yes,");
537 else
538 write_buf(buf, "\n\t\trepeat= No,");
539 simple = false;
540 }
541
542 if (key->vmodmap && (key->explicit & EXPLICIT_VMODMAP))
543 write_buf(buf, "\n\t\tvirtualMods= %s,",
544 ModMaskText(keymap->ctx, &keymap->mods, key->vmodmap));
545
546 switch (key->out_of_range_group_action) {
547 case RANGE_SATURATE:
548 write_buf(buf, "\n\t\tgroupsClamp,");
549 break;
550
551 case RANGE_REDIRECT:
552 write_buf(buf, "\n\t\tgroupsRedirect= Group%u,",
553 key->out_of_range_group_number + 1);
554 break;
555
556 default:
557 break;
558 }
559
560 show_actions = (key->explicit & EXPLICIT_INTERP);
561
562 if (key->num_groups > 1 || show_actions)
563 simple = false;
564
565 if (simple) {
566 write_buf(buf, "\t[ ");
567 if (!write_keysyms(keymap, buf, key, 0))
568 return false;
569 write_buf(buf, " ] };\n");
570 }
571 else {
572 xkb_level_index_t level;
573
574 for (group = 0; group < key->num_groups; group++) {
575 if (group != 0)
576 write_buf(buf, ",");
577 write_buf(buf, "\n\t\tsymbols[Group%u]= [ ", group + 1);
578 if (!write_keysyms(keymap, buf, key, group))
579 return false;
580 write_buf(buf, " ]");
581 if (show_actions) {
582 write_buf(buf, ",\n\t\tactions[Group%u]= [ ", group + 1);
583 for (level = 0; level < XkbKeyNumLevels(key, group); level++) {
584 if (level != 0)
585 write_buf(buf, ", ");
586 write_action(keymap, buf,
587 &key->groups[group].levels[level].action,
588 NULL, NULL);
589 }
590 write_buf(buf, " ]");
591 }
592 }
593 write_buf(buf, "\n\t};\n");
594 }
595
596 return true;
597 }
598
599 static bool
write_symbols(struct xkb_keymap * keymap,struct buf * buf)600 write_symbols(struct xkb_keymap *keymap, struct buf *buf)
601 {
602 const struct xkb_key *key;
603 xkb_layout_index_t group;
604 xkb_mod_index_t i;
605 const struct xkb_mod *mod;
606
607 if (keymap->symbols_section_name)
608 write_buf(buf, "xkb_symbols \"%s\" {\n",
609 keymap->symbols_section_name);
610 else
611 write_buf(buf, "xkb_symbols {\n");
612
613 for (group = 0; group < keymap->num_group_names; group++)
614 if (keymap->group_names[group])
615 write_buf(buf,
616 "\tname[Group%u]=\"%s\";\n", group + 1,
617 xkb_atom_text(keymap->ctx, keymap->group_names[group]));
618 if (group > 0)
619 write_buf(buf, "\n");
620
621 xkb_keys_foreach(key, keymap)
622 if (key->num_groups > 0)
623 write_key(keymap, buf, key);
624
625 xkb_mods_enumerate(i, mod, &keymap->mods) {
626 bool had_any = false;
627 xkb_keys_foreach(key, keymap) {
628 if (key->modmap & (1u << i)) {
629 if (!had_any)
630 write_buf(buf, "\tmodifier_map %s { ",
631 xkb_atom_text(keymap->ctx, mod->name));
632 write_buf(buf, "%s%s",
633 had_any ? ", " : "",
634 KeyNameText(keymap->ctx, key->name));
635 had_any = true;
636 }
637 }
638 if (had_any)
639 write_buf(buf, " };\n");
640 }
641
642 write_buf(buf, "};\n\n");
643 return true;
644 }
645
646 static bool
write_keymap(struct xkb_keymap * keymap,struct buf * buf)647 write_keymap(struct xkb_keymap *keymap, struct buf *buf)
648 {
649 return (check_write_buf(buf, "xkb_keymap {\n") &&
650 write_keycodes(keymap, buf) &&
651 write_types(keymap, buf) &&
652 write_compat(keymap, buf) &&
653 write_symbols(keymap, buf) &&
654 check_write_buf(buf, "};\n"));
655 }
656
657 char *
text_v1_keymap_get_as_string(struct xkb_keymap * keymap)658 text_v1_keymap_get_as_string(struct xkb_keymap *keymap)
659 {
660 struct buf buf = { NULL, 0, 0 };
661
662 if (!write_keymap(keymap, &buf)) {
663 free(buf.buf);
664 return NULL;
665 }
666
667 return buf.buf;
668 }
669