xkbfmisc.c revision 05b261ec
1/************************************************************
2 Copyright (c) 1995 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#include <X11/Xfuncs.h>
37
38#include <X11/X.h>
39#define	NEED_EVENTS
40#include <X11/keysym.h>
41#include <X11/Xproto.h>
42#include "misc.h"
43#include "inputstr.h"
44#include "dix.h"
45#include <X11/extensions/XKBstr.h>
46#define XKBSRV_NEED_FILE_FUNCS	1
47#include <xkbsrv.h>
48#include <X11/extensions/XKBgeom.h>
49#include "xkb.h"
50
51unsigned
52_XkbKSCheckCase(KeySym ks)
53{
54unsigned	set,rtrn;
55
56    set= (ks & (~0xff)) >> 8;
57    rtrn= 0;
58    switch (set) {
59	case 0:		/* latin 1 */
60	    if (((ks>=XK_A)&&(ks<=XK_Z))||
61		((ks>=XK_Agrave)&&(ks<=XK_THORN)&&(ks!=XK_multiply))) {
62		rtrn|= _XkbKSUpper;
63	    }
64	    if (((ks>=XK_a)&&(ks<=XK_z))||
65		((ks>=XK_agrave)&&(ks<=XK_ydiaeresis))) {
66		rtrn|= _XkbKSLower;
67	    }
68	    break;
69	case 1:		/* latin 2 */
70	    if (((ks>=XK_Aogonek)&&(ks<=XK_Zabovedot)&&(ks!=XK_breve))||
71		((ks>=XK_Racute)&&(ks<=XK_Tcedilla))) {
72		rtrn|= _XkbKSUpper;
73	    }
74	    if (((ks>=XK_aogonek)&&(ks<=XK_zabovedot)&&(ks!=XK_caron))||
75		((ks>=XK_racute)&&(ks<=XK_tcedilla))) {
76		rtrn|= _XkbKSLower;
77	    }
78	    break;
79	case 2:		/* latin 3 */
80	    if (((ks>=XK_Hstroke)&&(ks<=XK_Jcircumflex))||
81		((ks>=XK_Cabovedot)&&(ks<=XK_Scircumflex))) {
82		rtrn|= _XkbKSUpper;
83	    }
84	    if (((ks>=XK_hstroke)&&(ks<=XK_jcircumflex))||
85		((ks>=XK_cabovedot)&&(ks<=XK_scircumflex))) {
86		rtrn|= _XkbKSLower;
87	    }
88	    break;
89	case 3:		/* latin 4 */
90	    if (((ks>=XK_Rcedilla)&&(ks<=XK_Tslash))||
91	        (ks==XK_ENG)||
92		((ks>=XK_Amacron)&&(ks<=XK_Umacron))) {
93		rtrn|= _XkbKSUpper;
94	    }
95	    if (((ks>=XK_rcedilla)&&(ks<=XK_tslash))||
96	        (ks==XK_eng)||
97		((ks>=XK_amacron)&&(ks<=XK_umacron))) {
98		rtrn|= _XkbKSLower;
99	    }
100	    break;
101	case 18:		/* latin 8 */
102	    if ((ks==XK_Babovedot)||
103                ((ks>=XK_Dabovedot)&&(ks<=XK_Wacute))||
104		((ks>=XK_Ygrave)&&(ks<=XK_Fabovedot))||
105	        (ks==XK_Mabovedot)||
106	        (ks==XK_Pabovedot)||
107	        (ks==XK_Sabovedot)||
108	        (ks==XK_Wdiaeresis)||
109		((ks>=XK_Wcircumflex)&&(ks<=XK_Ycircumflex))) {
110		rtrn|= _XkbKSUpper;
111	    }
112	    if ((ks==XK_babovedot)||
113	        (ks==XK_dabovedot)||
114	        (ks==XK_fabovedot)||
115	        (ks==XK_mabovedot)||
116                ((ks>=XK_wgrave)&&(ks<=XK_wacute))||
117	        (ks==XK_ygrave)||
118		((ks>=XK_wdiaeresis)&&(ks<=XK_ycircumflex))) {
119		rtrn|= _XkbKSLower;
120	    }
121	    break;
122	case 19:		/* latin 9 */
123	    if ((ks==XK_OE)||(ks==XK_Ydiaeresis)) {
124		rtrn|= _XkbKSUpper;
125	    }
126	    if (ks==XK_oe) {
127		rtrn|= _XkbKSLower;
128	    }
129	    break;
130    }
131    return rtrn;
132}
133
134/***===================================================================***/
135
136static Bool
137XkbWriteSectionFromName(FILE *file,char *sectionName,char *name)
138{
139    fprintf(file,"    xkb_%-20s { include \"%s\" };\n",sectionName,name);
140    return True;
141}
142
143#define	NEED_DESC(n) ((!n)||((n)[0]=='+')||((n)[0]=='|')||(strchr((n),'%')))
144#define	COMPLETE(n)  ((n)&&(!NEED_DESC(n)))
145
146/* ARGSUSED */
147static void
148_AddIncl(	FILE *		file,
149		XkbFileInfo *	result,
150		Bool 		topLevel,
151		Bool 		showImplicit,
152		int 		index,
153		void *		priv)
154{
155    if ((priv)&&(strcmp((char *)priv,"%")!=0))
156	fprintf(file,"    include \"%s\"\n",(char *)priv);
157    return;
158}
159
160Bool
161XkbWriteXKBKeymapForNames(	FILE *			file,
162				XkbComponentNamesPtr	names,
163				Display *		dpy,
164				XkbDescPtr		xkb,
165				unsigned		want,
166				unsigned		need)
167{
168char *		name,*tmp;
169unsigned	complete;
170XkbNamesPtr	old_names;
171int		multi_section;
172unsigned	wantNames,wantConfig,wantDflts;
173XkbFileInfo	finfo;
174
175    bzero(&finfo,sizeof(XkbFileInfo));
176
177    complete= 0;
178    if ((name=names->keymap)==NULL)	name= "default";
179    if (COMPLETE(names->keycodes))	complete|= XkmKeyNamesMask;
180    if (COMPLETE(names->types))		complete|= XkmTypesMask;
181    if (COMPLETE(names->compat))	complete|= XkmCompatMapMask;
182    if (COMPLETE(names->symbols))	complete|= XkmSymbolsMask;
183    if (COMPLETE(names->geometry))	complete|= XkmGeometryMask;
184    want|= (complete|need);
185    if (want&XkmSymbolsMask)
186	want|= XkmKeyNamesMask|XkmTypesMask;
187
188    if (want==0)
189	return False;
190
191    if (xkb!=NULL) {
192	 old_names= xkb->names;
193	 finfo.type= 0;
194	 finfo.defined= 0;
195	 finfo.xkb= xkb;
196	 if (!XkbDetermineFileType(&finfo,XkbXKBFile,NULL))
197	    return False;
198    }
199    else old_names= NULL;
200
201    wantConfig= want&(~complete);
202    if (xkb!=NULL) {
203	if (wantConfig&XkmTypesMask) {
204	    if ((!xkb->map) || (xkb->map->num_types<XkbNumRequiredTypes))
205		wantConfig&= ~XkmTypesMask;
206	}
207	if (wantConfig&XkmCompatMapMask) {
208	    if ((!xkb->compat) || (xkb->compat->num_si<1))
209		wantConfig&= ~XkmCompatMapMask;
210	}
211	if (wantConfig&XkmSymbolsMask) {
212	    if ((!xkb->map) || (!xkb->map->key_sym_map))
213		wantConfig&= ~XkmSymbolsMask;
214	}
215	if (wantConfig&XkmIndicatorsMask) {
216	    if (!xkb->indicators)
217		wantConfig&= ~XkmIndicatorsMask;
218	}
219	if (wantConfig&XkmKeyNamesMask) {
220	    if ((!xkb->names)||(!xkb->names->keys))
221		wantConfig&= ~XkmKeyNamesMask;
222	}
223	if ((wantConfig&XkmGeometryMask)&&(!xkb->geom))
224	    wantConfig&= ~XkmGeometryMask;
225    }
226    else {
227	wantConfig= 0;
228    }
229    complete|= wantConfig;
230
231    wantDflts= 0;
232    wantNames= want&(~complete);
233    if ((xkb!=NULL) && (old_names!=NULL)) {
234	if (wantNames&XkmTypesMask) {
235	    if (old_names->types!=None) {
236		tmp= XkbAtomGetString(dpy,old_names->types);
237		names->types= _XkbDupString(tmp);
238	    }
239	    else {
240		wantDflts|= XkmTypesMask;
241	    }
242	    complete|= XkmTypesMask;
243	}
244	if (wantNames&XkmCompatMapMask) {
245	    if (old_names->compat!=None) {
246		tmp= XkbAtomGetString(dpy,old_names->compat);
247		names->compat= _XkbDupString(tmp);
248	    }
249	    else wantDflts|= XkmCompatMapMask;
250	    complete|= XkmCompatMapMask;
251	}
252	if (wantNames&XkmSymbolsMask) {
253	    if (old_names->symbols==None)
254		return False;
255	    tmp= XkbAtomGetString(dpy,old_names->symbols);
256	    names->symbols= _XkbDupString(tmp);
257	    complete|= XkmSymbolsMask;
258	}
259	if (wantNames&XkmKeyNamesMask) {
260	   if (old_names->keycodes!=None) {
261		tmp= XkbAtomGetString(dpy,old_names->keycodes);
262		names->keycodes= _XkbDupString(tmp);
263	    }
264	    else wantDflts|= XkmKeyNamesMask;
265	    complete|= XkmKeyNamesMask;
266	}
267	if (wantNames&XkmGeometryMask) {
268	    if (old_names->geometry==None)
269		return False;
270	    tmp= XkbAtomGetString(dpy,old_names->geometry);
271	    names->geometry= _XkbDupString(tmp);
272	    complete|= XkmGeometryMask;
273	    wantNames&= ~XkmGeometryMask;
274	}
275    }
276    if (complete&XkmCompatMapMask)
277	complete|= XkmIndicatorsMask|XkmVirtualModsMask;
278    else if (complete&(XkmSymbolsMask|XkmTypesMask))
279	complete|= XkmVirtualModsMask;
280    if (need & (~complete))
281	return False;
282    if ((complete&XkmSymbolsMask)&&((XkmKeyNamesMask|XkmTypesMask)&(~complete)))
283	return False;
284
285    multi_section= 1;
286    if (((complete&XkmKeymapRequired)==XkmKeymapRequired)&&
287	((complete&(~XkmKeymapLegal))==0)) {
288	fprintf(file,"xkb_keymap \"%s\" {\n",name);
289    }
290    else if (((complete&XkmSemanticsRequired)==XkmSemanticsRequired)&&
291	((complete&(~XkmSemanticsLegal))==0)) {
292	fprintf(file,"xkb_semantics \"%s\" {\n",name);
293    }
294    else if (((complete&XkmLayoutRequired)==XkmLayoutRequired)&&
295	((complete&(~XkmLayoutLegal))==0)) {
296	fprintf(file,"xkb_layout \"%s\" {\n",name);
297    }
298    else if (XkmSingleSection(complete&(~XkmVirtualModsMask))) {
299	multi_section= 0;
300    }
301    else {
302	return False;
303    }
304
305    wantNames= complete&(~(wantConfig|wantDflts));
306    name= names->keycodes;
307    if (wantConfig&XkmKeyNamesMask)
308	XkbWriteXKBKeycodes(file,&finfo,False,False,_AddIncl,name);
309    else if (wantDflts&XkmKeyNamesMask)
310	fprintf(stderr,"Default symbols not implemented yet!\n");
311    else if (wantNames&XkmKeyNamesMask)
312	XkbWriteSectionFromName(file,"keycodes",name);
313
314    name= names->types;
315    if (wantConfig&XkmTypesMask)
316	XkbWriteXKBKeyTypes(file,&finfo,False,False,_AddIncl,name);
317    else if (wantDflts&XkmTypesMask)
318	fprintf(stderr,"Default types not implemented yet!\n");
319    else if (wantNames&XkmTypesMask)
320	XkbWriteSectionFromName(file,"types",name);
321
322    name= names->compat;
323    if (wantConfig&XkmCompatMapMask)
324	XkbWriteXKBCompatMap(file,&finfo,False,False,_AddIncl,name);
325    else if (wantDflts&XkmCompatMapMask)
326	fprintf(stderr,"Default interps not implemented yet!\n");
327    else if (wantNames&XkmCompatMapMask)
328	XkbWriteSectionFromName(file,"compatibility",name);
329
330    name= names->symbols;
331    if (wantConfig&XkmSymbolsMask)
332	XkbWriteXKBSymbols(file,&finfo,False,False,_AddIncl,name);
333    else if (wantNames&XkmSymbolsMask)
334	XkbWriteSectionFromName(file,"symbols",name);
335
336    name= names->geometry;
337    if (wantConfig&XkmGeometryMask)
338	XkbWriteXKBGeometry(file,&finfo,False,False,_AddIncl,name);
339    else if (wantNames&XkmGeometryMask)
340	XkbWriteSectionFromName(file,"geometry",name);
341
342    if (multi_section)
343	fprintf(file,"};\n");
344    return True;
345}
346
347/***====================================================================***/
348
349int
350XkbFindKeycodeByName(XkbDescPtr xkb,char *name,Bool use_aliases)
351{
352register int	i;
353
354    if ((!xkb)||(!xkb->names)||(!xkb->names->keys))
355	return 0;
356    for (i=xkb->min_key_code;i<=xkb->max_key_code;i++) {
357	if (strncmp(xkb->names->keys[i].name,name,XkbKeyNameLength)==0)
358	    return i;
359    }
360    if (!use_aliases)
361	return 0;
362    if (xkb->geom && xkb->geom->key_aliases) {
363	XkbKeyAliasPtr	a;
364	a= xkb->geom->key_aliases;
365	for (i=0;i<xkb->geom->num_key_aliases;i++,a++) {
366	    if (strncmp(name,a->alias,XkbKeyNameLength)==0)
367		return XkbFindKeycodeByName(xkb,a->real,False);
368	}
369    }
370    if (xkb->names && xkb->names->key_aliases) {
371	XkbKeyAliasPtr	a;
372	a= xkb->names->key_aliases;
373	for (i=0;i<xkb->names->num_key_aliases;i++,a++) {
374	    if (strncmp(name,a->alias,XkbKeyNameLength)==0)
375		return XkbFindKeycodeByName(xkb,a->real,False);
376	}
377    }
378    return 0;
379}
380
381
382unsigned
383XkbConvertGetByNameComponents(Bool toXkm,unsigned orig)
384{
385unsigned	rtrn;
386
387    rtrn= 0;
388    if (toXkm) {
389	if (orig&XkbGBN_TypesMask)		rtrn|= XkmTypesMask;
390	if (orig&XkbGBN_CompatMapMask)		rtrn|= XkmCompatMapMask;
391	if (orig&XkbGBN_SymbolsMask)		rtrn|= XkmSymbolsMask;
392	if (orig&XkbGBN_IndicatorMapMask)	rtrn|= XkmIndicatorsMask;
393	if (orig&XkbGBN_KeyNamesMask)		rtrn|= XkmKeyNamesMask;
394	if (orig&XkbGBN_GeometryMask)		rtrn|= XkmGeometryMask;
395    }
396    else {
397	if (orig&XkmTypesMask)			rtrn|= XkbGBN_TypesMask;
398	if (orig&XkmCompatMapMask)		rtrn|= XkbGBN_CompatMapMask;
399	if (orig&XkmSymbolsMask)		rtrn|= XkbGBN_SymbolsMask;
400	if (orig&XkmIndicatorsMask)		rtrn|= XkbGBN_IndicatorMapMask;
401	if (orig&XkmKeyNamesMask)		rtrn|= XkbGBN_KeyNamesMask;
402	if (orig&XkmGeometryMask)		rtrn|= XkbGBN_GeometryMask;
403	if (orig!=0)				rtrn|= XkbGBN_OtherNamesMask;
404    }
405    return rtrn;
406}
407
408Bool
409XkbDetermineFileType(XkbFileInfoPtr finfo,int format,int *opts_missing)
410{
411unsigned	present;
412XkbDescPtr	xkb;
413
414    if ((!finfo)||(!finfo->xkb))
415	return False;
416    if (opts_missing)
417	*opts_missing= 0;
418    xkb= finfo->xkb;
419    present= 0;
420    if ((xkb->names)&&(xkb->names->keys))	present|= XkmKeyNamesMask;
421    if ((xkb->map)&&(xkb->map->types))		present|= XkmTypesMask;
422    if (xkb->compat)				present|= XkmCompatMapMask;
423    if ((xkb->map)&&(xkb->map->num_syms>1))	present|= XkmSymbolsMask;
424    if (xkb->indicators)			present|= XkmIndicatorsMask;
425    if (xkb->geom)				present|= XkmGeometryMask;
426    if (!present)
427	return False;
428    else switch (present) {
429	case XkmKeyNamesMask:
430	    finfo->type= 	XkmKeyNamesIndex;
431	    finfo->defined= 	present;
432	    return True;
433	case XkmTypesMask:
434	    finfo->type=	XkmTypesIndex;
435	    finfo->defined= 	present;
436	    return True;
437	case XkmCompatMapMask:
438	    finfo->type=	XkmCompatMapIndex;
439	    finfo->defined=	present;
440	    return True;
441	case XkmSymbolsMask:
442	    if (format!=XkbXKMFile) {
443		finfo->type= 	XkmSymbolsIndex;
444		finfo->defined=	present;
445		return True;
446	    }
447	    break;
448	case XkmGeometryMask:
449	    finfo->type=	XkmGeometryIndex;
450	    finfo->defined=	present;
451	    return True;
452    }
453    if ((present&(~XkmSemanticsLegal))==0) {
454	if ((XkmSemanticsRequired&present)==XkmSemanticsRequired) {
455	    if (opts_missing)
456		*opts_missing= XkmSemanticsOptional&(~present);
457	    finfo->type= 	XkmSemanticsFile;
458	    finfo->defined=	present;
459	    return True;
460	}
461    }
462    else if ((present&(~XkmLayoutLegal))==0) {
463	if ((XkmLayoutRequired&present)==XkmLayoutRequired) {
464	    if (opts_missing)
465		*opts_missing= XkmLayoutOptional&(~present);
466	    finfo->type=	XkmLayoutFile;
467	    finfo->defined=	present;
468	    return True;
469	}
470    }
471    else if ((present&(~XkmKeymapLegal))==0) {
472	if ((XkmKeymapRequired&present)==XkmKeymapRequired) {
473	    if (opts_missing)
474		*opts_missing= XkmKeymapOptional&(~present);
475	    finfo->type=	XkmKeymapFile;
476	    finfo->defined=	present;
477	    return True;
478	}
479    }
480    return False;
481}
482
483/* all latin-1 alphanumerics, plus parens, slash, minus, underscore and */
484/* wildcards */
485
486static unsigned char componentSpecLegal[] = {
487	0x00, 0x00, 0x00, 0x00, 0x00, 0xa7, 0xff, 0x83,
488	0xfe, 0xff, 0xff, 0x87, 0xfe, 0xff, 0xff, 0x07,
489	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
490	0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff
491};
492
493void
494XkbEnsureSafeMapName(char *name)
495{
496   if (name==NULL)
497        return;
498    while (*name!='\0') {
499	if ((componentSpecLegal[(*name)/8]&(1<<((*name)%8)))==0)
500	    *name= '_';
501        name++;
502    }
503    return;
504}
505
506/***====================================================================***/
507
508#define	UNMATCHABLE(c)	(((c)=='(')||((c)==')')||((c)=='/'))
509
510Bool
511XkbNameMatchesPattern(char *name,char *ptrn)
512{
513    while (ptrn[0]!='\0') {
514	if (name[0]=='\0') {
515	    if (ptrn[0]=='*') {
516		ptrn++;
517		continue;
518	    }
519	    return False;
520	}
521	if (ptrn[0]=='?') {
522	    if (UNMATCHABLE(name[0]))
523		return False;
524	}
525	else if (ptrn[0]=='*') {
526	    if ((!UNMATCHABLE(name[0]))&&XkbNameMatchesPattern(name+1,ptrn))
527		return True;
528	    return XkbNameMatchesPattern(name,ptrn+1);
529	}
530	else if (ptrn[0]!=name[0])
531	    return False;
532	name++;
533	ptrn++;
534    }
535    /* if we get here, the pattern is exhausted (-:just like me:-) */
536    return (name[0]=='\0');
537}
538