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