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