xkbtext.c revision 35c4bbdf
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
35#include <X11/Xos.h>
36
37#include <X11/X.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#include "xkbgeom.h"
47
48/***====================================================================***/
49
50#define	BUFFER_SIZE	512
51
52static char textBuffer[BUFFER_SIZE];
53static int tbNext = 0;
54
55static char *
56tbGetBuffer(unsigned size)
57{
58    char *rtrn;
59
60    if (size >= BUFFER_SIZE)
61        return NULL;
62    if ((BUFFER_SIZE - tbNext) <= size)
63        tbNext = 0;
64    rtrn = &textBuffer[tbNext];
65    tbNext += size;
66    return rtrn;
67}
68
69/***====================================================================***/
70
71char *
72XkbAtomText(Atom atm, unsigned format)
73{
74    const char *atmstr;
75    char *rtrn, *tmp;
76
77    atmstr = NameForAtom(atm);
78    if (atmstr != NULL) {
79        int len;
80
81        len = strlen(atmstr) + 1;
82        if (len > BUFFER_SIZE)
83            len = BUFFER_SIZE - 2;
84        rtrn = tbGetBuffer(len);
85        strlcpy(rtrn, atmstr, len);
86    }
87    else {
88        rtrn = tbGetBuffer(1);
89        rtrn[0] = '\0';
90    }
91    if (format == XkbCFile) {
92        for (tmp = rtrn; *tmp != '\0'; tmp++) {
93            if ((tmp == rtrn) && (!isalpha(*tmp)))
94                *tmp = '_';
95            else if (!isalnum(*tmp))
96                *tmp = '_';
97        }
98    }
99    return XkbStringText(rtrn, format);
100}
101
102/***====================================================================***/
103
104char *
105XkbVModIndexText(XkbDescPtr xkb, unsigned ndx, unsigned format)
106{
107    register int len;
108    register Atom *vmodNames;
109    char *rtrn;
110    const char *tmp;
111    char numBuf[20];
112
113    if (xkb && xkb->names)
114        vmodNames = xkb->names->vmods;
115    else
116        vmodNames = NULL;
117
118    tmp = NULL;
119    if (ndx >= XkbNumVirtualMods)
120        tmp = "illegal";
121    else if (vmodNames && (vmodNames[ndx] != None))
122        tmp = NameForAtom(vmodNames[ndx]);
123    if (tmp == NULL) {
124        snprintf(numBuf, sizeof(numBuf), "%d", ndx);
125        tmp = numBuf;
126    }
127
128    len = strlen(tmp) + 1;
129    if (format == XkbCFile)
130        len += 4;
131    if (len >= BUFFER_SIZE)
132        len = BUFFER_SIZE - 1;
133    rtrn = tbGetBuffer(len);
134    if (format == XkbCFile) {
135        strcpy(rtrn, "vmod_");
136        strncpy(&rtrn[5], tmp, len - 4);
137    }
138    else
139        strncpy(rtrn, tmp, len);
140    return rtrn;
141}
142
143char *
144XkbVModMaskText(XkbDescPtr xkb,
145                unsigned modMask, unsigned mask, unsigned format)
146{
147    register int i, bit;
148    int len;
149    char *mm, *rtrn;
150    char *str, buf[BUFFER_SIZE];
151
152    if ((modMask == 0) && (mask == 0)) {
153        rtrn = tbGetBuffer(5);
154        if (format == XkbCFile)
155            sprintf(rtrn, "0");
156        else
157            sprintf(rtrn, "none");
158        return rtrn;
159    }
160    if (modMask != 0)
161        mm = XkbModMaskText(modMask, format);
162    else
163        mm = NULL;
164
165    str = buf;
166    buf[0] = '\0';
167    if (mask) {
168        char *tmp;
169
170        for (i = 0, bit = 1; i < XkbNumVirtualMods; i++, bit <<= 1) {
171            if (mask & bit) {
172                tmp = XkbVModIndexText(xkb, i, format);
173                len = strlen(tmp) + 1 + (str == buf ? 0 : 1);
174                if (format == XkbCFile)
175                    len += 4;
176                if ((str - (buf + len)) <= BUFFER_SIZE) {
177                    if (str != buf) {
178                        if (format == XkbCFile)
179                            *str++ = '|';
180                        else
181                            *str++ = '+';
182                        len--;
183                    }
184                }
185                if (format == XkbCFile)
186                    sprintf(str, "%sMask", tmp);
187                else
188                    strcpy(str, tmp);
189                str = &str[len - 1];
190            }
191        }
192        str = buf;
193    }
194    else
195        str = NULL;
196    if (mm)
197        len = strlen(mm);
198    else
199        len = 0;
200    if (str)
201        len += strlen(str) + (mm == NULL ? 0 : 1);
202    if (len >= BUFFER_SIZE)
203        len = BUFFER_SIZE - 1;
204    rtrn = tbGetBuffer(len + 1);
205    rtrn[0] = '\0';
206
207    if (mm != NULL) {
208        i = strlen(mm);
209        if (i > len)
210            i = len;
211        strcpy(rtrn, mm);
212    }
213    else {
214        i = 0;
215    }
216    if (str != NULL) {
217        if (mm != NULL) {
218            if (format == XkbCFile)
219                strcat(rtrn, "|");
220            else
221                strcat(rtrn, "+");
222        }
223        strncat(rtrn, str, len - i);
224    }
225    rtrn[len] = '\0';
226    return rtrn;
227}
228
229static const char *modNames[XkbNumModifiers] = {
230    "Shift", "Lock", "Control", "Mod1", "Mod2", "Mod3", "Mod4", "Mod5"
231};
232
233char *
234XkbModIndexText(unsigned ndx, unsigned format)
235{
236    char *rtrn;
237    char buf[100];
238
239    if (format == XkbCFile) {
240        if (ndx < XkbNumModifiers)
241            snprintf(buf, sizeof(buf), "%sMapIndex", modNames[ndx]);
242        else if (ndx == XkbNoModifier)
243            snprintf(buf, sizeof(buf), "XkbNoModifier");
244        else
245            snprintf(buf, sizeof(buf), "0x%02x", ndx);
246    }
247    else {
248        if (ndx < XkbNumModifiers)
249            strcpy(buf, modNames[ndx]);
250        else if (ndx == XkbNoModifier)
251            strcpy(buf, "none");
252        else
253            snprintf(buf, sizeof(buf), "ILLEGAL_%02x", ndx);
254    }
255    rtrn = tbGetBuffer(strlen(buf) + 1);
256    strcpy(rtrn, buf);
257    return rtrn;
258}
259
260char *
261XkbModMaskText(unsigned mask, unsigned format)
262{
263    register int i, bit;
264    char buf[64], *rtrn;
265
266    if ((mask & 0xff) == 0xff) {
267        if (format == XkbCFile)
268            strcpy(buf, "0xff");
269        else
270            strcpy(buf, "all");
271    }
272    else if ((mask & 0xff) == 0) {
273        if (format == XkbCFile)
274            strcpy(buf, "0");
275        else
276            strcpy(buf, "none");
277    }
278    else {
279        char *str = buf;
280
281        buf[0] = '\0';
282        for (i = 0, bit = 1; i < XkbNumModifiers; i++, bit <<= 1) {
283            if (mask & bit) {
284                if (str != buf) {
285                    if (format == XkbCFile)
286                        *str++ = '|';
287                    else
288                        *str++ = '+';
289                }
290                strcpy(str, modNames[i]);
291                str = &str[strlen(str)];
292                if (format == XkbCFile) {
293                    strcpy(str, "Mask");
294                    str += 4;
295                }
296            }
297        }
298    }
299    rtrn = tbGetBuffer(strlen(buf) + 1);
300    strcpy(rtrn, buf);
301    return rtrn;
302}
303
304/***====================================================================***/
305
306 /*ARGSUSED*/ char *
307XkbConfigText(unsigned config, unsigned format)
308{
309    static char *buf;
310
311    buf = tbGetBuffer(32);
312    switch (config) {
313    case XkmSemanticsFile:
314        strcpy(buf, "Semantics");
315        break;
316    case XkmLayoutFile:
317        strcpy(buf, "Layout");
318        break;
319    case XkmKeymapFile:
320        strcpy(buf, "Keymap");
321        break;
322    case XkmGeometryFile:
323    case XkmGeometryIndex:
324        strcpy(buf, "Geometry");
325        break;
326    case XkmTypesIndex:
327        strcpy(buf, "Types");
328        break;
329    case XkmCompatMapIndex:
330        strcpy(buf, "CompatMap");
331        break;
332    case XkmSymbolsIndex:
333        strcpy(buf, "Symbols");
334        break;
335    case XkmIndicatorsIndex:
336        strcpy(buf, "Indicators");
337        break;
338    case XkmKeyNamesIndex:
339        strcpy(buf, "KeyNames");
340        break;
341    case XkmVirtualModsIndex:
342        strcpy(buf, "VirtualMods");
343        break;
344    default:
345        sprintf(buf, "unknown(%d)", config);
346        break;
347    }
348    return buf;
349}
350
351/***====================================================================***/
352
353char *
354XkbKeysymText(KeySym sym, unsigned format)
355{
356    static char buf[32];
357
358    if (sym == NoSymbol)
359        strcpy(buf, "NoSymbol");
360    else
361        snprintf(buf, sizeof(buf), "0x%lx", (long) sym);
362    return buf;
363}
364
365char *
366XkbKeyNameText(char *name, unsigned format)
367{
368    char *buf;
369
370    if (format == XkbCFile) {
371        buf = tbGetBuffer(5);
372        memcpy(buf, name, 4);
373        buf[4] = '\0';
374    }
375    else {
376        int len;
377
378        buf = tbGetBuffer(7);
379        buf[0] = '<';
380        memcpy(&buf[1], name, 4);
381        buf[5] = '\0';
382        len = strlen(buf);
383        buf[len++] = '>';
384        buf[len] = '\0';
385    }
386    return buf;
387}
388
389/***====================================================================***/
390
391static const char *siMatchText[5] = {
392    "NoneOf", "AnyOfOrNone", "AnyOf", "AllOf", "Exactly"
393};
394
395const char *
396XkbSIMatchText(unsigned type, unsigned format)
397{
398    static char buf[40];
399    const char *rtrn;
400
401    switch (type & XkbSI_OpMask) {
402    case XkbSI_NoneOf:
403        rtrn = siMatchText[0];
404        break;
405    case XkbSI_AnyOfOrNone:
406        rtrn = siMatchText[1];
407        break;
408    case XkbSI_AnyOf:
409        rtrn = siMatchText[2];
410        break;
411    case XkbSI_AllOf:
412        rtrn = siMatchText[3];
413        break;
414    case XkbSI_Exactly:
415        rtrn = siMatchText[4];
416        break;
417    default:
418        snprintf(buf, sizeof(buf), "0x%x", type & XkbSI_OpMask);
419        return buf;
420    }
421    if (format == XkbCFile) {
422        if (type & XkbSI_LevelOneOnly)
423            snprintf(buf, sizeof(buf), "XkbSI_LevelOneOnly|XkbSI_%s", rtrn);
424        else
425            snprintf(buf, sizeof(buf), "XkbSI_%s", rtrn);
426        rtrn = buf;
427    }
428    return rtrn;
429}
430
431/***====================================================================***/
432
433static const char *imWhichNames[] = {
434    "base",
435    "latched",
436    "locked",
437    "effective",
438    "compat"
439};
440
441char *
442XkbIMWhichStateMaskText(unsigned use_which, unsigned format)
443{
444    int len;
445    unsigned i, bit, tmp;
446    char *buf;
447
448    if (use_which == 0) {
449        buf = tbGetBuffer(2);
450        strcpy(buf, "0");
451        return buf;
452    }
453    tmp = use_which & XkbIM_UseAnyMods;
454    for (len = i = 0, bit = 1; tmp != 0; i++, bit <<= 1) {
455        if (tmp & bit) {
456            tmp &= ~bit;
457            len += strlen(imWhichNames[i]) + 1;
458            if (format == XkbCFile)
459                len += 9;
460        }
461    }
462    buf = tbGetBuffer(len + 1);
463    tmp = use_which & XkbIM_UseAnyMods;
464    for (len = i = 0, bit = 1; tmp != 0; i++, bit <<= 1) {
465        if (tmp & bit) {
466            tmp &= ~bit;
467            if (format == XkbCFile) {
468                if (len != 0)
469                    buf[len++] = '|';
470                sprintf(&buf[len], "XkbIM_Use%s", imWhichNames[i]);
471                buf[len + 9] = toupper(buf[len + 9]);
472            }
473            else {
474                if (len != 0)
475                    buf[len++] = '+';
476                sprintf(&buf[len], "%s", imWhichNames[i]);
477            }
478            len += strlen(&buf[len]);
479        }
480    }
481    return buf;
482}
483
484static const char *ctrlNames[] = {
485    "repeatKeys",
486    "slowKeys",
487    "bounceKeys",
488    "stickyKeys",
489    "mouseKeys",
490    "mouseKeysAccel",
491    "accessXKeys",
492    "accessXTimeout",
493    "accessXFeedback",
494    "audibleBell",
495    "overlay1",
496    "overlay2",
497    "ignoreGroupLock"
498};
499
500char *
501XkbControlsMaskText(unsigned ctrls, unsigned format)
502{
503    int len;
504    unsigned i, bit, tmp;
505    char *buf;
506
507    if (ctrls == 0) {
508        buf = tbGetBuffer(5);
509        if (format == XkbCFile)
510            strcpy(buf, "0");
511        else
512            strcpy(buf, "none");
513        return buf;
514    }
515    tmp = ctrls & XkbAllBooleanCtrlsMask;
516    for (len = i = 0, bit = 1; tmp != 0; i++, bit <<= 1) {
517        if (tmp & bit) {
518            tmp &= ~bit;
519            len += strlen(ctrlNames[i]) + 1;
520            if (format == XkbCFile)
521                len += 7;
522        }
523    }
524    buf = tbGetBuffer(len + 1);
525    tmp = ctrls & XkbAllBooleanCtrlsMask;
526    for (len = i = 0, bit = 1; tmp != 0; i++, bit <<= 1) {
527        if (tmp & bit) {
528            tmp &= ~bit;
529            if (format == XkbCFile) {
530                if (len != 0)
531                    buf[len++] = '|';
532                sprintf(&buf[len], "Xkb%sMask", ctrlNames[i]);
533                buf[len + 3] = toupper(buf[len + 3]);
534            }
535            else {
536                if (len != 0)
537                    buf[len++] = '+';
538                sprintf(&buf[len], "%s", ctrlNames[i]);
539            }
540            len += strlen(&buf[len]);
541        }
542    }
543    return buf;
544}
545
546/***====================================================================***/
547
548char *
549XkbStringText(char *str, unsigned format)
550{
551    char *buf;
552    register char *in, *out;
553    int len;
554    Bool ok;
555
556    if (str == NULL) {
557        buf = tbGetBuffer(2);
558        buf[0] = '\0';
559        return buf;
560    }
561    else if (format == XkbXKMFile)
562        return str;
563    for (ok = TRUE, len = 0, in = str; *in != '\0'; in++, len++) {
564        if (!isprint(*in)) {
565            ok = FALSE;
566            switch (*in) {
567            case '\n':
568            case '\t':
569            case '\v':
570            case '\b':
571            case '\r':
572            case '\f':
573                len++;
574                break;
575            default:
576                len += 4;
577                break;
578            }
579        }
580    }
581    if (ok)
582        return str;
583    buf = tbGetBuffer(len + 1);
584    for (in = str, out = buf; *in != '\0'; in++) {
585        if (isprint(*in))
586            *out++ = *in;
587        else {
588            *out++ = '\\';
589            if (*in == '\n')
590                *out++ = 'n';
591            else if (*in == '\t')
592                *out++ = 't';
593            else if (*in == '\v')
594                *out++ = 'v';
595            else if (*in == '\b')
596                *out++ = 'b';
597            else if (*in == '\r')
598                *out++ = 'r';
599            else if (*in == '\f')
600                *out++ = 'f';
601            else if ((*in == '\033') && (format == XkbXKMFile)) {
602                *out++ = 'e';
603            }
604            else {
605                *out++ = '0';
606                sprintf(out, "%o", *in);
607                while (*out != '\0')
608                    out++;
609            }
610        }
611    }
612    *out++ = '\0';
613    return buf;
614}
615
616/***====================================================================***/
617
618char *
619XkbGeomFPText(int val, unsigned format)
620{
621    int whole, frac;
622    char *buf;
623
624    buf = tbGetBuffer(12);
625    if (format == XkbCFile) {
626        sprintf(buf, "%d", val);
627    }
628    else {
629        whole = val / XkbGeomPtsPerMM;
630        frac = val % XkbGeomPtsPerMM;
631        if (frac != 0)
632            sprintf(buf, "%d.%d", whole, frac);
633        else
634            sprintf(buf, "%d", whole);
635    }
636    return buf;
637}
638
639char *
640XkbDoodadTypeText(unsigned type, unsigned format)
641{
642    char *buf;
643
644    if (format == XkbCFile) {
645        buf = tbGetBuffer(24);
646        if (type == XkbOutlineDoodad)
647            strcpy(buf, "XkbOutlineDoodad");
648        else if (type == XkbSolidDoodad)
649            strcpy(buf, "XkbSolidDoodad");
650        else if (type == XkbTextDoodad)
651            strcpy(buf, "XkbTextDoodad");
652        else if (type == XkbIndicatorDoodad)
653            strcpy(buf, "XkbIndicatorDoodad");
654        else if (type == XkbLogoDoodad)
655            strcpy(buf, "XkbLogoDoodad");
656        else
657            sprintf(buf, "UnknownDoodad%d", type);
658    }
659    else {
660        buf = tbGetBuffer(12);
661        if (type == XkbOutlineDoodad)
662            strcpy(buf, "outline");
663        else if (type == XkbSolidDoodad)
664            strcpy(buf, "solid");
665        else if (type == XkbTextDoodad)
666            strcpy(buf, "text");
667        else if (type == XkbIndicatorDoodad)
668            strcpy(buf, "indicator");
669        else if (type == XkbLogoDoodad)
670            strcpy(buf, "logo");
671        else
672            sprintf(buf, "unknown%d", type);
673    }
674    return buf;
675}
676
677static const char *actionTypeNames[XkbSA_NumActions] = {
678    "NoAction",
679    "SetMods", "LatchMods", "LockMods",
680    "SetGroup", "LatchGroup", "LockGroup",
681    "MovePtr",
682    "PtrBtn", "LockPtrBtn",
683    "SetPtrDflt",
684    "ISOLock",
685    "Terminate", "SwitchScreen",
686    "SetControls", "LockControls",
687    "ActionMessage",
688    "RedirectKey",
689    "DeviceBtn", "LockDeviceBtn"
690};
691
692const char *
693XkbActionTypeText(unsigned type, unsigned format)
694{
695    static char buf[32];
696    const char *rtrn;
697
698    if (type <= XkbSA_LastAction) {
699        rtrn = actionTypeNames[type];
700        if (format == XkbCFile) {
701            snprintf(buf, sizeof(buf), "XkbSA_%s", rtrn);
702            return buf;
703        }
704        return rtrn;
705    }
706    snprintf(buf, sizeof(buf), "Private");
707    return buf;
708}
709
710/***====================================================================***/
711
712static int
713TryCopyStr(char *to, const char *from, int *pLeft)
714{
715    register int len;
716
717    if (*pLeft > 0) {
718        len = strlen(from);
719        if (len < ((*pLeft) - 3)) {
720            strcat(to, from);
721            *pLeft -= len;
722            return TRUE;
723        }
724    }
725    *pLeft = -1;
726    return FALSE;
727}
728
729 /*ARGSUSED*/ static Bool
730CopyNoActionArgs(XkbDescPtr xkb, XkbAction *action, char *buf, int *sz)
731{
732    return TRUE;
733}
734
735static Bool
736CopyModActionArgs(XkbDescPtr xkb, XkbAction *action, char *buf, int *sz)
737{
738    XkbModAction *act;
739    unsigned tmp;
740
741    act = &action->mods;
742    tmp = XkbModActionVMods(act);
743    TryCopyStr(buf, "modifiers=", sz);
744    if (act->flags & XkbSA_UseModMapMods)
745        TryCopyStr(buf, "modMapMods", sz);
746    else if (act->real_mods || tmp) {
747        TryCopyStr(buf,
748                   XkbVModMaskText(xkb, act->real_mods, tmp, XkbXKBFile), sz);
749    }
750    else
751        TryCopyStr(buf, "none", sz);
752    if (act->type == XkbSA_LockMods)
753        return TRUE;
754    if (act->flags & XkbSA_ClearLocks)
755        TryCopyStr(buf, ",clearLocks", sz);
756    if (act->flags & XkbSA_LatchToLock)
757        TryCopyStr(buf, ",latchToLock", sz);
758    return TRUE;
759}
760
761 /*ARGSUSED*/ static Bool
762CopyGroupActionArgs(XkbDescPtr xkb, XkbAction *action, char *buf, int *sz)
763{
764    XkbGroupAction *act;
765    char tbuf[32];
766
767    act = &action->group;
768    TryCopyStr(buf, "group=", sz);
769    if (act->flags & XkbSA_GroupAbsolute)
770        snprintf(tbuf, sizeof(tbuf), "%d", XkbSAGroup(act) + 1);
771    else if (XkbSAGroup(act) < 0)
772        snprintf(tbuf, sizeof(tbuf), "%d", XkbSAGroup(act));
773    else
774        snprintf(tbuf, sizeof(tbuf), "+%d", XkbSAGroup(act));
775    TryCopyStr(buf, tbuf, sz);
776    if (act->type == XkbSA_LockGroup)
777        return TRUE;
778    if (act->flags & XkbSA_ClearLocks)
779        TryCopyStr(buf, ",clearLocks", sz);
780    if (act->flags & XkbSA_LatchToLock)
781        TryCopyStr(buf, ",latchToLock", sz);
782    return TRUE;
783}
784
785 /*ARGSUSED*/ static Bool
786CopyMovePtrArgs(XkbDescPtr xkb, XkbAction *action, char *buf, int *sz)
787{
788    XkbPtrAction *act;
789    int x, y;
790    char tbuf[32];
791
792    act = &action->ptr;
793    x = XkbPtrActionX(act);
794    y = XkbPtrActionY(act);
795    if ((act->flags & XkbSA_MoveAbsoluteX) || (x < 0))
796        snprintf(tbuf, sizeof(tbuf), "x=%d", x);
797    else
798        snprintf(tbuf, sizeof(tbuf), "x=+%d", x);
799    TryCopyStr(buf, tbuf, sz);
800
801    if ((act->flags & XkbSA_MoveAbsoluteY) || (y < 0))
802        snprintf(tbuf, sizeof(tbuf), ",y=%d", y);
803    else
804        snprintf(tbuf, sizeof(tbuf), ",y=+%d", y);
805    TryCopyStr(buf, tbuf, sz);
806    if (act->flags & XkbSA_NoAcceleration)
807        TryCopyStr(buf, ",!accel", sz);
808    return TRUE;
809}
810
811 /*ARGSUSED*/ static Bool
812CopyPtrBtnArgs(XkbDescPtr xkb, XkbAction *action, char *buf, int *sz)
813{
814    XkbPtrBtnAction *act;
815    char tbuf[32];
816
817    act = &action->btn;
818    TryCopyStr(buf, "button=", sz);
819    if ((act->button > 0) && (act->button < 6)) {
820        snprintf(tbuf, sizeof(tbuf), "%d", act->button);
821        TryCopyStr(buf, tbuf, sz);
822    }
823    else
824        TryCopyStr(buf, "default", sz);
825    if (act->count > 0) {
826        snprintf(tbuf, sizeof(tbuf), ",count=%d", act->count);
827        TryCopyStr(buf, tbuf, sz);
828    }
829    if (action->type == XkbSA_LockPtrBtn) {
830        switch (act->flags & (XkbSA_LockNoUnlock | XkbSA_LockNoLock)) {
831        case XkbSA_LockNoLock:
832            TryCopyStr(buf, ",affect=unlock", sz);
833            break;
834        case XkbSA_LockNoUnlock:
835            TryCopyStr(buf, ",affect=lock", sz);
836            break;
837        case XkbSA_LockNoUnlock | XkbSA_LockNoLock:
838            TryCopyStr(buf, ",affect=neither", sz);
839            break;
840        default:
841            TryCopyStr(buf, ",affect=both", sz);
842            break;
843        }
844    }
845    return TRUE;
846}
847
848 /*ARGSUSED*/ static Bool
849CopySetPtrDfltArgs(XkbDescPtr xkb, XkbAction *action, char *buf, int *sz)
850{
851    XkbPtrDfltAction *act;
852    char tbuf[32];
853
854    act = &action->dflt;
855    if (act->affect == XkbSA_AffectDfltBtn) {
856        TryCopyStr(buf, "affect=button,button=", sz);
857        if ((act->flags & XkbSA_DfltBtnAbsolute) ||
858            (XkbSAPtrDfltValue(act) < 0))
859            snprintf(tbuf, sizeof(tbuf), "%d", XkbSAPtrDfltValue(act));
860        else
861            snprintf(tbuf, sizeof(tbuf), "+%d", XkbSAPtrDfltValue(act));
862        TryCopyStr(buf, tbuf, sz);
863    }
864    return TRUE;
865}
866
867static Bool
868CopyISOLockArgs(XkbDescPtr xkb, XkbAction *action, char *buf, int *sz)
869{
870    XkbISOAction *act;
871    char tbuf[64];
872
873    act = &action->iso;
874    if (act->flags & XkbSA_ISODfltIsGroup) {
875        TryCopyStr(tbuf, "group=", sz);
876        if (act->flags & XkbSA_GroupAbsolute)
877            snprintf(tbuf, sizeof(tbuf), "%d", XkbSAGroup(act) + 1);
878        else if (XkbSAGroup(act) < 0)
879            snprintf(tbuf, sizeof(tbuf), "%d", XkbSAGroup(act));
880        else
881            snprintf(tbuf, sizeof(tbuf), "+%d", XkbSAGroup(act));
882        TryCopyStr(buf, tbuf, sz);
883    }
884    else {
885        unsigned tmp;
886
887        tmp = XkbModActionVMods(act);
888        TryCopyStr(buf, "modifiers=", sz);
889        if (act->flags & XkbSA_UseModMapMods)
890            TryCopyStr(buf, "modMapMods", sz);
891        else if (act->real_mods || tmp) {
892            if (act->real_mods) {
893                TryCopyStr(buf, XkbModMaskText(act->real_mods, XkbXKBFile), sz);
894                if (tmp)
895                    TryCopyStr(buf, "+", sz);
896            }
897            if (tmp)
898                TryCopyStr(buf, XkbVModMaskText(xkb, 0, tmp, XkbXKBFile), sz);
899        }
900        else
901            TryCopyStr(buf, "none", sz);
902    }
903    TryCopyStr(buf, ",affect=", sz);
904    if ((act->affect & XkbSA_ISOAffectMask) == 0)
905        TryCopyStr(buf, "all", sz);
906    else {
907        int nOut = 0;
908
909        if ((act->affect & XkbSA_ISONoAffectMods) == 0) {
910            TryCopyStr(buf, "mods", sz);
911            nOut++;
912        }
913        if ((act->affect & XkbSA_ISONoAffectGroup) == 0) {
914            snprintf(tbuf, sizeof(tbuf), "%sgroups", (nOut > 0 ? "+" : ""));
915            TryCopyStr(buf, tbuf, sz);
916            nOut++;
917        }
918        if ((act->affect & XkbSA_ISONoAffectPtr) == 0) {
919            snprintf(tbuf, sizeof(tbuf), "%spointer", (nOut > 0 ? "+" : ""));
920            TryCopyStr(buf, tbuf, sz);
921            nOut++;
922        }
923        if ((act->affect & XkbSA_ISONoAffectCtrls) == 0) {
924            snprintf(tbuf, sizeof(tbuf), "%scontrols", (nOut > 0 ? "+" : ""));
925            TryCopyStr(buf, tbuf, sz);
926            nOut++;
927        }
928    }
929    return TRUE;
930}
931
932 /*ARGSUSED*/ static Bool
933CopySwitchScreenArgs(XkbDescPtr xkb, XkbAction *action, char *buf, int *sz)
934{
935    XkbSwitchScreenAction *act;
936    char tbuf[32];
937
938    act = &action->screen;
939    if ((act->flags & XkbSA_SwitchAbsolute) || (XkbSAScreen(act) < 0))
940        snprintf(tbuf, sizeof(tbuf), "screen=%d", XkbSAScreen(act));
941    else
942        snprintf(tbuf, sizeof(tbuf), "screen=+%d", XkbSAScreen(act));
943    TryCopyStr(buf, tbuf, sz);
944    if (act->flags & XkbSA_SwitchApplication)
945        TryCopyStr(buf, ",!same", sz);
946    else
947        TryCopyStr(buf, ",same", sz);
948    return TRUE;
949}
950
951 /*ARGSUSED*/ static Bool
952CopySetLockControlsArgs(XkbDescPtr xkb, XkbAction *action, char *buf, int *sz)
953{
954    XkbCtrlsAction *act;
955    unsigned tmp;
956    char tbuf[32];
957
958    act = &action->ctrls;
959    tmp = XkbActionCtrls(act);
960    TryCopyStr(buf, "controls=", sz);
961    if (tmp == 0)
962        TryCopyStr(buf, "none", sz);
963    else if ((tmp & XkbAllBooleanCtrlsMask) == XkbAllBooleanCtrlsMask)
964        TryCopyStr(buf, "all", sz);
965    else {
966        int nOut = 0;
967
968        if (tmp & XkbRepeatKeysMask) {
969            snprintf(tbuf, sizeof(tbuf), "%sRepeatKeys", (nOut > 0 ? "+" : ""));
970            TryCopyStr(buf, tbuf, sz);
971            nOut++;
972        }
973        if (tmp & XkbSlowKeysMask) {
974            snprintf(tbuf, sizeof(tbuf), "%sSlowKeys", (nOut > 0 ? "+" : ""));
975            TryCopyStr(buf, tbuf, sz);
976            nOut++;
977        }
978        if (tmp & XkbBounceKeysMask) {
979            snprintf(tbuf, sizeof(tbuf), "%sBounceKeys", (nOut > 0 ? "+" : ""));
980            TryCopyStr(buf, tbuf, sz);
981            nOut++;
982        }
983        if (tmp & XkbStickyKeysMask) {
984            snprintf(tbuf, sizeof(tbuf), "%sStickyKeys", (nOut > 0 ? "+" : ""));
985            TryCopyStr(buf, tbuf, sz);
986            nOut++;
987        }
988        if (tmp & XkbMouseKeysMask) {
989            snprintf(tbuf, sizeof(tbuf), "%sMouseKeys", (nOut > 0 ? "+" : ""));
990            TryCopyStr(buf, tbuf, sz);
991            nOut++;
992        }
993        if (tmp & XkbMouseKeysAccelMask) {
994            snprintf(tbuf, sizeof(tbuf), "%sMouseKeysAccel",
995                     (nOut > 0 ? "+" : ""));
996            TryCopyStr(buf, tbuf, sz);
997            nOut++;
998        }
999        if (tmp & XkbAccessXKeysMask) {
1000            snprintf(tbuf, sizeof(tbuf), "%sAccessXKeys",
1001                     (nOut > 0 ? "+" : ""));
1002            TryCopyStr(buf, tbuf, sz);
1003            nOut++;
1004        }
1005        if (tmp & XkbAccessXTimeoutMask) {
1006            snprintf(tbuf, sizeof(tbuf), "%sAccessXTimeout",
1007                     (nOut > 0 ? "+" : ""));
1008            TryCopyStr(buf, tbuf, sz);
1009            nOut++;
1010        }
1011        if (tmp & XkbAccessXFeedbackMask) {
1012            snprintf(tbuf, sizeof(tbuf), "%sAccessXFeedback",
1013                     (nOut > 0 ? "+" : ""));
1014            TryCopyStr(buf, tbuf, sz);
1015            nOut++;
1016        }
1017        if (tmp & XkbAudibleBellMask) {
1018            snprintf(tbuf, sizeof(tbuf), "%sAudibleBell",
1019                     (nOut > 0 ? "+" : ""));
1020            TryCopyStr(buf, tbuf, sz);
1021            nOut++;
1022        }
1023        if (tmp & XkbOverlay1Mask) {
1024            snprintf(tbuf, sizeof(tbuf), "%sOverlay1", (nOut > 0 ? "+" : ""));
1025            TryCopyStr(buf, tbuf, sz);
1026            nOut++;
1027        }
1028        if (tmp & XkbOverlay2Mask) {
1029            snprintf(tbuf, sizeof(tbuf), "%sOverlay2", (nOut > 0 ? "+" : ""));
1030            TryCopyStr(buf, tbuf, sz);
1031            nOut++;
1032        }
1033        if (tmp & XkbIgnoreGroupLockMask) {
1034            snprintf(tbuf, sizeof(tbuf), "%sIgnoreGroupLock",
1035                     (nOut > 0 ? "+" : ""));
1036            TryCopyStr(buf, tbuf, sz);
1037            nOut++;
1038        }
1039    }
1040    return TRUE;
1041}
1042
1043 /*ARGSUSED*/ static Bool
1044CopyActionMessageArgs(XkbDescPtr xkb, XkbAction *action, char *buf, int *sz)
1045{
1046    XkbMessageAction *act;
1047    unsigned all;
1048    char tbuf[32];
1049
1050    act = &action->msg;
1051    all = XkbSA_MessageOnPress | XkbSA_MessageOnRelease;
1052    TryCopyStr(buf, "report=", sz);
1053    if ((act->flags & all) == 0)
1054        TryCopyStr(buf, "none", sz);
1055    else if ((act->flags & all) == all)
1056        TryCopyStr(buf, "all", sz);
1057    else if (act->flags & XkbSA_MessageOnPress)
1058        TryCopyStr(buf, "KeyPress", sz);
1059    else
1060        TryCopyStr(buf, "KeyRelease", sz);
1061    snprintf(tbuf, sizeof(tbuf), ",data[0]=0x%02x", act->message[0]);
1062    TryCopyStr(buf, tbuf, sz);
1063    snprintf(tbuf, sizeof(tbuf), ",data[1]=0x%02x", act->message[1]);
1064    TryCopyStr(buf, tbuf, sz);
1065    snprintf(tbuf, sizeof(tbuf), ",data[2]=0x%02x", act->message[2]);
1066    TryCopyStr(buf, tbuf, sz);
1067    snprintf(tbuf, sizeof(tbuf), ",data[3]=0x%02x", act->message[3]);
1068    TryCopyStr(buf, tbuf, sz);
1069    snprintf(tbuf, sizeof(tbuf), ",data[4]=0x%02x", act->message[4]);
1070    TryCopyStr(buf, tbuf, sz);
1071    snprintf(tbuf, sizeof(tbuf), ",data[5]=0x%02x", act->message[5]);
1072    TryCopyStr(buf, tbuf, sz);
1073    return TRUE;
1074}
1075
1076static Bool
1077CopyRedirectKeyArgs(XkbDescPtr xkb, XkbAction *action, char *buf, int *sz)
1078{
1079    XkbRedirectKeyAction *act;
1080    char tbuf[32], *tmp;
1081    unsigned kc;
1082    unsigned vmods, vmods_mask;
1083
1084    act = &action->redirect;
1085    kc = act->new_key;
1086    vmods = XkbSARedirectVMods(act);
1087    vmods_mask = XkbSARedirectVModsMask(act);
1088    if (xkb && xkb->names && xkb->names->keys && (kc <= xkb->max_key_code) &&
1089        (xkb->names->keys[kc].name[0] != '\0')) {
1090        char *kn;
1091
1092        kn = XkbKeyNameText(xkb->names->keys[kc].name, XkbXKBFile);
1093        snprintf(tbuf, sizeof(tbuf), "key=%s", kn);
1094    }
1095    else
1096        snprintf(tbuf, sizeof(tbuf), "key=%d", kc);
1097    TryCopyStr(buf, tbuf, sz);
1098    if ((act->mods_mask == 0) && (vmods_mask == 0))
1099        return TRUE;
1100    if ((act->mods_mask == XkbAllModifiersMask) &&
1101        (vmods_mask == XkbAllVirtualModsMask)) {
1102        tmp = XkbVModMaskText(xkb, act->mods, vmods, XkbXKBFile);
1103        TryCopyStr(buf, ",mods=", sz);
1104        TryCopyStr(buf, tmp, sz);
1105    }
1106    else {
1107        if ((act->mods_mask & act->mods) || (vmods_mask & vmods)) {
1108            tmp = XkbVModMaskText(xkb, act->mods_mask & act->mods,
1109                                  vmods_mask & vmods, XkbXKBFile);
1110            TryCopyStr(buf, ",mods= ", sz);
1111            TryCopyStr(buf, tmp, sz);
1112        }
1113        if ((act->mods_mask & (~act->mods)) || (vmods_mask & (~vmods))) {
1114            tmp = XkbVModMaskText(xkb, act->mods_mask & (~act->mods),
1115                                  vmods_mask & (~vmods), XkbXKBFile);
1116            TryCopyStr(buf, ",clearMods= ", sz);
1117            TryCopyStr(buf, tmp, sz);
1118        }
1119    }
1120    return TRUE;
1121}
1122
1123 /*ARGSUSED*/ static Bool
1124CopyDeviceBtnArgs(XkbDescPtr xkb, XkbAction *action, char *buf, int *sz)
1125{
1126    XkbDeviceBtnAction *act;
1127    char tbuf[32];
1128
1129    act = &action->devbtn;
1130    snprintf(tbuf, sizeof(tbuf), "device= %d", act->device);
1131    TryCopyStr(buf, tbuf, sz);
1132    TryCopyStr(buf, ",button=", sz);
1133    snprintf(tbuf, sizeof(tbuf), "%d", act->button);
1134    TryCopyStr(buf, tbuf, sz);
1135    if (act->count > 0) {
1136        snprintf(tbuf, sizeof(tbuf), ",count=%d", act->count);
1137        TryCopyStr(buf, tbuf, sz);
1138    }
1139    if (action->type == XkbSA_LockDeviceBtn) {
1140        switch (act->flags & (XkbSA_LockNoUnlock | XkbSA_LockNoLock)) {
1141        case XkbSA_LockNoLock:
1142            TryCopyStr(buf, ",affect=unlock", sz);
1143            break;
1144        case XkbSA_LockNoUnlock:
1145            TryCopyStr(buf, ",affect=lock", sz);
1146            break;
1147        case XkbSA_LockNoUnlock | XkbSA_LockNoLock:
1148            TryCopyStr(buf, ",affect=neither", sz);
1149            break;
1150        default:
1151            TryCopyStr(buf, ",affect=both", sz);
1152            break;
1153        }
1154    }
1155    return TRUE;
1156}
1157
1158 /*ARGSUSED*/ static Bool
1159CopyOtherArgs(XkbDescPtr xkb, XkbAction *action, char *buf, int *sz)
1160{
1161    XkbAnyAction *act;
1162    char tbuf[32];
1163
1164    act = &action->any;
1165    snprintf(tbuf, sizeof(tbuf), "type=0x%02x", act->type);
1166    TryCopyStr(buf, tbuf, sz);
1167    snprintf(tbuf, sizeof(tbuf), ",data[0]=0x%02x", act->data[0]);
1168    TryCopyStr(buf, tbuf, sz);
1169    snprintf(tbuf, sizeof(tbuf), ",data[1]=0x%02x", act->data[1]);
1170    TryCopyStr(buf, tbuf, sz);
1171    snprintf(tbuf, sizeof(tbuf), ",data[2]=0x%02x", act->data[2]);
1172    TryCopyStr(buf, tbuf, sz);
1173    snprintf(tbuf, sizeof(tbuf), ",data[3]=0x%02x", act->data[3]);
1174    TryCopyStr(buf, tbuf, sz);
1175    snprintf(tbuf, sizeof(tbuf), ",data[4]=0x%02x", act->data[4]);
1176    TryCopyStr(buf, tbuf, sz);
1177    snprintf(tbuf, sizeof(tbuf), ",data[5]=0x%02x", act->data[5]);
1178    TryCopyStr(buf, tbuf, sz);
1179    snprintf(tbuf, sizeof(tbuf), ",data[6]=0x%02x", act->data[6]);
1180    TryCopyStr(buf, tbuf, sz);
1181    return TRUE;
1182}
1183
1184typedef Bool (*actionCopy) (XkbDescPtr /* xkb */ ,
1185                            XkbAction * /* action */ ,
1186                            char * /* buf */ ,
1187                            int *       /* sz */
1188    );
1189
1190static actionCopy copyActionArgs[XkbSA_NumActions] = {
1191    CopyNoActionArgs /* NoAction     */ ,
1192    CopyModActionArgs /* SetMods      */ ,
1193    CopyModActionArgs /* LatchMods    */ ,
1194    CopyModActionArgs /* LockMods     */ ,
1195    CopyGroupActionArgs /* SetGroup     */ ,
1196    CopyGroupActionArgs /* LatchGroup   */ ,
1197    CopyGroupActionArgs /* LockGroup    */ ,
1198    CopyMovePtrArgs /* MovePtr      */ ,
1199    CopyPtrBtnArgs /* PtrBtn       */ ,
1200    CopyPtrBtnArgs /* LockPtrBtn   */ ,
1201    CopySetPtrDfltArgs /* SetPtrDflt   */ ,
1202    CopyISOLockArgs /* ISOLock      */ ,
1203    CopyNoActionArgs /* Terminate    */ ,
1204    CopySwitchScreenArgs /* SwitchScreen */ ,
1205    CopySetLockControlsArgs /* SetControls  */ ,
1206    CopySetLockControlsArgs /* LockControls */ ,
1207    CopyActionMessageArgs /* ActionMessage */ ,
1208    CopyRedirectKeyArgs /* RedirectKey  */ ,
1209    CopyDeviceBtnArgs /* DeviceBtn    */ ,
1210    CopyDeviceBtnArgs           /* LockDeviceBtn */
1211};
1212
1213#define	ACTION_SZ	256
1214
1215char *
1216XkbActionText(XkbDescPtr xkb, XkbAction *action, unsigned format)
1217{
1218    char buf[ACTION_SZ], *tmp;
1219    int sz;
1220
1221    if (format == XkbCFile) {
1222        snprintf(buf, sizeof(buf),
1223                 "{ %20s, { 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x } }",
1224                 XkbActionTypeText(action->type, XkbCFile),
1225                 action->any.data[0], action->any.data[1], action->any.data[2],
1226                 action->any.data[3], action->any.data[4], action->any.data[5],
1227                 action->any.data[6]);
1228    }
1229    else {
1230        snprintf(buf, sizeof(buf), "%s(",
1231                 XkbActionTypeText(action->type, XkbXKBFile));
1232        sz = ACTION_SZ - strlen(buf) + 2;       /* room for close paren and NULL */
1233        if (action->type < (unsigned) XkbSA_NumActions)
1234            (*copyActionArgs[action->type]) (xkb, action, buf, &sz);
1235        else
1236            CopyOtherArgs(xkb, action, buf, &sz);
1237        TryCopyStr(buf, ")", &sz);
1238    }
1239    tmp = tbGetBuffer(strlen(buf) + 1);
1240    if (tmp != NULL)
1241        strcpy(tmp, buf);
1242    return tmp;
1243}
1244
1245char *
1246XkbBehaviorText(XkbDescPtr xkb, XkbBehavior * behavior, unsigned format)
1247{
1248    char buf[256], *tmp;
1249
1250    if (format == XkbCFile) {
1251        if (behavior->type == XkbKB_Default)
1252            snprintf(buf, sizeof(buf), "{   0,    0 }");
1253        else
1254            snprintf(buf, sizeof(buf), "{ %3d, 0x%02x }", behavior->type,
1255                     behavior->data);
1256    }
1257    else {
1258        unsigned type, permanent;
1259
1260        type = behavior->type & XkbKB_OpMask;
1261        permanent = ((behavior->type & XkbKB_Permanent) != 0);
1262
1263        if (type == XkbKB_Lock) {
1264            snprintf(buf, sizeof(buf), "lock= %s",
1265                     (permanent ? "Permanent" : "TRUE"));
1266        }
1267        else if (type == XkbKB_RadioGroup) {
1268            int g;
1269
1270            g = ((behavior->data) & (~XkbKB_RGAllowNone)) + 1;
1271            if (XkbKB_RGAllowNone & behavior->data) {
1272                snprintf(buf, sizeof(buf), "allowNone,");
1273                tmp = &buf[strlen(buf)];
1274            }
1275            else
1276                tmp = buf;
1277            if (permanent)
1278                sprintf(tmp, "permanentRadioGroup= %d", g);
1279            else
1280                sprintf(tmp, "radioGroup= %d", g);
1281        }
1282        else if ((type == XkbKB_Overlay1) || (type == XkbKB_Overlay2)) {
1283            int ndx, kc;
1284            char *kn;
1285
1286            ndx = ((type == XkbKB_Overlay1) ? 1 : 2);
1287            kc = behavior->data;
1288            if ((xkb) && (xkb->names) && (xkb->names->keys))
1289                kn = XkbKeyNameText(xkb->names->keys[kc].name, XkbXKBFile);
1290            else {
1291                static char tbuf[8];
1292
1293                snprintf(tbuf, sizeof(tbuf), "%d", kc);
1294                kn = tbuf;
1295            }
1296            if (permanent)
1297                snprintf(buf, sizeof(buf), "permanentOverlay%d= %s", ndx, kn);
1298            else
1299                snprintf(buf, sizeof(buf), "overlay%d= %s", ndx, kn);
1300        }
1301    }
1302    tmp = tbGetBuffer(strlen(buf) + 1);
1303    if (tmp != NULL)
1304        strcpy(tmp, buf);
1305    return tmp;
1306}
1307
1308/***====================================================================***/
1309
1310char *
1311XkbIndentText(unsigned size)
1312{
1313    static char buf[32];
1314    register int i;
1315
1316    if (size > 31)
1317        size = 31;
1318
1319    for (i = 0; i < size; i++) {
1320        buf[i] = ' ';
1321    }
1322    buf[size] = '\0';
1323    return buf;
1324}
1325