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