xkbfmisc.c revision 35c4bbdf
11.6Ssimonb/************************************************************
21.1Sjonathan Copyright (c) 1995 by Silicon Graphics Computer Systems, Inc.
31.2Sjonathan
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#include <X11/extensions/XKMformat.h>
38
39#include <X11/X.h>
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{
54    unsigned 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_ssharp) && (ks <= XK_ydiaeresis) &&
66             (ks != XK_division))) {
67            rtrn |= _XkbKSLower;
68        }
69        break;
70    case 1:                    /* latin 2 */
71        if (((ks >= XK_Aogonek) && (ks <= XK_Zabovedot) && (ks != XK_breve)) ||
72            ((ks >= XK_Racute) && (ks <= XK_Tcedilla))) {
73            rtrn |= _XkbKSUpper;
74        }
75        if (((ks >= XK_aogonek) && (ks <= XK_zabovedot) && (ks != XK_ogonek) &&
76             (ks != XK_caron) && (ks != XK_doubleacute)) || ((ks >= XK_racute)
77                                                             && (ks <=
78                                                                 XK_tcedilla)))
79        {
80            rtrn |= _XkbKSLower;
81        }
82        break;
83    case 2:                    /* latin 3 */
84        if (((ks >= XK_Hstroke) && (ks <= XK_Jcircumflex)) ||
85            ((ks >= XK_Cabovedot) && (ks <= XK_Scircumflex))) {
86            rtrn |= _XkbKSUpper;
87        }
88        if (((ks >= XK_hstroke) && (ks <= XK_jcircumflex)) ||
89            ((ks >= XK_cabovedot) && (ks <= XK_scircumflex))) {
90            rtrn |= _XkbKSLower;
91        }
92        break;
93    case 3:                    /* latin 4 */
94        if (((ks >= XK_Rcedilla) && (ks <= XK_Tslash)) ||
95            (ks == XK_ENG) || ((ks >= XK_Amacron) && (ks <= XK_Umacron))) {
96            rtrn |= _XkbKSUpper;
97        }
98        if ((ks == XK_kra) ||
99            ((ks >= XK_rcedilla) && (ks <= XK_tslash)) ||
100            (ks == XK_eng) || ((ks >= XK_amacron) && (ks <= XK_umacron))) {
101            rtrn |= _XkbKSLower;
102        }
103        break;
104    case 18:                   /* latin 8 */
105        if ((ks == XK_Wcircumflex) ||
106            (ks == XK_Ycircumflex) ||
107            (ks == XK_Babovedot) ||
108            (ks == XK_Dabovedot) ||
109            (ks == XK_Fabovedot) ||
110            (ks == XK_Mabovedot) ||
111            (ks == XK_Pabovedot) ||
112            (ks == XK_Sabovedot) ||
113            (ks == XK_Tabovedot) ||
114            (ks == XK_Wgrave) ||
115            (ks == XK_Wacute) || (ks == XK_Wdiaeresis) || (ks == XK_Ygrave)) {
116            rtrn |= _XkbKSUpper;
117        }
118        if ((ks == XK_wcircumflex) ||
119            (ks == XK_ycircumflex) ||
120            (ks == XK_babovedot) ||
121            (ks == XK_dabovedot) ||
122            (ks == XK_fabovedot) ||
123            (ks == XK_mabovedot) ||
124            (ks == XK_pabovedot) ||
125            (ks == XK_sabovedot) ||
126            (ks == XK_tabovedot) ||
127            (ks == XK_wgrave) ||
128            (ks == XK_wacute) || (ks == XK_wdiaeresis) || (ks == XK_ygrave)) {
129            rtrn |= _XkbKSLower;
130        }
131        break;
132    case 19:                   /* latin 9 */
133        if ((ks == XK_OE) || (ks == XK_Ydiaeresis)) {
134            rtrn |= _XkbKSUpper;
135        }
136        if (ks == XK_oe) {
137            rtrn |= _XkbKSLower;
138        }
139        break;
140    }
141    return rtrn;
142}
143
144/***===================================================================***/
145
146static Bool
147XkbWriteSectionFromName(FILE * file, const char *sectionName, const char *name)
148{
149    fprintf(file, "    xkb_%-20s { include \"%s\" };\n", sectionName, name);
150    return TRUE;
151}
152
153#define	NEED_DESC(n) ((!n)||((n)[0]=='+')||((n)[0]=='|')||(strchr((n),'%')))
154#define	COMPLETE(n)  ((n)&&(!NEED_DESC(n)))
155
156/* ARGSUSED */
157static void
158_AddIncl(FILE * file,
159         XkbDescPtr xkb,
160         Bool topLevel, Bool showImplicit, int index, void *priv)
161{
162    if ((priv) && (strcmp((char *) priv, "%") != 0))
163        fprintf(file, "    include \"%s\"\n", (char *) priv);
164    return;
165}
166
167Bool
168XkbWriteXKBKeymapForNames(FILE * file,
169                          XkbComponentNamesPtr names,
170                          XkbDescPtr xkb, unsigned want, unsigned need)
171{
172    const char *tmp;
173    unsigned complete;
174    XkbNamesPtr old_names;
175    int multi_section;
176    unsigned wantNames, wantConfig, wantDflts;
177
178    complete = 0;
179    if (COMPLETE(names->keycodes))
180        complete |= XkmKeyNamesMask;
181    if (COMPLETE(names->types))
182        complete |= XkmTypesMask;
183    if (COMPLETE(names->compat))
184        complete |= XkmCompatMapMask;
185    if (COMPLETE(names->symbols))
186        complete |= XkmSymbolsMask;
187    if (COMPLETE(names->geometry))
188        complete |= XkmGeometryMask;
189    want |= (complete | need);
190    if (want & XkmSymbolsMask)
191        want |= XkmKeyNamesMask | XkmTypesMask;
192
193    if (want == 0)
194        return FALSE;
195
196    if (xkb) {
197        old_names = xkb->names;
198
199        xkb->defined = 0;
200        /* Wow would it ever be neat if we didn't need this noise. */
201        if (xkb->names && xkb->names->keys)
202            xkb->defined |= XkmKeyNamesMask;
203        if (xkb->map && xkb->map->types)
204            xkb->defined |= XkmTypesMask;
205        if (xkb->compat)
206            xkb->defined |= XkmCompatMapMask;
207        if (xkb->map && xkb->map->num_syms)
208            xkb->defined |= XkmSymbolsMask;
209        if (xkb->indicators)
210            xkb->defined |= XkmIndicatorsMask;
211        if (xkb->geom)
212            xkb->defined |= XkmGeometryMask;
213    }
214    else {
215        old_names = NULL;
216    }
217
218    wantConfig = want & (~complete);
219    if (xkb != NULL) {
220        if (wantConfig & XkmTypesMask) {
221            if ((!xkb->map) || (xkb->map->num_types < XkbNumRequiredTypes))
222                wantConfig &= ~XkmTypesMask;
223        }
224        if (wantConfig & XkmCompatMapMask) {
225            if ((!xkb->compat) || (xkb->compat->num_si < 1))
226                wantConfig &= ~XkmCompatMapMask;
227        }
228        if (wantConfig & XkmSymbolsMask) {
229            if ((!xkb->map) || (!xkb->map->key_sym_map))
230                wantConfig &= ~XkmSymbolsMask;
231        }
232        if (wantConfig & XkmIndicatorsMask) {
233            if (!xkb->indicators)
234                wantConfig &= ~XkmIndicatorsMask;
235        }
236        if (wantConfig & XkmKeyNamesMask) {
237            if ((!xkb->names) || (!xkb->names->keys))
238                wantConfig &= ~XkmKeyNamesMask;
239        }
240        if ((wantConfig & XkmGeometryMask) && (!xkb->geom))
241            wantConfig &= ~XkmGeometryMask;
242    }
243    else {
244        wantConfig = 0;
245    }
246    complete |= wantConfig;
247
248    wantDflts = 0;
249    wantNames = want & (~complete);
250    if ((xkb != NULL) && (old_names != NULL)) {
251        if (wantNames & XkmTypesMask) {
252            if (old_names->types != None) {
253                tmp = NameForAtom(old_names->types);
254                names->types = Xstrdup(tmp);
255            }
256            else {
257                wantDflts |= XkmTypesMask;
258            }
259            complete |= XkmTypesMask;
260        }
261        if (wantNames & XkmCompatMapMask) {
262            if (old_names->compat != None) {
263                tmp = NameForAtom(old_names->compat);
264                names->compat = Xstrdup(tmp);
265            }
266            else
267                wantDflts |= XkmCompatMapMask;
268            complete |= XkmCompatMapMask;
269        }
270        if (wantNames & XkmSymbolsMask) {
271            if (old_names->symbols == None)
272                return FALSE;
273            tmp = NameForAtom(old_names->symbols);
274            names->symbols = Xstrdup(tmp);
275            complete |= XkmSymbolsMask;
276        }
277        if (wantNames & XkmKeyNamesMask) {
278            if (old_names->keycodes != None) {
279                tmp = NameForAtom(old_names->keycodes);
280                names->keycodes = Xstrdup(tmp);
281            }
282            else
283                wantDflts |= XkmKeyNamesMask;
284            complete |= XkmKeyNamesMask;
285        }
286        if (wantNames & XkmGeometryMask) {
287            if (old_names->geometry == None)
288                return FALSE;
289            tmp = NameForAtom(old_names->geometry);
290            names->geometry = Xstrdup(tmp);
291            complete |= XkmGeometryMask;
292            wantNames &= ~XkmGeometryMask;
293        }
294    }
295    if (complete & XkmCompatMapMask)
296        complete |= XkmIndicatorsMask | XkmVirtualModsMask;
297    else if (complete & (XkmSymbolsMask | XkmTypesMask))
298        complete |= XkmVirtualModsMask;
299    if (need & (~complete))
300        return FALSE;
301    if ((complete & XkmSymbolsMask) &&
302        ((XkmKeyNamesMask | XkmTypesMask) & (~complete)))
303        return FALSE;
304
305    multi_section = 1;
306    if (((complete & XkmKeymapRequired) == XkmKeymapRequired) &&
307        ((complete & (~XkmKeymapLegal)) == 0)) {
308        fprintf(file, "xkb_keymap \"default\" {\n");
309    }
310    else if (((complete & XkmSemanticsRequired) == XkmSemanticsRequired) &&
311             ((complete & (~XkmSemanticsLegal)) == 0)) {
312        fprintf(file, "xkb_semantics \"default\" {\n");
313    }
314    else if (((complete & XkmLayoutRequired) == XkmLayoutRequired) &&
315             ((complete & (~XkmLayoutLegal)) == 0)) {
316        fprintf(file, "xkb_layout \"default\" {\n");
317    }
318    else if (XkmSingleSection(complete & (~XkmVirtualModsMask))) {
319        multi_section = 0;
320    }
321    else {
322        return FALSE;
323    }
324
325    wantNames = complete & (~(wantConfig | wantDflts));
326    if (wantConfig & XkmKeyNamesMask)
327        XkbWriteXKBKeycodes(file, xkb, FALSE, FALSE, _AddIncl, names->keycodes);
328    else if (wantDflts & XkmKeyNamesMask)
329        fprintf(stderr, "Default symbols not implemented yet!\n");
330    else if (wantNames & XkmKeyNamesMask)
331        XkbWriteSectionFromName(file, "keycodes", names->keycodes);
332
333    if (wantConfig & XkmTypesMask)
334        XkbWriteXKBKeyTypes(file, xkb, FALSE, FALSE, _AddIncl, names->types);
335    else if (wantDflts & XkmTypesMask)
336        fprintf(stderr, "Default types not implemented yet!\n");
337    else if (wantNames & XkmTypesMask)
338        XkbWriteSectionFromName(file, "types", names->types);
339
340    if (wantConfig & XkmCompatMapMask)
341        XkbWriteXKBCompatMap(file, xkb, FALSE, FALSE, _AddIncl, names->compat);
342    else if (wantDflts & XkmCompatMapMask)
343        fprintf(stderr, "Default interps not implemented yet!\n");
344    else if (wantNames & XkmCompatMapMask)
345        XkbWriteSectionFromName(file, "compatibility", names->compat);
346
347    if (wantConfig & XkmSymbolsMask)
348        XkbWriteXKBSymbols(file, xkb, FALSE, FALSE, _AddIncl, names->symbols);
349    else if (wantNames & XkmSymbolsMask)
350        XkbWriteSectionFromName(file, "symbols", names->symbols);
351
352    if (wantConfig & XkmGeometryMask)
353        XkbWriteXKBGeometry(file, xkb, FALSE, FALSE, _AddIncl, names->geometry);
354    else if (wantNames & XkmGeometryMask)
355        XkbWriteSectionFromName(file, "geometry", names->geometry);
356
357    if (multi_section)
358        fprintf(file, "};\n");
359    return TRUE;
360}
361
362/***====================================================================***/
363
364int
365XkbFindKeycodeByName(XkbDescPtr xkb, char *name, Bool use_aliases)
366{
367    register int i;
368
369    if ((!xkb) || (!xkb->names) || (!xkb->names->keys))
370        return 0;
371    for (i = xkb->min_key_code; i <= xkb->max_key_code; i++) {
372        if (strncmp(xkb->names->keys[i].name, name, XkbKeyNameLength) == 0)
373            return i;
374    }
375    if (!use_aliases)
376        return 0;
377    if (xkb->geom && xkb->geom->key_aliases) {
378        XkbKeyAliasPtr a;
379
380        a = xkb->geom->key_aliases;
381        for (i = 0; i < xkb->geom->num_key_aliases; i++, a++) {
382            if (strncmp(name, a->alias, XkbKeyNameLength) == 0)
383                return XkbFindKeycodeByName(xkb, a->real, FALSE);
384        }
385    }
386    if (xkb->names && xkb->names->key_aliases) {
387        XkbKeyAliasPtr a;
388
389        a = xkb->names->key_aliases;
390        for (i = 0; i < xkb->names->num_key_aliases; i++, a++) {
391            if (strncmp(name, a->alias, XkbKeyNameLength) == 0)
392                return XkbFindKeycodeByName(xkb, a->real, FALSE);
393        }
394    }
395    return 0;
396}
397
398unsigned
399XkbConvertGetByNameComponents(Bool toXkm, unsigned orig)
400{
401    unsigned rtrn;
402
403    rtrn = 0;
404    if (toXkm) {
405        if (orig & XkbGBN_TypesMask)
406            rtrn |= XkmTypesMask;
407        if (orig & XkbGBN_CompatMapMask)
408            rtrn |= XkmCompatMapMask;
409        if (orig & XkbGBN_SymbolsMask)
410            rtrn |= XkmSymbolsMask;
411        if (orig & XkbGBN_IndicatorMapMask)
412            rtrn |= XkmIndicatorsMask;
413        if (orig & XkbGBN_KeyNamesMask)
414            rtrn |= XkmKeyNamesMask;
415        if (orig & XkbGBN_GeometryMask)
416            rtrn |= XkmGeometryMask;
417    }
418    else {
419        if (orig & XkmTypesMask)
420            rtrn |= XkbGBN_TypesMask;
421        if (orig & XkmCompatMapMask)
422            rtrn |= XkbGBN_CompatMapMask;
423        if (orig & XkmSymbolsMask)
424            rtrn |= XkbGBN_SymbolsMask;
425        if (orig & XkmIndicatorsMask)
426            rtrn |= XkbGBN_IndicatorMapMask;
427        if (orig & XkmKeyNamesMask)
428            rtrn |= XkbGBN_KeyNamesMask;
429        if (orig & XkmGeometryMask)
430            rtrn |= XkbGBN_GeometryMask;
431        if (orig != 0)
432            rtrn |= XkbGBN_OtherNamesMask;
433    }
434    return rtrn;
435}
436
437/***====================================================================***/
438
439#define	UNMATCHABLE(c)	(((c)=='(')||((c)==')')||((c)=='/'))
440
441Bool
442XkbNameMatchesPattern(char *name, char *ptrn)
443{
444    while (ptrn[0] != '\0') {
445        if (name[0] == '\0') {
446            if (ptrn[0] == '*') {
447                ptrn++;
448                continue;
449            }
450            return FALSE;
451        }
452        if (ptrn[0] == '?') {
453            if (UNMATCHABLE(name[0]))
454                return FALSE;
455        }
456        else if (ptrn[0] == '*') {
457            if ((!UNMATCHABLE(name[0])) &&
458                XkbNameMatchesPattern(name + 1, ptrn))
459                return TRUE;
460            return XkbNameMatchesPattern(name, ptrn + 1);
461        }
462        else if (ptrn[0] != name[0])
463            return FALSE;
464        name++;
465        ptrn++;
466    }
467    /* if we get here, the pattern is exhausted (-:just like me:-) */
468    return name[0] == '\0';
469}
470