xkbfmisc.c revision 4642e01f
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 "xkbstr.h"
46#define XKBSRV_NEED_FILE_FUNCS	1
47#include <xkbsrv.h>
48#include "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		XkbDescPtr 	xkb,
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				XkbDescPtr		xkb,
164				unsigned		want,
165				unsigned		need)
166{
167char *		name,*tmp;
168unsigned	complete;
169XkbNamesPtr	old_names;
170int		multi_section;
171unsigned	wantNames,wantConfig,wantDflts;
172
173    complete= 0;
174    if ((name=names->keymap)==NULL)	name= "default";
175    if (COMPLETE(names->keycodes))	complete|= XkmKeyNamesMask;
176    if (COMPLETE(names->types))		complete|= XkmTypesMask;
177    if (COMPLETE(names->compat))	complete|= XkmCompatMapMask;
178    if (COMPLETE(names->symbols))	complete|= XkmSymbolsMask;
179    if (COMPLETE(names->geometry))	complete|= XkmGeometryMask;
180    want|= (complete|need);
181    if (want&XkmSymbolsMask)
182	want|= XkmKeyNamesMask|XkmTypesMask;
183
184    if (want==0)
185	return False;
186
187    if (xkb) {
188        old_names = xkb->names;
189
190        xkb->defined = 0;
191        /* Wow would it ever be neat if we didn't need this noise. */
192        if (xkb->names && xkb->names->keys)
193            xkb->defined |= XkmKeyNamesMask;
194        if (xkb->map && xkb->map->types)
195            xkb->defined |= XkmTypesMask;
196        if (xkb->compat)
197            xkb->defined |= XkmCompatMapMask;
198        if (xkb->map && xkb->map->num_syms)
199            xkb->defined |= XkmSymbolsMask;
200        if (xkb->indicators)
201            xkb->defined |= XkmIndicatorsMask;
202        if (xkb->geom)
203            xkb->defined |= XkmGeometryMask;
204    }
205    else {
206        old_names= NULL;
207    }
208
209    wantConfig= want&(~complete);
210    if (xkb!=NULL) {
211	if (wantConfig&XkmTypesMask) {
212	    if ((!xkb->map) || (xkb->map->num_types<XkbNumRequiredTypes))
213		wantConfig&= ~XkmTypesMask;
214	}
215	if (wantConfig&XkmCompatMapMask) {
216	    if ((!xkb->compat) || (xkb->compat->num_si<1))
217		wantConfig&= ~XkmCompatMapMask;
218	}
219	if (wantConfig&XkmSymbolsMask) {
220	    if ((!xkb->map) || (!xkb->map->key_sym_map))
221		wantConfig&= ~XkmSymbolsMask;
222	}
223	if (wantConfig&XkmIndicatorsMask) {
224	    if (!xkb->indicators)
225		wantConfig&= ~XkmIndicatorsMask;
226	}
227	if (wantConfig&XkmKeyNamesMask) {
228	    if ((!xkb->names)||(!xkb->names->keys))
229		wantConfig&= ~XkmKeyNamesMask;
230	}
231	if ((wantConfig&XkmGeometryMask)&&(!xkb->geom))
232	    wantConfig&= ~XkmGeometryMask;
233    }
234    else {
235	wantConfig= 0;
236    }
237    complete|= wantConfig;
238
239    wantDflts= 0;
240    wantNames= want&(~complete);
241    if ((xkb!=NULL) && (old_names!=NULL)) {
242	if (wantNames&XkmTypesMask) {
243	    if (old_names->types!=None) {
244		tmp= XkbAtomGetString(old_names->types);
245		names->types= _XkbDupString(tmp);
246	    }
247	    else {
248		wantDflts|= XkmTypesMask;
249	    }
250	    complete|= XkmTypesMask;
251	}
252	if (wantNames&XkmCompatMapMask) {
253	    if (old_names->compat!=None) {
254		tmp= XkbAtomGetString(old_names->compat);
255		names->compat= _XkbDupString(tmp);
256	    }
257	    else wantDflts|= XkmCompatMapMask;
258	    complete|= XkmCompatMapMask;
259	}
260	if (wantNames&XkmSymbolsMask) {
261	    if (old_names->symbols==None)
262		return False;
263	    tmp= XkbAtomGetString(old_names->symbols);
264	    names->symbols= _XkbDupString(tmp);
265	    complete|= XkmSymbolsMask;
266	}
267	if (wantNames&XkmKeyNamesMask) {
268	   if (old_names->keycodes!=None) {
269		tmp= XkbAtomGetString(old_names->keycodes);
270		names->keycodes= _XkbDupString(tmp);
271	    }
272	    else wantDflts|= XkmKeyNamesMask;
273	    complete|= XkmKeyNamesMask;
274	}
275	if (wantNames&XkmGeometryMask) {
276	    if (old_names->geometry==None)
277		return False;
278	    tmp= XkbAtomGetString(old_names->geometry);
279	    names->geometry= _XkbDupString(tmp);
280	    complete|= XkmGeometryMask;
281	    wantNames&= ~XkmGeometryMask;
282	}
283    }
284    if (complete&XkmCompatMapMask)
285	complete|= XkmIndicatorsMask|XkmVirtualModsMask;
286    else if (complete&(XkmSymbolsMask|XkmTypesMask))
287	complete|= XkmVirtualModsMask;
288    if (need & (~complete))
289	return False;
290    if ((complete&XkmSymbolsMask)&&((XkmKeyNamesMask|XkmTypesMask)&(~complete)))
291	return False;
292
293    multi_section= 1;
294    if (((complete&XkmKeymapRequired)==XkmKeymapRequired)&&
295	((complete&(~XkmKeymapLegal))==0)) {
296	fprintf(file,"xkb_keymap \"%s\" {\n",name);
297    }
298    else if (((complete&XkmSemanticsRequired)==XkmSemanticsRequired)&&
299	((complete&(~XkmSemanticsLegal))==0)) {
300	fprintf(file,"xkb_semantics \"%s\" {\n",name);
301    }
302    else if (((complete&XkmLayoutRequired)==XkmLayoutRequired)&&
303	((complete&(~XkmLayoutLegal))==0)) {
304	fprintf(file,"xkb_layout \"%s\" {\n",name);
305    }
306    else if (XkmSingleSection(complete&(~XkmVirtualModsMask))) {
307	multi_section= 0;
308    }
309    else {
310	return False;
311    }
312
313    wantNames= complete&(~(wantConfig|wantDflts));
314    name= names->keycodes;
315    if (wantConfig&XkmKeyNamesMask)
316	XkbWriteXKBKeycodes(file,xkb,False,False,_AddIncl,name);
317    else if (wantDflts&XkmKeyNamesMask)
318	fprintf(stderr,"Default symbols not implemented yet!\n");
319    else if (wantNames&XkmKeyNamesMask)
320	XkbWriteSectionFromName(file,"keycodes",name);
321
322    name= names->types;
323    if (wantConfig&XkmTypesMask)
324	XkbWriteXKBKeyTypes(file,xkb,False,False,_AddIncl,name);
325    else if (wantDflts&XkmTypesMask)
326	fprintf(stderr,"Default types not implemented yet!\n");
327    else if (wantNames&XkmTypesMask)
328	XkbWriteSectionFromName(file,"types",name);
329
330    name= names->compat;
331    if (wantConfig&XkmCompatMapMask)
332	XkbWriteXKBCompatMap(file,xkb,False,False,_AddIncl,name);
333    else if (wantDflts&XkmCompatMapMask)
334	fprintf(stderr,"Default interps not implemented yet!\n");
335    else if (wantNames&XkmCompatMapMask)
336	XkbWriteSectionFromName(file,"compatibility",name);
337
338    name= names->symbols;
339    if (wantConfig&XkmSymbolsMask)
340	XkbWriteXKBSymbols(file,xkb,False,False,_AddIncl,name);
341    else if (wantNames&XkmSymbolsMask)
342	XkbWriteSectionFromName(file,"symbols",name);
343
344    name= names->geometry;
345    if (wantConfig&XkmGeometryMask)
346	XkbWriteXKBGeometry(file,xkb,False,False,_AddIncl,name);
347    else if (wantNames&XkmGeometryMask)
348	XkbWriteSectionFromName(file,"geometry",name);
349
350    if (multi_section)
351	fprintf(file,"};\n");
352    return True;
353}
354
355/***====================================================================***/
356
357int
358XkbFindKeycodeByName(XkbDescPtr xkb,char *name,Bool use_aliases)
359{
360register int	i;
361
362    if ((!xkb)||(!xkb->names)||(!xkb->names->keys))
363	return 0;
364    for (i=xkb->min_key_code;i<=xkb->max_key_code;i++) {
365	if (strncmp(xkb->names->keys[i].name,name,XkbKeyNameLength)==0)
366	    return i;
367    }
368    if (!use_aliases)
369	return 0;
370    if (xkb->geom && xkb->geom->key_aliases) {
371	XkbKeyAliasPtr	a;
372	a= xkb->geom->key_aliases;
373	for (i=0;i<xkb->geom->num_key_aliases;i++,a++) {
374	    if (strncmp(name,a->alias,XkbKeyNameLength)==0)
375		return XkbFindKeycodeByName(xkb,a->real,False);
376	}
377    }
378    if (xkb->names && xkb->names->key_aliases) {
379	XkbKeyAliasPtr	a;
380	a= xkb->names->key_aliases;
381	for (i=0;i<xkb->names->num_key_aliases;i++,a++) {
382	    if (strncmp(name,a->alias,XkbKeyNameLength)==0)
383		return XkbFindKeycodeByName(xkb,a->real,False);
384	}
385    }
386    return 0;
387}
388
389
390unsigned
391XkbConvertGetByNameComponents(Bool toXkm,unsigned orig)
392{
393unsigned	rtrn;
394
395    rtrn= 0;
396    if (toXkm) {
397	if (orig&XkbGBN_TypesMask)		rtrn|= XkmTypesMask;
398	if (orig&XkbGBN_CompatMapMask)		rtrn|= XkmCompatMapMask;
399	if (orig&XkbGBN_SymbolsMask)		rtrn|= XkmSymbolsMask;
400	if (orig&XkbGBN_IndicatorMapMask)	rtrn|= XkmIndicatorsMask;
401	if (orig&XkbGBN_KeyNamesMask)		rtrn|= XkmKeyNamesMask;
402	if (orig&XkbGBN_GeometryMask)		rtrn|= XkmGeometryMask;
403    }
404    else {
405	if (orig&XkmTypesMask)			rtrn|= XkbGBN_TypesMask;
406	if (orig&XkmCompatMapMask)		rtrn|= XkbGBN_CompatMapMask;
407	if (orig&XkmSymbolsMask)		rtrn|= XkbGBN_SymbolsMask;
408	if (orig&XkmIndicatorsMask)		rtrn|= XkbGBN_IndicatorMapMask;
409	if (orig&XkmKeyNamesMask)		rtrn|= XkbGBN_KeyNamesMask;
410	if (orig&XkmGeometryMask)		rtrn|= XkbGBN_GeometryMask;
411	if (orig!=0)				rtrn|= XkbGBN_OtherNamesMask;
412    }
413    return rtrn;
414}
415
416/* all latin-1 alphanumerics, plus parens, slash, minus, underscore and */
417/* wildcards */
418
419static unsigned char componentSpecLegal[] = {
420	0x00, 0x00, 0x00, 0x00, 0x00, 0xa7, 0xff, 0x83,
421	0xfe, 0xff, 0xff, 0x87, 0xfe, 0xff, 0xff, 0x07,
422	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
423	0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff
424};
425
426void
427XkbEnsureSafeMapName(char *name)
428{
429   if (name==NULL)
430        return;
431    while (*name!='\0') {
432	if ((componentSpecLegal[(*name)/8]&(1<<((*name)%8)))==0)
433	    *name= '_';
434        name++;
435    }
436    return;
437}
438
439/***====================================================================***/
440
441#define	UNMATCHABLE(c)	(((c)=='(')||((c)==')')||((c)=='/'))
442
443Bool
444XkbNameMatchesPattern(char *name,char *ptrn)
445{
446    while (ptrn[0]!='\0') {
447	if (name[0]=='\0') {
448	    if (ptrn[0]=='*') {
449		ptrn++;
450		continue;
451	    }
452	    return False;
453	}
454	if (ptrn[0]=='?') {
455	    if (UNMATCHABLE(name[0]))
456		return False;
457	}
458	else if (ptrn[0]=='*') {
459	    if ((!UNMATCHABLE(name[0]))&&XkbNameMatchesPattern(name+1,ptrn))
460		return True;
461	    return XkbNameMatchesPattern(name,ptrn+1);
462	}
463	else if (ptrn[0]!=name[0])
464	    return False;
465	name++;
466	ptrn++;
467    }
468    /* if we get here, the pattern is exhausted (-:just like me:-) */
469    return (name[0]=='\0');
470}
471