| 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 | #ifdef HAVE_DIX_CONFIG_H |
| 28 | #include <dix-config.h> |
| 29 | #endif |
| 30 | |
| 31 | #include <stdio.h> |
| 32 | #include <ctype.h> |
| 33 | #include <stdlib.h> |
| 34 | #include <X11/Xfuncs.h> |
| 35 | |
| 36 | #include <X11/X.h> |
| 37 | #include <X11/keysym.h> |
| 38 | #include <X11/Xproto.h> |
| 39 | #include <X11/extensions/XKMformat.h> |
| 40 | #include "misc.h" |
| 41 | #include "inputstr.h" |
| 42 | #include "dix.h" |
| 43 | #include "xkbstr.h" |
| 44 | #define XKBSRV_NEED_FILE_FUNCS 1 |
| 45 | #include <xkbsrv.h> |
| 46 | |
| 47 | #include "xkbgeom.h" |
| 48 | #include "xkbfile.h" |
| 49 | |
| 50 | #define VMOD_HIDE_VALUE 0 |
| 51 | #define VMOD_SHOW_VALUE 1 |
| 52 | #define VMOD_COMMENT_VALUE 2 |
| 53 | |
| 54 | static Bool |
| 55 | WriteXKBVModDecl(FILE * file, XkbDescPtr xkb, int showValue) |
| 56 | { |
| 57 | register int i, nMods; |
| 58 | Atom *vmodNames; |
| 59 | |
| 60 | if (xkb == NULL) |
| 61 | return FALSE; |
| 62 | if (xkb->names != NULL) |
| 63 | vmodNames = xkb->names->vmods; |
| 64 | else |
| 65 | vmodNames = NULL; |
| 66 | |
| 67 | for (i = nMods = 0; i < XkbNumVirtualMods; i++) { |
| 68 | if ((vmodNames != NULL) && (vmodNames[i] != None)) { |
| 69 | if (nMods == 0) |
| 70 | fprintf(file, " virtual_modifiers "); |
| 71 | else |
| 72 | fprintf(file, ","); |
| 73 | fprintf(file, "%s", XkbAtomText(vmodNames[i], XkbXKBFile)); |
| 74 | if ((showValue != VMOD_HIDE_VALUE) && |
| 75 | (xkb->server) && (xkb->server->vmods[i] != XkbNoModifierMask)) { |
| 76 | if (showValue == VMOD_COMMENT_VALUE) { |
| 77 | fprintf(file, "/* = %s */", |
| 78 | XkbModMaskText(xkb->server->vmods[i], XkbXKBFile)); |
| 79 | } |
| 80 | else { |
| 81 | fprintf(file, "= %s", |
| 82 | XkbModMaskText(xkb->server->vmods[i], XkbXKBFile)); |
| 83 | } |
| 84 | } |
| 85 | nMods++; |
| 86 | } |
| 87 | } |
| 88 | if (nMods > 0) |
| 89 | fprintf(file, ";\n\n"); |
| 90 | return TRUE; |
| 91 | } |
| 92 | |
| 93 | /***====================================================================***/ |
| 94 | |
| 95 | static Bool |
| 96 | WriteXKBAction(FILE * file, XkbDescPtr xkb, XkbAnyAction * action) |
| 97 | { |
| 98 | fprintf(file, "%s", XkbActionText(xkb, (XkbAction *) action, XkbXKBFile)); |
| 99 | return TRUE; |
| 100 | } |
| 101 | |
| 102 | /***====================================================================***/ |
| 103 | |
| 104 | Bool |
| 105 | XkbWriteXKBKeycodes(FILE * file, |
| 106 | XkbDescPtr xkb, |
| 107 | Bool topLevel, |
| 108 | Bool showImplicit, XkbFileAddOnFunc addOn, void *priv) |
| 109 | { |
| 110 | Atom kcName; |
| 111 | register unsigned i; |
| 112 | const char *alternate; |
| 113 | |
| 114 | if ((!xkb) || (!xkb->names) || (!xkb->names->keys)) { |
| 115 | _XkbLibError(_XkbErrMissingNames, "XkbWriteXKBKeycodes", 0); |
| 116 | return FALSE; |
| 117 | } |
| 118 | kcName = xkb->names->keycodes; |
| 119 | if (kcName != None) |
| 120 | fprintf(file, "xkb_keycodes \"%s\" {\n", |
| 121 | XkbAtomText(kcName, XkbXKBFile)); |
| 122 | else |
| 123 | fprintf(file, "xkb_keycodes {\n"); |
| 124 | fprintf(file, " minimum = %d;\n", xkb->min_key_code); |
| 125 | fprintf(file, " maximum = %d;\n", xkb->max_key_code); |
| 126 | for (i = xkb->min_key_code; i <= xkb->max_key_code; i++) { |
| 127 | if (xkb->names->keys[i].name[0] != '\0') { |
| 128 | if (XkbFindKeycodeByName(xkb, xkb->names->keys[i].name, TRUE) != i) |
| 129 | alternate = "alternate "; |
| 130 | else |
| 131 | alternate = ""; |
| 132 | fprintf(file, " %s%6s = %d;\n", alternate, |
| 133 | XkbKeyNameText(xkb->names->keys[i].name, XkbXKBFile), i); |
| 134 | } |
| 135 | } |
| 136 | if (xkb->indicators != NULL) { |
| 137 | for (i = 0; i < XkbNumIndicators; i++) { |
| 138 | const char *type; |
| 139 | |
| 140 | if (xkb->indicators->phys_indicators & (1 << i)) |
| 141 | type = " "; |
| 142 | else |
| 143 | type = " virtual "; |
| 144 | if (xkb->names->indicators[i] != None) { |
| 145 | fprintf(file, "%sindicator %d = \"%s\";\n", type, i + 1, |
| 146 | XkbAtomText(xkb->names->indicators[i], XkbXKBFile)); |
| 147 | } |
| 148 | } |
| 149 | } |
| 150 | if (xkb->names->key_aliases != NULL) { |
| 151 | XkbKeyAliasPtr pAl; |
| 152 | |
| 153 | pAl = xkb->names->key_aliases; |
| 154 | for (i = 0; i < xkb->names->num_key_aliases; i++, pAl++) { |
| 155 | fprintf(file, " alias %6s = %6s;\n", |
| 156 | XkbKeyNameText(pAl->alias, XkbXKBFile), |
| 157 | XkbKeyNameText(pAl->real, XkbXKBFile)); |
| 158 | } |
| 159 | } |
| 160 | if (addOn) |
| 161 | (*addOn) (file, xkb, topLevel, showImplicit, XkmKeyNamesIndex, priv); |
| 162 | fprintf(file, "};\n\n"); |
| 163 | return TRUE; |
| 164 | } |
| 165 | |
| 166 | Bool |
| 167 | XkbWriteXKBKeyTypes(FILE * file, |
| 168 | XkbDescPtr xkb, |
| 169 | Bool topLevel, |
| 170 | Bool showImplicit, XkbFileAddOnFunc addOn, void *priv) |
| 171 | { |
| 172 | register unsigned i, n; |
| 173 | XkbKeyTypePtr type; |
| 174 | XkbKTMapEntryPtr entry; |
| 175 | |
| 176 | if ((!xkb) || (!xkb->map) || (!xkb->map->types)) { |
| 177 | _XkbLibError(_XkbErrMissingTypes, "XkbWriteXKBKeyTypes", 0); |
| 178 | return FALSE; |
| 179 | } |
| 180 | if (xkb->map->num_types < XkbNumRequiredTypes) { |
| 181 | _XkbLibError(_XkbErrMissingReqTypes, "XkbWriteXKBKeyTypes", 0); |
| 182 | return 0; |
| 183 | } |
| 184 | if ((xkb->names == NULL) || (xkb->names->types == None)) |
| 185 | fprintf(file, "xkb_types {\n\n"); |
| 186 | else |
| 187 | fprintf(file, "xkb_types \"%s\" {\n\n", |
| 188 | XkbAtomText(xkb->names->types, XkbXKBFile)); |
| 189 | WriteXKBVModDecl(file, xkb, |
| 190 | (showImplicit ? VMOD_COMMENT_VALUE : VMOD_HIDE_VALUE)); |
| 191 | |
| 192 | type = xkb->map->types; |
| 193 | for (i = 0; i < xkb->map->num_types; i++, type++) { |
| 194 | fprintf(file, " type \"%s\" {\n", |
| 195 | XkbAtomText(type->name, XkbXKBFile)); |
| 196 | fprintf(file, " modifiers= %s;\n", |
| 197 | XkbVModMaskText(xkb, type->mods.real_mods, type->mods.vmods, |
| 198 | XkbXKBFile)); |
| 199 | entry = type->map; |
| 200 | for (n = 0; n < type->map_count; n++, entry++) { |
| 201 | char *str; |
| 202 | |
| 203 | str = XkbVModMaskText(xkb, entry->mods.real_mods, entry->mods.vmods, |
| 204 | XkbXKBFile); |
| 205 | fprintf(file, " map[%s]= Level%d;\n", str, entry->level + 1); |
| 206 | if ((type->preserve) && ((type->preserve[n].real_mods) || |
| 207 | (type->preserve[n].vmods))) { |
| 208 | fprintf(file, " preserve[%s]= ", str); |
| 209 | fprintf(file, "%s;\n", XkbVModMaskText(xkb, |
| 210 | type->preserve[n]. |
| 211 | real_mods, |
| 212 | type->preserve[n].vmods, |
| 213 | XkbXKBFile)); |
| 214 | } |
| 215 | } |
| 216 | if (type->level_names != NULL) { |
| 217 | Atom *name = type->level_names; |
| 218 | |
| 219 | for (n = 0; n < type->num_levels; n++, name++) { |
| 220 | if ((*name) == None) |
| 221 | continue; |
| 222 | fprintf(file, " level_name[Level%d]= \"%s\";\n", n + 1, |
| 223 | XkbAtomText(*name, XkbXKBFile)); |
| 224 | } |
| 225 | } |
| 226 | fprintf(file, " };\n"); |
| 227 | } |
| 228 | if (addOn) |
| 229 | (*addOn) (file, xkb, topLevel, showImplicit, XkmTypesIndex, priv); |
| 230 | fprintf(file, "};\n\n"); |
| 231 | return TRUE; |
| 232 | } |
| 233 | |
| 234 | static Bool |
| 235 | WriteXKBIndicatorMap(FILE * file, |
| 236 | XkbDescPtr xkb, |
| 237 | Atom name, |
| 238 | XkbIndicatorMapPtr led, XkbFileAddOnFunc addOn, void *priv) |
| 239 | { |
| 240 | |
| 241 | fprintf(file, " indicator \"%s\" {\n", NameForAtom(name)); |
| 242 | if (led->flags & XkbIM_NoExplicit) |
| 243 | fprintf(file, " !allowExplicit;\n"); |
| 244 | if (led->flags & XkbIM_LEDDrivesKB) |
| 245 | fprintf(file, " indicatorDrivesKeyboard;\n"); |
| 246 | if (led->which_groups != 0) { |
| 247 | if (led->which_groups != XkbIM_UseEffective) { |
| 248 | fprintf(file, " whichGroupState= %s;\n", |
| 249 | XkbIMWhichStateMaskText(led->which_groups, XkbXKBFile)); |
| 250 | } |
| 251 | fprintf(file, " groups= 0x%02x;\n", led->groups); |
| 252 | } |
| 253 | if (led->which_mods != 0) { |
| 254 | if (led->which_mods != XkbIM_UseEffective) { |
| 255 | fprintf(file, " whichModState= %s;\n", |
| 256 | XkbIMWhichStateMaskText(led->which_mods, XkbXKBFile)); |
| 257 | } |
| 258 | fprintf(file, " modifiers= %s;\n", |
| 259 | XkbVModMaskText(xkb, |
| 260 | led->mods.real_mods, led->mods.vmods, |
| 261 | XkbXKBFile)); |
| 262 | } |
| 263 | if (led->ctrls != 0) { |
| 264 | fprintf(file, " controls= %s;\n", |
| 265 | XkbControlsMaskText(led->ctrls, XkbXKBFile)); |
| 266 | } |
| 267 | if (addOn) |
| 268 | (*addOn) (file, xkb, FALSE, TRUE, XkmIndicatorsIndex, priv); |
| 269 | fprintf(file, " };\n"); |
| 270 | return TRUE; |
| 271 | } |
| 272 | |
| 273 | Bool |
| 274 | XkbWriteXKBCompatMap(FILE * file, |
| 275 | XkbDescPtr xkb, |
| 276 | Bool topLevel, |
| 277 | Bool showImplicit, XkbFileAddOnFunc addOn, void *priv) |
| 278 | { |
| 279 | register unsigned i; |
| 280 | XkbSymInterpretPtr interp; |
| 281 | |
| 282 | if ((!xkb) || (!xkb->compat) || (!xkb->compat->sym_interpret)) { |
| 283 | _XkbLibError(_XkbErrMissingCompatMap, "XkbWriteXKBCompatMap", 0); |
| 284 | return FALSE; |
| 285 | } |
| 286 | if ((xkb->names == NULL) || (xkb->names->compat == None)) |
| 287 | fprintf(file, "xkb_compatibility {\n\n"); |
| 288 | else |
| 289 | fprintf(file, "xkb_compatibility \"%s\" {\n\n", |
| 290 | XkbAtomText(xkb->names->compat, XkbXKBFile)); |
| 291 | WriteXKBVModDecl(file, xkb, |
| 292 | (showImplicit ? VMOD_COMMENT_VALUE : VMOD_HIDE_VALUE)); |
| 293 | |
| 294 | fprintf(file, " interpret.useModMapMods= AnyLevel;\n"); |
| 295 | fprintf(file, " interpret.repeat= FALSE;\n"); |
| 296 | fprintf(file, " interpret.locking= FALSE;\n"); |
| 297 | interp = xkb->compat->sym_interpret; |
| 298 | for (i = 0; i < xkb->compat->num_si; i++, interp++) { |
| 299 | fprintf(file, " interpret %s+%s(%s) {\n", |
| 300 | ((interp->sym == NoSymbol) ? "Any" : |
| 301 | XkbKeysymText(interp->sym, XkbXKBFile)), |
| 302 | XkbSIMatchText(interp->match, XkbXKBFile), |
| 303 | XkbModMaskText(interp->mods, XkbXKBFile)); |
| 304 | if (interp->virtual_mod != XkbNoModifier) { |
| 305 | fprintf(file, " virtualModifier= %s;\n", |
| 306 | XkbVModIndexText(xkb, interp->virtual_mod, XkbXKBFile)); |
| 307 | } |
| 308 | if (interp->match & XkbSI_LevelOneOnly) |
| 309 | fprintf(file, " useModMapMods=level1;\n"); |
| 310 | if (interp->flags & XkbSI_LockingKey) |
| 311 | fprintf(file, " locking= TRUE;\n"); |
| 312 | if (interp->flags & XkbSI_AutoRepeat) |
| 313 | fprintf(file, " repeat= TRUE;\n"); |
| 314 | fprintf(file, " action= "); |
| 315 | WriteXKBAction(file, xkb, &interp->act); |
| 316 | fprintf(file, ";\n"); |
| 317 | fprintf(file, " };\n"); |
| 318 | } |
| 319 | for (i = 0; i < XkbNumKbdGroups; i++) { |
| 320 | XkbModsPtr gc; |
| 321 | |
| 322 | gc = &xkb->compat->groups[i]; |
| 323 | if ((gc->real_mods == 0) && (gc->vmods == 0)) |
| 324 | continue; |
| 325 | fprintf(file, " group %d = %s;\n", i + 1, XkbVModMaskText(xkb, |
| 326 | gc-> |
| 327 | real_mods, |
| 328 | gc->vmods, |
| 329 | XkbXKBFile)); |
| 330 | } |
| 331 | if (xkb->indicators) { |
| 332 | for (i = 0; i < XkbNumIndicators; i++) { |
| 333 | XkbIndicatorMapPtr map = &xkb->indicators->maps[i]; |
| 334 | |
| 335 | if ((map->flags != 0) || (map->which_groups != 0) || |
| 336 | (map->groups != 0) || (map->which_mods != 0) || |
| 337 | (map->mods.real_mods != 0) || (map->mods.vmods != 0) || |
| 338 | (map->ctrls != 0)) { |
| 339 | WriteXKBIndicatorMap(file, xkb, xkb->names->indicators[i], map, |
| 340 | addOn, priv); |
| 341 | } |
| 342 | } |
| 343 | } |
| 344 | if (addOn) |
| 345 | (*addOn) (file, xkb, topLevel, showImplicit, XkmCompatMapIndex, priv); |
| 346 | fprintf(file, "};\n\n"); |
| 347 | return TRUE; |
| 348 | } |
| 349 | |
| 350 | Bool |
| 351 | XkbWriteXKBSymbols(FILE * file, |
| 352 | XkbDescPtr xkb, |
| 353 | Bool topLevel, |
| 354 | Bool showImplicit, XkbFileAddOnFunc addOn, void *priv) |
| 355 | { |
| 356 | register unsigned i, tmp; |
| 357 | XkbClientMapPtr map; |
| 358 | XkbServerMapPtr srv; |
| 359 | Bool showActions; |
| 360 | |
| 361 | if (!xkb) { |
| 362 | _XkbLibError(_XkbErrMissingSymbols, "XkbWriteXKBSymbols", 0); |
| 363 | return FALSE; |
| 364 | } |
| 365 | |
| 366 | map = xkb->map; |
| 367 | if ((!map) || (!map->syms) || (!map->key_sym_map)) { |
| 368 | _XkbLibError(_XkbErrMissingSymbols, "XkbWriteXKBSymbols", 0); |
| 369 | return FALSE; |
| 370 | } |
| 371 | if ((!xkb->names) || (!xkb->names->keys)) { |
| 372 | _XkbLibError(_XkbErrMissingNames, "XkbWriteXKBSymbols", 0); |
| 373 | return FALSE; |
| 374 | } |
| 375 | if ((xkb->names == NULL) || (xkb->names->symbols == None)) |
| 376 | fprintf(file, "xkb_symbols {\n\n"); |
| 377 | else |
| 378 | fprintf(file, "xkb_symbols \"%s\" {\n\n", |
| 379 | XkbAtomText(xkb->names->symbols, XkbXKBFile)); |
| 380 | for (tmp = i = 0; i < XkbNumKbdGroups; i++) { |
| 381 | if (xkb->names->groups[i] != None) { |
| 382 | fprintf(file, " name[group%d]=\"%s\";\n", i + 1, |
| 383 | XkbAtomText(xkb->names->groups[i], XkbXKBFile)); |
| 384 | tmp++; |
| 385 | } |
| 386 | } |
| 387 | if (tmp > 0) |
| 388 | fprintf(file, "\n"); |
| 389 | srv = xkb->server; |
| 390 | for (i = xkb->min_key_code; i <= xkb->max_key_code; i++) { |
| 391 | Bool simple; |
| 392 | |
| 393 | if ((int) XkbKeyNumSyms(xkb, i) < 1) |
| 394 | continue; |
| 395 | if (XkbFindKeycodeByName(xkb, xkb->names->keys[i].name, TRUE) != i) |
| 396 | continue; |
| 397 | simple = TRUE; |
| 398 | fprintf(file, " key %6s {", |
| 399 | XkbKeyNameText(xkb->names->keys[i].name, XkbXKBFile)); |
| 400 | if (srv->explicit) { |
| 401 | if (((srv->explicit[i] & XkbExplicitKeyTypesMask) != 0) || |
| 402 | (showImplicit)) { |
| 403 | int typeNdx, g; |
| 404 | Bool multi; |
| 405 | const char *comment = " "; |
| 406 | |
| 407 | if ((srv->explicit[i] & XkbExplicitKeyTypesMask) == 0) |
| 408 | comment = "//"; |
| 409 | multi = FALSE; |
| 410 | typeNdx = XkbKeyKeyTypeIndex(xkb, i, 0); |
| 411 | for (g = 1; (g < XkbKeyNumGroups(xkb, i)) && (!multi); g++) { |
| 412 | if (XkbKeyKeyTypeIndex(xkb, i, g) != typeNdx) |
| 413 | multi = TRUE; |
| 414 | } |
| 415 | if (multi) { |
| 416 | for (g = 0; g < XkbKeyNumGroups(xkb, i); g++) { |
| 417 | typeNdx = XkbKeyKeyTypeIndex(xkb, i, g); |
| 418 | if (srv->explicit[i] & (1 << g)) { |
| 419 | fprintf(file, "\n%s type[group%d]= \"%s\",", |
| 420 | comment, g + 1, |
| 421 | XkbAtomText(map->types[typeNdx].name, |
| 422 | XkbXKBFile)); |
| 423 | } |
| 424 | else if (showImplicit) { |
| 425 | fprintf(file, "\n// type[group%d]= \"%s\",", |
| 426 | g + 1, XkbAtomText(map->types[typeNdx].name, |
| 427 | XkbXKBFile)); |
| 428 | } |
| 429 | } |
| 430 | } |
| 431 | else { |
| 432 | fprintf(file, "\n%s type= \"%s\",", comment, |
| 433 | XkbAtomText(map->types[typeNdx].name, XkbXKBFile)); |
| 434 | } |
| 435 | simple = FALSE; |
| 436 | } |
| 437 | if (((srv->explicit[i] & XkbExplicitAutoRepeatMask) != 0) && |
| 438 | (xkb->ctrls != NULL)) { |
| 439 | if (xkb->ctrls->per_key_repeat[i / 8] & (1 << (i % 8))) |
| 440 | fprintf(file, "\n repeat= Yes,"); |
| 441 | else |
| 442 | fprintf(file, "\n repeat= No,"); |
| 443 | simple = FALSE; |
| 444 | } |
| 445 | if ((xkb->server != NULL) && (xkb->server->vmodmap != NULL) && |
| 446 | (xkb->server->vmodmap[i] != 0)) { |
| 447 | if ((srv->explicit[i] & XkbExplicitVModMapMask) != 0) { |
| 448 | fprintf(file, "\n virtualMods= %s,", |
| 449 | XkbVModMaskText(xkb, 0, |
| 450 | xkb->server->vmodmap[i], |
| 451 | XkbXKBFile)); |
| 452 | } |
| 453 | else if (showImplicit) { |
| 454 | fprintf(file, "\n// virtualMods= %s,", |
| 455 | XkbVModMaskText(xkb, 0, |
| 456 | xkb->server->vmodmap[i], |
| 457 | XkbXKBFile)); |
| 458 | } |
| 459 | } |
| 460 | } |
| 461 | switch (XkbOutOfRangeGroupAction(XkbKeyGroupInfo(xkb, i))) { |
| 462 | case XkbClampIntoRange: |
| 463 | fprintf(file, "\n groupsClamp,"); |
| 464 | break; |
| 465 | case XkbRedirectIntoRange: |
| 466 | fprintf(file, "\n groupsRedirect= Group%d,", |
| 467 | XkbOutOfRangeGroupNumber(XkbKeyGroupInfo(xkb, i)) + 1); |
| 468 | break; |
| 469 | } |
| 470 | if (srv->behaviors != NULL) { |
| 471 | unsigned type; |
| 472 | |
| 473 | type = srv->behaviors[i].type & XkbKB_OpMask; |
| 474 | |
| 475 | if (type != XkbKB_Default) { |
| 476 | simple = FALSE; |
| 477 | fprintf(file, "\n %s,", |
| 478 | XkbBehaviorText(xkb, &srv->behaviors[i], XkbXKBFile)); |
| 479 | } |
| 480 | } |
| 481 | if ((srv->explicit == NULL) || showImplicit || |
| 482 | ((srv->explicit[i] & XkbExplicitInterpretMask) != 0)) |
| 483 | showActions = XkbKeyHasActions(xkb, i); |
| 484 | else |
| 485 | showActions = FALSE; |
| 486 | |
| 487 | if (((unsigned) XkbKeyNumGroups(xkb, i) > 1) || showActions) |
| 488 | simple = FALSE; |
| 489 | if (simple) { |
| 490 | KeySym *syms; |
| 491 | unsigned s; |
| 492 | |
| 493 | syms = XkbKeySymsPtr(xkb, i); |
| 494 | fprintf(file, " [ "); |
| 495 | for (s = 0; s < XkbKeyGroupWidth(xkb, i, XkbGroup1Index); s++) { |
| 496 | if (s != 0) |
| 497 | fprintf(file, ", "); |
| 498 | fprintf(file, "%15s", XkbKeysymText(*syms++, XkbXKBFile)); |
| 499 | } |
| 500 | fprintf(file, " ] };\n"); |
| 501 | } |
| 502 | else { |
| 503 | unsigned g, s; |
| 504 | KeySym *syms; |
| 505 | XkbAction *acts; |
| 506 | |
| 507 | syms = XkbKeySymsPtr(xkb, i); |
| 508 | acts = XkbKeyActionsPtr(xkb, i); |
| 509 | for (g = 0; g < XkbKeyNumGroups(xkb, i); g++) { |
| 510 | if (g != 0) |
| 511 | fprintf(file, ","); |
| 512 | fprintf(file, "\n symbols[Group%d]= [ ", g + 1); |
| 513 | for (s = 0; s < XkbKeyGroupWidth(xkb, i, g); s++) { |
| 514 | if (s != 0) |
| 515 | fprintf(file, ", "); |
| 516 | fprintf(file, "%15s", XkbKeysymText(syms[s], XkbXKBFile)); |
| 517 | } |
| 518 | fprintf(file, " ]"); |
| 519 | syms += XkbKeyGroupsWidth(xkb, i); |
| 520 | if (showActions) { |
| 521 | fprintf(file, ",\n actions[Group%d]= [ ", g + 1); |
| 522 | for (s = 0; s < XkbKeyGroupWidth(xkb, i, g); s++) { |
| 523 | if (s != 0) |
| 524 | fprintf(file, ", "); |
| 525 | WriteXKBAction(file, xkb, (XkbAnyAction *) &acts[s]); |
| 526 | } |
| 527 | fprintf(file, " ]"); |
| 528 | acts += XkbKeyGroupsWidth(xkb, i); |
| 529 | } |
| 530 | } |
| 531 | fprintf(file, "\n };\n"); |
| 532 | } |
| 533 | } |
| 534 | if (map && map->modmap) { |
| 535 | for (i = xkb->min_key_code; i <= xkb->max_key_code; i++) { |
| 536 | if (map->modmap[i] != 0) { |
| 537 | register int n, bit; |
| 538 | |
| 539 | for (bit = 1, n = 0; n < XkbNumModifiers; n++, bit <<= 1) { |
| 540 | if (map->modmap[i] & bit) { |
| 541 | char buf[5]; |
| 542 | |
| 543 | memcpy(buf, xkb->names->keys[i].name, 4); |
| 544 | buf[4] = '\0'; |
| 545 | fprintf(file, " modifier_map %s { <%s> };\n", |
| 546 | XkbModIndexText(n, XkbXKBFile), buf); |
| 547 | } |
| 548 | } |
| 549 | } |
| 550 | } |
| 551 | } |
| 552 | if (addOn) |
| 553 | (*addOn) (file, xkb, topLevel, showImplicit, XkmSymbolsIndex, priv); |
| 554 | fprintf(file, "};\n\n"); |
| 555 | return TRUE; |
| 556 | } |
| 557 | |
| 558 | static Bool |
| 559 | WriteXKBOutline(FILE * file, |
| 560 | XkbShapePtr shape, |
| 561 | XkbOutlinePtr outline, int lastRadius, int first, int indent) |
| 562 | { |
| 563 | register int i; |
| 564 | XkbPointPtr pt; |
| 565 | char *iStr; |
| 566 | |
| 567 | fprintf(file, "%s", iStr = XkbIndentText(first)); |
| 568 | if (first != indent) |
| 569 | iStr = XkbIndentText(indent); |
| 570 | if (outline->corner_radius != lastRadius) { |
| 571 | fprintf(file, "corner= %s,", |
| 572 | XkbGeomFPText(outline->corner_radius, XkbMessage)); |
| 573 | if (shape != NULL) { |
| 574 | fprintf(file, "\n%s", iStr); |
| 575 | } |
| 576 | } |
| 577 | if (shape) { |
| 578 | if (outline == shape->approx) |
| 579 | fprintf(file, "approx= "); |
| 580 | else if (outline == shape->primary) |
| 581 | fprintf(file, "primary= "); |
| 582 | } |
| 583 | fprintf(file, "{"); |
| 584 | for (pt = outline->points, i = 0; i < outline->num_points; i++, pt++) { |
| 585 | if (i == 0) |
| 586 | fprintf(file, " "); |
| 587 | else if ((i % 4) == 0) |
| 588 | fprintf(file, ",\n%s ", iStr); |
| 589 | else |
| 590 | fprintf(file, ", "); |
| 591 | fprintf(file, "[ %3s, %3s ]", XkbGeomFPText(pt->x, XkbXKBFile), |
| 592 | XkbGeomFPText(pt->y, XkbXKBFile)); |
| 593 | } |
| 594 | fprintf(file, " }"); |
| 595 | return TRUE; |
| 596 | } |
| 597 | |
| 598 | static Bool |
| 599 | WriteXKBDoodad(FILE * file, |
| 600 | unsigned indent, XkbGeometryPtr geom, XkbDoodadPtr doodad) |
| 601 | { |
| 602 | register char *i_str; |
| 603 | XkbShapePtr shape; |
| 604 | XkbColorPtr color; |
| 605 | |
| 606 | i_str = XkbIndentText(indent); |
| 607 | fprintf(file, "%s%s \"%s\" {\n", i_str, |
| 608 | XkbDoodadTypeText(doodad->any.type, XkbMessage), |
| 609 | XkbAtomText(doodad->any.name, XkbMessage)); |
| 610 | fprintf(file, "%s top= %s;\n", i_str, |
| 611 | XkbGeomFPText(doodad->any.top, XkbXKBFile)); |
| 612 | fprintf(file, "%s left= %s;\n", i_str, |
| 613 | XkbGeomFPText(doodad->any.left, XkbXKBFile)); |
| 614 | fprintf(file, "%s priority= %d;\n", i_str, doodad->any.priority); |
| 615 | switch (doodad->any.type) { |
| 616 | case XkbOutlineDoodad: |
| 617 | case XkbSolidDoodad: |
| 618 | if (doodad->shape.angle != 0) { |
| 619 | fprintf(file, "%s angle= %s;\n", i_str, |
| 620 | XkbGeomFPText(doodad->shape.angle, XkbXKBFile)); |
| 621 | } |
| 622 | if (doodad->shape.color_ndx != 0) { |
| 623 | fprintf(file, "%s color= \"%s\";\n", i_str, |
| 624 | XkbShapeDoodadColor(geom, &doodad->shape)->spec); |
| 625 | } |
| 626 | shape = XkbShapeDoodadShape(geom, &doodad->shape); |
| 627 | fprintf(file, "%s shape= \"%s\";\n", i_str, |
| 628 | XkbAtomText(shape->name, XkbXKBFile)); |
| 629 | break; |
| 630 | case XkbTextDoodad: |
| 631 | if (doodad->text.angle != 0) { |
| 632 | fprintf(file, "%s angle= %s;\n", i_str, |
| 633 | XkbGeomFPText(doodad->text.angle, XkbXKBFile)); |
| 634 | } |
| 635 | if (doodad->text.width != 0) { |
| 636 | fprintf(file, "%s width= %s;\n", i_str, |
| 637 | XkbGeomFPText(doodad->text.width, XkbXKBFile)); |
| 638 | |
| 639 | } |
| 640 | if (doodad->text.height != 0) { |
| 641 | fprintf(file, "%s height= %s;\n", i_str, |
| 642 | XkbGeomFPText(doodad->text.height, XkbXKBFile)); |
| 643 | |
| 644 | } |
| 645 | if (doodad->text.color_ndx != 0) { |
| 646 | color = XkbTextDoodadColor(geom, &doodad->text); |
| 647 | fprintf(file, "%s color= \"%s\";\n", i_str, |
| 648 | XkbStringText(color->spec, XkbXKBFile)); |
| 649 | } |
| 650 | fprintf(file, "%s XFont= \"%s\";\n", i_str, |
| 651 | XkbStringText(doodad->text.font, XkbXKBFile)); |
| 652 | fprintf(file, "%s text= \"%s\";\n", i_str, |
| 653 | XkbStringText(doodad->text.text, XkbXKBFile)); |
| 654 | break; |
| 655 | case XkbIndicatorDoodad: |
| 656 | shape = XkbIndicatorDoodadShape(geom, &doodad->indicator); |
| 657 | color = XkbIndicatorDoodadOnColor(geom, &doodad->indicator); |
| 658 | fprintf(file, "%s onColor= \"%s\";\n", i_str, |
| 659 | XkbStringText(color->spec, XkbXKBFile)); |
| 660 | color = XkbIndicatorDoodadOffColor(geom, &doodad->indicator); |
| 661 | fprintf(file, "%s offColor= \"%s\";\n", i_str, |
| 662 | XkbStringText(color->spec, XkbXKBFile)); |
| 663 | fprintf(file, "%s shape= \"%s\";\n", i_str, |
| 664 | XkbAtomText(shape->name, XkbXKBFile)); |
| 665 | break; |
| 666 | case XkbLogoDoodad: |
| 667 | fprintf(file, "%s logoName= \"%s\";\n", i_str, |
| 668 | XkbStringText(doodad->logo.logo_name, XkbXKBFile)); |
| 669 | if (doodad->shape.angle != 0) { |
| 670 | fprintf(file, "%s angle= %s;\n", i_str, |
| 671 | XkbGeomFPText(doodad->logo.angle, XkbXKBFile)); |
| 672 | } |
| 673 | if (doodad->shape.color_ndx != 0) { |
| 674 | fprintf(file, "%s color= \"%s\";\n", i_str, |
| 675 | XkbLogoDoodadColor(geom, &doodad->logo)->spec); |
| 676 | } |
| 677 | shape = XkbLogoDoodadShape(geom, &doodad->logo); |
| 678 | fprintf(file, "%s shape= \"%s\";\n", i_str, |
| 679 | XkbAtomText(shape->name, XkbXKBFile)); |
| 680 | break; |
| 681 | } |
| 682 | fprintf(file, "%s};\n", i_str); |
| 683 | return TRUE; |
| 684 | } |
| 685 | |
| 686 | /*ARGSUSED*/ static Bool |
| 687 | WriteXKBOverlay(FILE * file, |
| 688 | unsigned indent, XkbGeometryPtr geom, XkbOverlayPtr ol) |
| 689 | { |
| 690 | register char *i_str; |
| 691 | int r, k, nOut; |
| 692 | XkbOverlayRowPtr row; |
| 693 | XkbOverlayKeyPtr key; |
| 694 | |
| 695 | i_str = XkbIndentText(indent); |
| 696 | if (ol->name != None) { |
| 697 | fprintf(file, "%soverlay \"%s\" {\n", i_str, |
| 698 | XkbAtomText(ol->name, XkbMessage)); |
| 699 | } |
| 700 | else |
| 701 | fprintf(file, "%soverlay {\n", i_str); |
| 702 | for (nOut = r = 0, row = ol->rows; r < ol->num_rows; r++, row++) { |
| 703 | for (k = 0, key = row->keys; k < row->num_keys; k++, key++) { |
| 704 | char *over, *under; |
| 705 | |
| 706 | over = XkbKeyNameText(key->over.name, XkbXKBFile); |
| 707 | under = XkbKeyNameText(key->under.name, XkbXKBFile); |
| 708 | if (nOut == 0) |
| 709 | fprintf(file, "%s %6s=%6s", i_str, under, over); |
| 710 | else if ((nOut % 4) == 0) |
| 711 | fprintf(file, ",\n%s %6s=%6s", i_str, under, over); |
| 712 | else |
| 713 | fprintf(file, ", %6s=%6s", under, over); |
| 714 | nOut++; |
| 715 | } |
| 716 | } |
| 717 | fprintf(file, "\n%s};\n", i_str); |
| 718 | return TRUE; |
| 719 | } |
| 720 | |
| 721 | static Bool |
| 722 | WriteXKBSection(FILE * file, XkbSectionPtr s, XkbGeometryPtr geom) |
| 723 | { |
| 724 | register int i; |
| 725 | XkbRowPtr row; |
| 726 | int dfltKeyColor = 0; |
| 727 | |
| 728 | fprintf(file, " section \"%s\" {\n", XkbAtomText(s->name, XkbXKBFile)); |
| 729 | if (s->rows && (s->rows->num_keys > 0)) { |
| 730 | dfltKeyColor = s->rows->keys[0].color_ndx; |
| 731 | fprintf(file, " key.color= \"%s\";\n", |
| 732 | XkbStringText(geom->colors[dfltKeyColor].spec, XkbXKBFile)); |
| 733 | } |
| 734 | fprintf(file, " priority= %d;\n", s->priority); |
| 735 | fprintf(file, " top= %s;\n", |
| 736 | XkbGeomFPText(s->top, XkbXKBFile)); |
| 737 | fprintf(file, " left= %s;\n", |
| 738 | XkbGeomFPText(s->left, XkbXKBFile)); |
| 739 | fprintf(file, " width= %s;\n", |
| 740 | XkbGeomFPText(s->width, XkbXKBFile)); |
| 741 | fprintf(file, " height= %s;\n", |
| 742 | XkbGeomFPText(s->height, XkbXKBFile)); |
| 743 | if (s->angle != 0) { |
| 744 | fprintf(file, " angle= %s;\n", |
| 745 | XkbGeomFPText(s->angle, XkbXKBFile)); |
| 746 | } |
| 747 | for (i = 0, row = s->rows; i < s->num_rows; i++, row++) { |
| 748 | fprintf(file, " row {\n"); |
| 749 | fprintf(file, " top= %s;\n", |
| 750 | XkbGeomFPText(row->top, XkbXKBFile)); |
| 751 | fprintf(file, " left= %s;\n", |
| 752 | XkbGeomFPText(row->left, XkbXKBFile)); |
| 753 | if (row->vertical) |
| 754 | fprintf(file, " vertical;\n"); |
| 755 | if (row->num_keys > 0) { |
| 756 | register int k; |
| 757 | register XkbKeyPtr key; |
| 758 | int forceNL = 0; |
| 759 | int nThisLine = 0; |
| 760 | |
| 761 | fprintf(file, " keys {\n"); |
| 762 | for (k = 0, key = row->keys; k < row->num_keys; k++, key++) { |
| 763 | XkbShapePtr shape; |
| 764 | |
| 765 | if (key->color_ndx != dfltKeyColor) |
| 766 | forceNL = 1; |
| 767 | if (k == 0) { |
| 768 | fprintf(file, " "); |
| 769 | nThisLine = 0; |
| 770 | } |
| 771 | else if (((nThisLine % 2) == 1) || (forceNL)) { |
| 772 | fprintf(file, ",\n "); |
| 773 | forceNL = nThisLine = 0; |
| 774 | } |
| 775 | else { |
| 776 | fprintf(file, ", "); |
| 777 | nThisLine++; |
| 778 | } |
| 779 | shape = XkbKeyShape(geom, key); |
| 780 | fprintf(file, "{ %6s, \"%s\", %3s", |
| 781 | XkbKeyNameText(key->name.name, XkbXKBFile), |
| 782 | XkbAtomText(shape->name, XkbXKBFile), |
| 783 | XkbGeomFPText(key->gap, XkbXKBFile)); |
| 784 | if (key->color_ndx != dfltKeyColor) { |
| 785 | fprintf(file, ", color=\"%s\"", |
| 786 | XkbKeyColor(geom, key)->spec); |
| 787 | forceNL = 1; |
| 788 | } |
| 789 | fprintf(file, " }"); |
| 790 | } |
| 791 | fprintf(file, "\n };\n"); |
| 792 | } |
| 793 | fprintf(file, " };\n"); |
| 794 | } |
| 795 | if (s->doodads != NULL) { |
| 796 | XkbDoodadPtr doodad; |
| 797 | |
| 798 | for (i = 0, doodad = s->doodads; i < s->num_doodads; i++, doodad++) { |
| 799 | WriteXKBDoodad(file, 8, geom, doodad); |
| 800 | } |
| 801 | } |
| 802 | if (s->overlays != NULL) { |
| 803 | XkbOverlayPtr ol; |
| 804 | |
| 805 | for (i = 0, ol = s->overlays; i < s->num_overlays; i++, ol++) { |
| 806 | WriteXKBOverlay(file, 8, geom, ol); |
| 807 | } |
| 808 | } |
| 809 | fprintf(file, " }; // End of \"%s\" section\n\n", |
| 810 | XkbAtomText(s->name, XkbXKBFile)); |
| 811 | return TRUE; |
| 812 | } |
| 813 | |
| 814 | Bool |
| 815 | XkbWriteXKBGeometry(FILE * file, |
| 816 | XkbDescPtr xkb, |
| 817 | Bool topLevel, |
| 818 | Bool showImplicit, XkbFileAddOnFunc addOn, void *priv) |
| 819 | { |
| 820 | register unsigned i, n; |
| 821 | XkbGeometryPtr geom; |
| 822 | |
| 823 | if ((!xkb) || (!xkb->geom)) { |
| 824 | _XkbLibError(_XkbErrMissingGeometry, "XkbWriteXKBGeometry", 0); |
| 825 | return FALSE; |
| 826 | } |
| 827 | geom = xkb->geom; |
| 828 | if (geom->name == None) |
| 829 | fprintf(file, "xkb_geometry {\n\n"); |
| 830 | else |
| 831 | fprintf(file, "xkb_geometry \"%s\" {\n\n", |
| 832 | XkbAtomText(geom->name, XkbXKBFile)); |
| 833 | fprintf(file, " width= %s;\n", |
| 834 | XkbGeomFPText(geom->width_mm, XkbXKBFile)); |
| 835 | fprintf(file, " height= %s;\n\n", |
| 836 | XkbGeomFPText(geom->height_mm, XkbXKBFile)); |
| 837 | |
| 838 | if (geom->key_aliases != NULL) { |
| 839 | XkbKeyAliasPtr pAl; |
| 840 | |
| 841 | pAl = geom->key_aliases; |
| 842 | for (i = 0; i < geom->num_key_aliases; i++, pAl++) { |
| 843 | fprintf(file, " alias %6s = %6s;\n", |
| 844 | XkbKeyNameText(pAl->alias, XkbXKBFile), |
| 845 | XkbKeyNameText(pAl->real, XkbXKBFile)); |
| 846 | } |
| 847 | fprintf(file, "\n"); |
| 848 | } |
| 849 | |
| 850 | if (geom->base_color != NULL) |
| 851 | fprintf(file, " baseColor= \"%s\";\n", |
| 852 | XkbStringText(geom->base_color->spec, XkbXKBFile)); |
| 853 | if (geom->label_color != NULL) |
| 854 | fprintf(file, " labelColor= \"%s\";\n", |
| 855 | XkbStringText(geom->label_color->spec, XkbXKBFile)); |
| 856 | if (geom->label_font != NULL) |
| 857 | fprintf(file, " xfont= \"%s\";\n", |
| 858 | XkbStringText(geom->label_font, XkbXKBFile)); |
| 859 | if ((geom->num_colors > 0) && (showImplicit)) { |
| 860 | XkbColorPtr color; |
| 861 | |
| 862 | for (color = geom->colors, i = 0; i < geom->num_colors; i++, color++) { |
| 863 | fprintf(file, "// color[%d]= \"%s\"\n", i, |
| 864 | XkbStringText(color->spec, XkbXKBFile)); |
| 865 | } |
| 866 | fprintf(file, "\n"); |
| 867 | } |
| 868 | if (geom->num_properties > 0) { |
| 869 | XkbPropertyPtr prop; |
| 870 | |
| 871 | for (prop = geom->properties, i = 0; i < geom->num_properties; |
| 872 | i++, prop++) { |
| 873 | fprintf(file, " %s= \"%s\";\n", prop->name, |
| 874 | XkbStringText(prop->value, XkbXKBFile)); |
| 875 | } |
| 876 | fprintf(file, "\n"); |
| 877 | } |
| 878 | if (geom->num_shapes > 0) { |
| 879 | XkbShapePtr shape; |
| 880 | XkbOutlinePtr outline; |
| 881 | int lastR; |
| 882 | |
| 883 | for (shape = geom->shapes, i = 0; i < geom->num_shapes; i++, shape++) { |
| 884 | lastR = 0; |
| 885 | fprintf(file, " shape \"%s\" {", |
| 886 | XkbAtomText(shape->name, XkbXKBFile)); |
| 887 | outline = shape->outlines; |
| 888 | if (shape->num_outlines > 1) { |
| 889 | for (n = 0; n < shape->num_outlines; n++, outline++) { |
| 890 | if (n == 0) |
| 891 | fprintf(file, "\n"); |
| 892 | else |
| 893 | fprintf(file, ",\n"); |
| 894 | WriteXKBOutline(file, shape, outline, lastR, 8, 8); |
| 895 | lastR = outline->corner_radius; |
| 896 | } |
| 897 | fprintf(file, "\n };\n"); |
| 898 | } |
| 899 | else { |
| 900 | WriteXKBOutline(file, NULL, outline, lastR, 1, 8); |
| 901 | fprintf(file, " };\n"); |
| 902 | } |
| 903 | } |
| 904 | } |
| 905 | if (geom->num_sections > 0) { |
| 906 | XkbSectionPtr section; |
| 907 | |
| 908 | for (section = geom->sections, i = 0; i < geom->num_sections; |
| 909 | i++, section++) { |
| 910 | WriteXKBSection(file, section, geom); |
| 911 | } |
| 912 | } |
| 913 | if (geom->num_doodads > 0) { |
| 914 | XkbDoodadPtr doodad; |
| 915 | |
| 916 | for (i = 0, doodad = geom->doodads; i < geom->num_doodads; |
| 917 | i++, doodad++) { |
| 918 | WriteXKBDoodad(file, 4, geom, doodad); |
| 919 | } |
| 920 | } |
| 921 | if (addOn) |
| 922 | (*addOn) (file, xkb, topLevel, showImplicit, XkmGeometryIndex, priv); |
| 923 | fprintf(file, "};\n\n"); |
| 924 | return TRUE; |
| 925 | } |