1/*
2 * Copyright 1985, 1987, 1990, 1998  The Open Group
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
18 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 *
21 * Except as contained in this notice, the names of the authors or their
22 * institutions shall not be used in advertising or otherwise to promote the
23 * sale, use or other dealings in this Software without prior written
24 * authorization from the authors.
25 */
26
27/*
28 * Copyright © 2009 Dan Nicholson
29 *
30 * Permission is hereby granted, free of charge, to any person obtaining a
31 * copy of this software and associated documentation files (the "Software"),
32 * to deal in the Software without restriction, including without limitation
33 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
34 * and/or sell copies of the Software, and to permit persons to whom the
35 * Software is furnished to do so, subject to the following conditions:
36 *
37 * The above copyright notice and this permission notice (including the next
38 * paragraph) shall be included in all copies or substantial portions of the
39 * Software.
40 *
41 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
42 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
43 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
44 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
45 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
46 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
47 * DEALINGS IN THE SOFTWARE.
48 */
49
50#include <stdlib.h>
51#include "xkbcommon/xkbcommon.h"
52#include "utils.h"
53#include "keysym.h"
54#include "ks_tables.h"
55
56static inline const char *
57get_name(const struct name_keysym *entry)
58{
59    return keysym_names + entry->offset;
60}
61
62static int
63compare_by_keysym(const void *a, const void *b)
64{
65    const xkb_keysym_t *key = a;
66    const struct name_keysym *entry = b;
67    if (*key < entry->keysym)
68        return -1;
69    if (*key > entry->keysym)
70        return 1;
71    return 0;
72}
73
74static int
75compare_by_name(const void *a, const void *b)
76{
77    const char *key = a;
78    const struct name_keysym *entry = b;
79    return strcasecmp(key, get_name(entry));
80}
81
82XKB_EXPORT int
83xkb_keysym_get_name(xkb_keysym_t ks, char *buffer, size_t size)
84{
85    const struct name_keysym *entry;
86
87    if ((ks & ((unsigned long) ~0x1fffffff)) != 0) {
88        snprintf(buffer, size, "Invalid");
89        return -1;
90    }
91
92    entry = bsearch(&ks, keysym_to_name,
93                    ARRAY_SIZE(keysym_to_name),
94                    sizeof(*keysym_to_name),
95                    compare_by_keysym);
96    if (entry)
97        return snprintf(buffer, size, "%s", get_name(entry));
98
99    /* Unnamed Unicode codepoint. */
100    if (ks >= 0x01000100 && ks <= 0x0110ffff) {
101        const int width = (ks & 0xff0000UL) ? 8 : 4;
102        return snprintf(buffer, size, "U%0*lX", width, ks & 0xffffffUL);
103    }
104
105    /* Unnamed, non-Unicode, symbol (shouldn't generally happen). */
106    return snprintf(buffer, size, "0x%08x", ks);
107}
108
109/*
110 * Find the correct keysym if one case-insensitive match is given.
111 *
112 * The name_to_keysym table is sorted by strcasecmp(). So bsearch() may return
113 * _any_ of all possible case-insensitive duplicates. This function searches the
114 * returned entry @entry, all previous and all next entries that match by
115 * case-insensitive comparison and returns the exact match to @name. If @icase
116 * is true, then this returns the best case-insensitive match instead of a
117 * correct match.
118 * The "best" case-insensitive match is the lower-case keysym which we find with
119 * the help of xkb_keysym_is_lower().
120 * The only keysyms that only differ by letter-case are keysyms that are
121 * available as lower-case and upper-case variant (like KEY_a and KEY_A). So
122 * returning the first lower-case match is enough in this case.
123 */
124static const struct name_keysym *
125find_sym(const struct name_keysym *entry, const char *name, bool icase)
126{
127    const struct name_keysym *iter, *last;
128    size_t len = ARRAY_SIZE(name_to_keysym);
129
130    if (!entry)
131        return NULL;
132
133    if (!icase && strcmp(get_name(entry), name) == 0)
134        return entry;
135    if (icase && xkb_keysym_is_lower(entry->keysym))
136        return entry;
137
138    for (iter = entry - 1; iter >= name_to_keysym; --iter) {
139        if (!icase && strcmp(get_name(iter), name) == 0)
140            return iter;
141        if (strcasecmp(get_name(iter), get_name(entry)) != 0)
142            break;
143        if (icase && xkb_keysym_is_lower(iter->keysym))
144            return iter;
145    }
146
147    last = name_to_keysym + len;
148    for (iter = entry + 1; iter < last; ++iter) {
149        if (!icase && strcmp(get_name(iter), name) == 0)
150            return iter;
151        if (strcasecmp(get_name(iter), get_name(entry)) != 0)
152            break;
153        if (icase && xkb_keysym_is_lower(iter->keysym))
154            return iter;
155    }
156
157    if (icase)
158        return entry;
159    return NULL;
160}
161
162XKB_EXPORT xkb_keysym_t
163xkb_keysym_from_name(const char *s, enum xkb_keysym_flags flags)
164{
165    const struct name_keysym *entry;
166    char *tmp;
167    xkb_keysym_t val;
168    bool icase = (flags & XKB_KEYSYM_CASE_INSENSITIVE);
169
170    if (flags & ~XKB_KEYSYM_CASE_INSENSITIVE)
171        return XKB_KEY_NoSymbol;
172
173    entry = bsearch(s, name_to_keysym,
174                    ARRAY_SIZE(name_to_keysym),
175                    sizeof(*name_to_keysym),
176                    compare_by_name);
177    entry = find_sym(entry, s, icase);
178    if (entry)
179        return entry->keysym;
180
181    if (*s == 'U' || (icase && *s == 'u')) {
182        val = strtoul(&s[1], &tmp, 16);
183        if (tmp && *tmp != '\0')
184            return XKB_KEY_NoSymbol;
185
186        if (val < 0x20 || (val > 0x7e && val < 0xa0))
187            return XKB_KEY_NoSymbol;
188        if (val < 0x100)
189            return val;
190        if (val > 0x10ffff)
191            return XKB_KEY_NoSymbol;
192        return val | 0x01000000;
193    }
194    else if (s[0] == '0' && (s[1] == 'x' || (icase && s[1] == 'X'))) {
195        val = strtoul(&s[2], &tmp, 16);
196        if (tmp && *tmp != '\0')
197            return XKB_KEY_NoSymbol;
198
199        return val;
200    }
201
202    /* Stupid inconsistency between the headers and XKeysymDB: the former has
203     * no separating underscore, while some XF86* syms in the latter did.
204     * As a last ditch effort, try without. */
205    if (strncmp(s, "XF86_", 5) == 0 ||
206        (icase && strncasecmp(s, "XF86_", 5) == 0)) {
207        xkb_keysym_t ret;
208        tmp = strdup(s);
209        if (!tmp)
210            return XKB_KEY_NoSymbol;
211        memmove(&tmp[4], &tmp[5], strlen(s) - 5 + 1);
212        ret = xkb_keysym_from_name(tmp, flags);
213        free(tmp);
214        return ret;
215    }
216
217    return XKB_KEY_NoSymbol;
218}
219
220bool
221xkb_keysym_is_keypad(xkb_keysym_t keysym)
222{
223    return keysym >= XKB_KEY_KP_Space && keysym <= XKB_KEY_KP_Equal;
224}
225
226
227bool
228xkb_keysym_is_modifier(xkb_keysym_t keysym)
229{
230    return
231        (keysym >= XKB_KEY_Shift_L && keysym <= XKB_KEY_Hyper_R) ||
232        /* libX11 only goes upto XKB_KEY_ISO_Level5_Lock. */
233        (keysym >= XKB_KEY_ISO_Lock && keysym <= XKB_KEY_ISO_Last_Group_Lock) ||
234        keysym == XKB_KEY_Mode_switch ||
235        keysym == XKB_KEY_Num_Lock;
236}
237
238static void
239XConvertCase(xkb_keysym_t sym, xkb_keysym_t *lower, xkb_keysym_t *upper);
240
241bool
242xkb_keysym_is_lower(xkb_keysym_t ks)
243{
244    xkb_keysym_t lower, upper;
245
246    XConvertCase(ks, &lower, &upper);
247
248    if (lower == upper)
249        return false;
250
251    return (ks == lower ? true : false);
252}
253
254bool
255xkb_keysym_is_upper(xkb_keysym_t ks)
256{
257    xkb_keysym_t lower, upper;
258
259    XConvertCase(ks, &lower, &upper);
260
261    if (lower == upper)
262        return false;
263
264    return (ks == upper ? true : false);
265}
266
267xkb_keysym_t
268xkb_keysym_to_lower(xkb_keysym_t ks)
269{
270    xkb_keysym_t lower, upper;
271
272    XConvertCase(ks, &lower, &upper);
273
274    return lower;
275}
276
277xkb_keysym_t
278xkb_keysym_to_upper(xkb_keysym_t ks)
279{
280    xkb_keysym_t lower, upper;
281
282    XConvertCase(ks, &lower, &upper);
283
284    return upper;
285}
286
287/*
288 * The following is copied verbatim from libX11:src/KeyBind.c, commit
289 * d45b3fc19fbe95c41afc4e51d768df6d42332010, with the following changes:
290 *  - unsigned -> uint32_t
291 *  - unsigend short -> uint16_t
292 *  - s/XK_/XKB_KEY_
293 *
294 * XXX: If newlocale() and iswlower_l()/iswupper_l() interface ever
295 *      become portable, we should use that in conjunction with
296 *      xkb_keysym_to_utf32(), instead of all this stuff.  We should
297 *      be sure to give the same results as libX11, though, and be
298 *      locale independent; this information is used by xkbcomp to
299 *      find the automatic type to assign to key groups.
300 */
301
302static void
303UCSConvertCase(uint32_t code, xkb_keysym_t *lower, xkb_keysym_t *upper)
304{
305    /* Case conversion for UCS, as in Unicode Data version 4.0.0 */
306    /* NB: Only converts simple one-to-one mappings. */
307
308    /* Tables are used where they take less space than     */
309    /* the code to work out the mappings. Zero values mean */
310    /* undefined code points.                              */
311
312    static uint16_t const IPAExt_upper_mapping[] = { /* part only */
313                            0x0181, 0x0186, 0x0255, 0x0189, 0x018A,
314    0x0258, 0x018F, 0x025A, 0x0190, 0x025C, 0x025D, 0x025E, 0x025F,
315    0x0193, 0x0261, 0x0262, 0x0194, 0x0264, 0x0265, 0x0266, 0x0267,
316    0x0197, 0x0196, 0x026A, 0x026B, 0x026C, 0x026D, 0x026E, 0x019C,
317    0x0270, 0x0271, 0x019D, 0x0273, 0x0274, 0x019F, 0x0276, 0x0277,
318    0x0278, 0x0279, 0x027A, 0x027B, 0x027C, 0x027D, 0x027E, 0x027F,
319    0x01A6, 0x0281, 0x0282, 0x01A9, 0x0284, 0x0285, 0x0286, 0x0287,
320    0x01AE, 0x0289, 0x01B1, 0x01B2, 0x028C, 0x028D, 0x028E, 0x028F,
321    0x0290, 0x0291, 0x01B7
322    };
323
324    static uint16_t const LatinExtB_upper_mapping[] = { /* first part only */
325    0x0180, 0x0181, 0x0182, 0x0182, 0x0184, 0x0184, 0x0186, 0x0187,
326    0x0187, 0x0189, 0x018A, 0x018B, 0x018B, 0x018D, 0x018E, 0x018F,
327    0x0190, 0x0191, 0x0191, 0x0193, 0x0194, 0x01F6, 0x0196, 0x0197,
328    0x0198, 0x0198, 0x019A, 0x019B, 0x019C, 0x019D, 0x0220, 0x019F,
329    0x01A0, 0x01A0, 0x01A2, 0x01A2, 0x01A4, 0x01A4, 0x01A6, 0x01A7,
330    0x01A7, 0x01A9, 0x01AA, 0x01AB, 0x01AC, 0x01AC, 0x01AE, 0x01AF,
331    0x01AF, 0x01B1, 0x01B2, 0x01B3, 0x01B3, 0x01B5, 0x01B5, 0x01B7,
332    0x01B8, 0x01B8, 0x01BA, 0x01BB, 0x01BC, 0x01BC, 0x01BE, 0x01F7,
333    0x01C0, 0x01C1, 0x01C2, 0x01C3, 0x01C4, 0x01C4, 0x01C4, 0x01C7,
334    0x01C7, 0x01C7, 0x01CA, 0x01CA, 0x01CA
335    };
336
337    static uint16_t const LatinExtB_lower_mapping[] = { /* first part only */
338    0x0180, 0x0253, 0x0183, 0x0183, 0x0185, 0x0185, 0x0254, 0x0188,
339    0x0188, 0x0256, 0x0257, 0x018C, 0x018C, 0x018D, 0x01DD, 0x0259,
340    0x025B, 0x0192, 0x0192, 0x0260, 0x0263, 0x0195, 0x0269, 0x0268,
341    0x0199, 0x0199, 0x019A, 0x019B, 0x026F, 0x0272, 0x019E, 0x0275,
342    0x01A1, 0x01A1, 0x01A3, 0x01A3, 0x01A5, 0x01A5, 0x0280, 0x01A8,
343    0x01A8, 0x0283, 0x01AA, 0x01AB, 0x01AD, 0x01AD, 0x0288, 0x01B0,
344    0x01B0, 0x028A, 0x028B, 0x01B4, 0x01B4, 0x01B6, 0x01B6, 0x0292,
345    0x01B9, 0x01B9, 0x01BA, 0x01BB, 0x01BD, 0x01BD, 0x01BE, 0x01BF,
346    0x01C0, 0x01C1, 0x01C2, 0x01C3, 0x01C6, 0x01C6, 0x01C6, 0x01C9,
347    0x01C9, 0x01C9, 0x01CC, 0x01CC, 0x01CC
348    };
349
350    static uint16_t const Greek_upper_mapping[] = {
351    0x0000, 0x0000, 0x0000, 0x0000, 0x0374, 0x0375, 0x0000, 0x0000,
352    0x0000, 0x0000, 0x037A, 0x0000, 0x0000, 0x0000, 0x037E, 0x0000,
353    0x0000, 0x0000, 0x0000, 0x0000, 0x0384, 0x0385, 0x0386, 0x0387,
354    0x0388, 0x0389, 0x038A, 0x0000, 0x038C, 0x0000, 0x038E, 0x038F,
355    0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397,
356    0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F,
357    0x03A0, 0x03A1, 0x0000, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7,
358    0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x0386, 0x0388, 0x0389, 0x038A,
359    0x03B0, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397,
360    0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F,
361    0x03A0, 0x03A1, 0x03A3, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7,
362    0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x038C, 0x038E, 0x038F, 0x0000,
363    0x0392, 0x0398, 0x03D2, 0x03D3, 0x03D4, 0x03A6, 0x03A0, 0x03D7,
364    0x03D8, 0x03D8, 0x03DA, 0x03DA, 0x03DC, 0x03DC, 0x03DE, 0x03DE,
365    0x03E0, 0x03E0, 0x03E2, 0x03E2, 0x03E4, 0x03E4, 0x03E6, 0x03E6,
366    0x03E8, 0x03E8, 0x03EA, 0x03EA, 0x03EC, 0x03EC, 0x03EE, 0x03EE,
367    0x039A, 0x03A1, 0x03F9, 0x03F3, 0x03F4, 0x0395, 0x03F6, 0x03F7,
368    0x03F7, 0x03F9, 0x03FA, 0x03FA, 0x0000, 0x0000, 0x0000, 0x0000
369    };
370
371    static uint16_t const Greek_lower_mapping[] = {
372    0x0000, 0x0000, 0x0000, 0x0000, 0x0374, 0x0375, 0x0000, 0x0000,
373    0x0000, 0x0000, 0x037A, 0x0000, 0x0000, 0x0000, 0x037E, 0x0000,
374    0x0000, 0x0000, 0x0000, 0x0000, 0x0384, 0x0385, 0x03AC, 0x0387,
375    0x03AD, 0x03AE, 0x03AF, 0x0000, 0x03CC, 0x0000, 0x03CD, 0x03CE,
376    0x0390, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7,
377    0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
378    0x03C0, 0x03C1, 0x0000, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7,
379    0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03AC, 0x03AD, 0x03AE, 0x03AF,
380    0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7,
381    0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
382    0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7,
383    0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x0000,
384    0x03D0, 0x03D1, 0x03D2, 0x03D3, 0x03D4, 0x03D5, 0x03D6, 0x03D7,
385    0x03D9, 0x03D9, 0x03DB, 0x03DB, 0x03DD, 0x03DD, 0x03DF, 0x03DF,
386    0x03E1, 0x03E1, 0x03E3, 0x03E3, 0x03E5, 0x03E5, 0x03E7, 0x03E7,
387    0x03E9, 0x03E9, 0x03EB, 0x03EB, 0x03ED, 0x03ED, 0x03EF, 0x03EF,
388    0x03F0, 0x03F1, 0x03F2, 0x03F3, 0x03B8, 0x03F5, 0x03F6, 0x03F8,
389    0x03F8, 0x03F2, 0x03FB, 0x03FB, 0x0000, 0x0000, 0x0000, 0x0000
390    };
391
392    static uint16_t const GreekExt_lower_mapping[] = {
393    0x1F00, 0x1F01, 0x1F02, 0x1F03, 0x1F04, 0x1F05, 0x1F06, 0x1F07,
394    0x1F00, 0x1F01, 0x1F02, 0x1F03, 0x1F04, 0x1F05, 0x1F06, 0x1F07,
395    0x1F10, 0x1F11, 0x1F12, 0x1F13, 0x1F14, 0x1F15, 0x0000, 0x0000,
396    0x1F10, 0x1F11, 0x1F12, 0x1F13, 0x1F14, 0x1F15, 0x0000, 0x0000,
397    0x1F20, 0x1F21, 0x1F22, 0x1F23, 0x1F24, 0x1F25, 0x1F26, 0x1F27,
398    0x1F20, 0x1F21, 0x1F22, 0x1F23, 0x1F24, 0x1F25, 0x1F26, 0x1F27,
399    0x1F30, 0x1F31, 0x1F32, 0x1F33, 0x1F34, 0x1F35, 0x1F36, 0x1F37,
400    0x1F30, 0x1F31, 0x1F32, 0x1F33, 0x1F34, 0x1F35, 0x1F36, 0x1F37,
401    0x1F40, 0x1F41, 0x1F42, 0x1F43, 0x1F44, 0x1F45, 0x0000, 0x0000,
402    0x1F40, 0x1F41, 0x1F42, 0x1F43, 0x1F44, 0x1F45, 0x0000, 0x0000,
403    0x1F50, 0x1F51, 0x1F52, 0x1F53, 0x1F54, 0x1F55, 0x1F56, 0x1F57,
404    0x0000, 0x1F51, 0x0000, 0x1F53, 0x0000, 0x1F55, 0x0000, 0x1F57,
405    0x1F60, 0x1F61, 0x1F62, 0x1F63, 0x1F64, 0x1F65, 0x1F66, 0x1F67,
406    0x1F60, 0x1F61, 0x1F62, 0x1F63, 0x1F64, 0x1F65, 0x1F66, 0x1F67,
407    0x1F70, 0x1F71, 0x1F72, 0x1F73, 0x1F74, 0x1F75, 0x1F76, 0x1F77,
408    0x1F78, 0x1F79, 0x1F7A, 0x1F7B, 0x1F7C, 0x1F7D, 0x0000, 0x0000,
409    0x1F80, 0x1F81, 0x1F82, 0x1F83, 0x1F84, 0x1F85, 0x1F86, 0x1F87,
410    0x1F80, 0x1F81, 0x1F82, 0x1F83, 0x1F84, 0x1F85, 0x1F86, 0x1F87,
411    0x1F90, 0x1F91, 0x1F92, 0x1F93, 0x1F94, 0x1F95, 0x1F96, 0x1F97,
412    0x1F90, 0x1F91, 0x1F92, 0x1F93, 0x1F94, 0x1F95, 0x1F96, 0x1F97,
413    0x1FA0, 0x1FA1, 0x1FA2, 0x1FA3, 0x1FA4, 0x1FA5, 0x1FA6, 0x1FA7,
414    0x1FA0, 0x1FA1, 0x1FA2, 0x1FA3, 0x1FA4, 0x1FA5, 0x1FA6, 0x1FA7,
415    0x1FB0, 0x1FB1, 0x1FB2, 0x1FB3, 0x1FB4, 0x0000, 0x1FB6, 0x1FB7,
416    0x1FB0, 0x1FB1, 0x1F70, 0x1F71, 0x1FB3, 0x1FBD, 0x1FBE, 0x1FBF,
417    0x1FC0, 0x1FC1, 0x1FC2, 0x1FC3, 0x1FC4, 0x0000, 0x1FC6, 0x1FC7,
418    0x1F72, 0x1F73, 0x1F74, 0x1F75, 0x1FC3, 0x1FCD, 0x1FCE, 0x1FCF,
419    0x1FD0, 0x1FD1, 0x1FD2, 0x1FD3, 0x0000, 0x0000, 0x1FD6, 0x1FD7,
420    0x1FD0, 0x1FD1, 0x1F76, 0x1F77, 0x0000, 0x1FDD, 0x1FDE, 0x1FDF,
421    0x1FE0, 0x1FE1, 0x1FE2, 0x1FE3, 0x1FE4, 0x1FE5, 0x1FE6, 0x1FE7,
422    0x1FE0, 0x1FE1, 0x1F7A, 0x1F7B, 0x1FE5, 0x1FED, 0x1FEE, 0x1FEF,
423    0x0000, 0x0000, 0x1FF2, 0x1FF3, 0x1FF4, 0x0000, 0x1FF6, 0x1FF7,
424    0x1F78, 0x1F79, 0x1F7C, 0x1F7D, 0x1FF3, 0x1FFD, 0x1FFE, 0x0000
425    };
426
427    static uint16_t const GreekExt_upper_mapping[] = {
428    0x1F08, 0x1F09, 0x1F0A, 0x1F0B, 0x1F0C, 0x1F0D, 0x1F0E, 0x1F0F,
429    0x1F08, 0x1F09, 0x1F0A, 0x1F0B, 0x1F0C, 0x1F0D, 0x1F0E, 0x1F0F,
430    0x1F18, 0x1F19, 0x1F1A, 0x1F1B, 0x1F1C, 0x1F1D, 0x0000, 0x0000,
431    0x1F18, 0x1F19, 0x1F1A, 0x1F1B, 0x1F1C, 0x1F1D, 0x0000, 0x0000,
432    0x1F28, 0x1F29, 0x1F2A, 0x1F2B, 0x1F2C, 0x1F2D, 0x1F2E, 0x1F2F,
433    0x1F28, 0x1F29, 0x1F2A, 0x1F2B, 0x1F2C, 0x1F2D, 0x1F2E, 0x1F2F,
434    0x1F38, 0x1F39, 0x1F3A, 0x1F3B, 0x1F3C, 0x1F3D, 0x1F3E, 0x1F3F,
435    0x1F38, 0x1F39, 0x1F3A, 0x1F3B, 0x1F3C, 0x1F3D, 0x1F3E, 0x1F3F,
436    0x1F48, 0x1F49, 0x1F4A, 0x1F4B, 0x1F4C, 0x1F4D, 0x0000, 0x0000,
437    0x1F48, 0x1F49, 0x1F4A, 0x1F4B, 0x1F4C, 0x1F4D, 0x0000, 0x0000,
438    0x1F50, 0x1F59, 0x1F52, 0x1F5B, 0x1F54, 0x1F5D, 0x1F56, 0x1F5F,
439    0x0000, 0x1F59, 0x0000, 0x1F5B, 0x0000, 0x1F5D, 0x0000, 0x1F5F,
440    0x1F68, 0x1F69, 0x1F6A, 0x1F6B, 0x1F6C, 0x1F6D, 0x1F6E, 0x1F6F,
441    0x1F68, 0x1F69, 0x1F6A, 0x1F6B, 0x1F6C, 0x1F6D, 0x1F6E, 0x1F6F,
442    0x1FBA, 0x1FBB, 0x1FC8, 0x1FC9, 0x1FCA, 0x1FCB, 0x1FDA, 0x1FDB,
443    0x1FF8, 0x1FF9, 0x1FEA, 0x1FEB, 0x1FFA, 0x1FFB, 0x0000, 0x0000,
444    0x1F88, 0x1F89, 0x1F8A, 0x1F8B, 0x1F8C, 0x1F8D, 0x1F8E, 0x1F8F,
445    0x1F88, 0x1F89, 0x1F8A, 0x1F8B, 0x1F8C, 0x1F8D, 0x1F8E, 0x1F8F,
446    0x1F98, 0x1F99, 0x1F9A, 0x1F9B, 0x1F9C, 0x1F9D, 0x1F9E, 0x1F9F,
447    0x1F98, 0x1F99, 0x1F9A, 0x1F9B, 0x1F9C, 0x1F9D, 0x1F9E, 0x1F9F,
448    0x1FA8, 0x1FA9, 0x1FAA, 0x1FAB, 0x1FAC, 0x1FAD, 0x1FAE, 0x1FAF,
449    0x1FA8, 0x1FA9, 0x1FAA, 0x1FAB, 0x1FAC, 0x1FAD, 0x1FAE, 0x1FAF,
450    0x1FB8, 0x1FB9, 0x1FB2, 0x1FBC, 0x1FB4, 0x0000, 0x1FB6, 0x1FB7,
451    0x1FB8, 0x1FB9, 0x1FBA, 0x1FBB, 0x1FBC, 0x1FBD, 0x0399, 0x1FBF,
452    0x1FC0, 0x1FC1, 0x1FC2, 0x1FCC, 0x1FC4, 0x0000, 0x1FC6, 0x1FC7,
453    0x1FC8, 0x1FC9, 0x1FCA, 0x1FCB, 0x1FCC, 0x1FCD, 0x1FCE, 0x1FCF,
454    0x1FD8, 0x1FD9, 0x1FD2, 0x1FD3, 0x0000, 0x0000, 0x1FD6, 0x1FD7,
455    0x1FD8, 0x1FD9, 0x1FDA, 0x1FDB, 0x0000, 0x1FDD, 0x1FDE, 0x1FDF,
456    0x1FE8, 0x1FE9, 0x1FE2, 0x1FE3, 0x1FE4, 0x1FEC, 0x1FE6, 0x1FE7,
457    0x1FE8, 0x1FE9, 0x1FEA, 0x1FEB, 0x1FEC, 0x1FED, 0x1FEE, 0x1FEF,
458    0x0000, 0x0000, 0x1FF2, 0x1FFC, 0x1FF4, 0x0000, 0x1FF6, 0x1FF7,
459    0x1FF8, 0x1FF9, 0x1FFA, 0x1FFB, 0x1FFC, 0x1FFD, 0x1FFE, 0x0000
460    };
461
462    *lower = code;
463    *upper = code;
464
465    /* Basic Latin and Latin-1 Supplement, U+0000 to U+00FF */
466    if (code <= 0x00ff) {
467        if (code >= 0x0041 && code <= 0x005a)             /* A-Z */
468            *lower += 0x20;
469        else if (code >= 0x0061 && code <= 0x007a)        /* a-z */
470            *upper -= 0x20;
471        else if ( (code >= 0x00c0 && code <= 0x00d6) ||
472	          (code >= 0x00d8 && code <= 0x00de) )
473            *lower += 0x20;
474        else if ( (code >= 0x00e0 && code <= 0x00f6) ||
475	          (code >= 0x00f8 && code <= 0x00fe) )
476            *upper -= 0x20;
477        else if (code == 0x00ff)      /* y with diaeresis */
478            *upper = 0x0178;
479        else if (code == 0x00b5)      /* micro sign */
480            *upper = 0x039c;
481	return;
482    }
483
484    /* Latin Extended-A, U+0100 to U+017F */
485    if (code >= 0x0100 && code <= 0x017f) {
486        if ( (code >= 0x0100 && code <= 0x012f) ||
487             (code >= 0x0132 && code <= 0x0137) ||
488             (code >= 0x014a && code <= 0x0177) ) {
489            *upper = code & ~1;
490            *lower = code | 1;
491        }
492        else if ( (code >= 0x0139 && code <= 0x0148) ||
493                  (code >= 0x0179 && code <= 0x017e) ) {
494            if (code & 1)
495	        *lower += 1;
496            else
497	        *upper -= 1;
498        }
499        else if (code == 0x0130)
500            *lower = 0x0069;
501        else if (code == 0x0131)
502            *upper = 0x0049;
503        else if (code == 0x0178)
504            *lower = 0x00ff;
505        else if (code == 0x017f)
506            *upper = 0x0053;
507        return;
508    }
509
510    /* Latin Extended-B, U+0180 to U+024F */
511    if (code >= 0x0180 && code <= 0x024f) {
512        if (code >= 0x01cd && code <= 0x01dc) {
513	    if (code & 1)
514	       *lower += 1;
515	    else
516	       *upper -= 1;
517        }
518        else if ( (code >= 0x01de && code <= 0x01ef) ||
519                  (code >= 0x01f4 && code <= 0x01f5) ||
520                  (code >= 0x01f8 && code <= 0x021f) ||
521                  (code >= 0x0222 && code <= 0x0233) ) {
522            *lower |= 1;
523            *upper &= ~1;
524        }
525        else if (code >= 0x0180 && code <= 0x01cc) {
526            *lower = LatinExtB_lower_mapping[code - 0x0180];
527            *upper = LatinExtB_upper_mapping[code - 0x0180];
528        }
529        else if (code == 0x01dd)
530            *upper = 0x018e;
531        else if (code == 0x01f1 || code == 0x01f2) {
532            *lower = 0x01f3;
533            *upper = 0x01f1;
534        }
535        else if (code == 0x01f3)
536            *upper = 0x01f1;
537        else if (code == 0x01f6)
538            *lower = 0x0195;
539        else if (code == 0x01f7)
540            *lower = 0x01bf;
541        else if (code == 0x0220)
542            *lower = 0x019e;
543        return;
544    }
545
546    /* IPA Extensions, U+0250 to U+02AF */
547    if (code >= 0x0253 && code <= 0x0292) {
548        *upper = IPAExt_upper_mapping[code - 0x0253];
549    }
550
551    /* Combining Diacritical Marks, U+0300 to U+036F */
552    if (code == 0x0345) {
553        *upper = 0x0399;
554    }
555
556    /* Greek and Coptic, U+0370 to U+03FF */
557    if (code >= 0x0370 && code <= 0x03ff) {
558        *lower = Greek_lower_mapping[code - 0x0370];
559        *upper = Greek_upper_mapping[code - 0x0370];
560        if (*upper == 0)
561            *upper = code;
562        if (*lower == 0)
563            *lower = code;
564    }
565
566    /* Cyrillic and Cyrillic Supplementary, U+0400 to U+052F */
567    if ( (code >= 0x0400 && code <= 0x04ff) ||
568         (code >= 0x0500 && code <= 0x052f) ) {
569        if (code >= 0x0400 && code <= 0x040f)
570            *lower += 0x50;
571        else if (code >= 0x0410 && code <= 0x042f)
572            *lower += 0x20;
573        else if (code >= 0x0430 && code <= 0x044f)
574            *upper -= 0x20;
575        else if (code >= 0x0450 && code <= 0x045f)
576            *upper -= 0x50;
577        else if ( (code >= 0x0460 && code <= 0x0481) ||
578                  (code >= 0x048a && code <= 0x04bf) ||
579	          (code >= 0x04d0 && code <= 0x04f5) ||
580	          (code >= 0x04f8 && code <= 0x04f9) ||
581                  (code >= 0x0500 && code <= 0x050f) ) {
582            *upper &= ~1;
583            *lower |= 1;
584        }
585        else if (code >= 0x04c1 && code <= 0x04ce) {
586	    if (code & 1)
587	        *lower += 1;
588	    else
589	        *upper -= 1;
590        }
591    }
592
593    /* Armenian, U+0530 to U+058F */
594    if (code >= 0x0530 && code <= 0x058f) {
595        if (code >= 0x0531 && code <= 0x0556)
596            *lower += 0x30;
597        else if (code >=0x0561 && code <= 0x0586)
598            *upper -= 0x30;
599    }
600
601    /* Latin Extended Additional, U+1E00 to U+1EFF */
602    if (code >= 0x1e00 && code <= 0x1eff) {
603        if ( (code >= 0x1e00 && code <= 0x1e95) ||
604             (code >= 0x1ea0 && code <= 0x1ef9) ) {
605            *upper &= ~1;
606            *lower |= 1;
607        }
608        else if (code == 0x1e9b)
609            *upper = 0x1e60;
610    }
611
612    /* Greek Extended, U+1F00 to U+1FFF */
613    if (code >= 0x1f00 && code <= 0x1fff) {
614        *lower = GreekExt_lower_mapping[code - 0x1f00];
615        *upper = GreekExt_upper_mapping[code - 0x1f00];
616        if (*upper == 0)
617            *upper = code;
618        if (*lower == 0)
619            *lower = code;
620    }
621
622    /* Letterlike Symbols, U+2100 to U+214F */
623    if (code >= 0x2100 && code <= 0x214f) {
624        switch (code) {
625        case 0x2126: *lower = 0x03c9; break;
626        case 0x212a: *lower = 0x006b; break;
627        case 0x212b: *lower = 0x00e5; break;
628        }
629    }
630    /* Number Forms, U+2150 to U+218F */
631    else if (code >= 0x2160 && code <= 0x216f)
632        *lower += 0x10;
633    else if (code >= 0x2170 && code <= 0x217f)
634        *upper -= 0x10;
635    /* Enclosed Alphanumerics, U+2460 to U+24FF */
636    else if (code >= 0x24b6 && code <= 0x24cf)
637        *lower += 0x1a;
638    else if (code >= 0x24d0 && code <= 0x24e9)
639        *upper -= 0x1a;
640    /* Halfwidth and Fullwidth Forms, U+FF00 to U+FFEF */
641    else if (code >= 0xff21 && code <= 0xff3a)
642        *lower += 0x20;
643    else if (code >= 0xff41 && code <= 0xff5a)
644        *upper -= 0x20;
645    /* Deseret, U+10400 to U+104FF */
646    else if (code >= 0x10400 && code <= 0x10427)
647        *lower += 0x28;
648    else if (code >= 0x10428 && code <= 0x1044f)
649        *upper -= 0x28;
650}
651
652static void
653XConvertCase(xkb_keysym_t sym, xkb_keysym_t *lower, xkb_keysym_t *upper)
654{
655    /* Latin 1 keysym */
656    if (sym < 0x100) {
657        UCSConvertCase(sym, lower, upper);
658	return;
659    }
660
661    /* Unicode keysym */
662    if ((sym & 0xff000000) == 0x01000000) {
663        UCSConvertCase((sym & 0x00ffffff), lower, upper);
664        *upper |= 0x01000000;
665        *lower |= 0x01000000;
666        return;
667    }
668
669    /* Legacy keysym */
670
671    *lower = sym;
672    *upper = sym;
673
674    switch(sym >> 8) {
675    case 1: /* Latin 2 */
676	/* Assume the KeySym is a legal value (ignore discontinuities) */
677	if (sym == XKB_KEY_Aogonek)
678	    *lower = XKB_KEY_aogonek;
679	else if (sym >= XKB_KEY_Lstroke && sym <= XKB_KEY_Sacute)
680	    *lower += (XKB_KEY_lstroke - XKB_KEY_Lstroke);
681	else if (sym >= XKB_KEY_Scaron && sym <= XKB_KEY_Zacute)
682	    *lower += (XKB_KEY_scaron - XKB_KEY_Scaron);
683	else if (sym >= XKB_KEY_Zcaron && sym <= XKB_KEY_Zabovedot)
684	    *lower += (XKB_KEY_zcaron - XKB_KEY_Zcaron);
685	else if (sym == XKB_KEY_aogonek)
686	    *upper = XKB_KEY_Aogonek;
687	else if (sym >= XKB_KEY_lstroke && sym <= XKB_KEY_sacute)
688	    *upper -= (XKB_KEY_lstroke - XKB_KEY_Lstroke);
689	else if (sym >= XKB_KEY_scaron && sym <= XKB_KEY_zacute)
690	    *upper -= (XKB_KEY_scaron - XKB_KEY_Scaron);
691	else if (sym >= XKB_KEY_zcaron && sym <= XKB_KEY_zabovedot)
692	    *upper -= (XKB_KEY_zcaron - XKB_KEY_Zcaron);
693	else if (sym >= XKB_KEY_Racute && sym <= XKB_KEY_Tcedilla)
694	    *lower += (XKB_KEY_racute - XKB_KEY_Racute);
695	else if (sym >= XKB_KEY_racute && sym <= XKB_KEY_tcedilla)
696	    *upper -= (XKB_KEY_racute - XKB_KEY_Racute);
697	break;
698    case 2: /* Latin 3 */
699	/* Assume the KeySym is a legal value (ignore discontinuities) */
700	if (sym >= XKB_KEY_Hstroke && sym <= XKB_KEY_Hcircumflex)
701	    *lower += (XKB_KEY_hstroke - XKB_KEY_Hstroke);
702	else if (sym >= XKB_KEY_Gbreve && sym <= XKB_KEY_Jcircumflex)
703	    *lower += (XKB_KEY_gbreve - XKB_KEY_Gbreve);
704	else if (sym >= XKB_KEY_hstroke && sym <= XKB_KEY_hcircumflex)
705	    *upper -= (XKB_KEY_hstroke - XKB_KEY_Hstroke);
706	else if (sym >= XKB_KEY_gbreve && sym <= XKB_KEY_jcircumflex)
707	    *upper -= (XKB_KEY_gbreve - XKB_KEY_Gbreve);
708	else if (sym >= XKB_KEY_Cabovedot && sym <= XKB_KEY_Scircumflex)
709	    *lower += (XKB_KEY_cabovedot - XKB_KEY_Cabovedot);
710	else if (sym >= XKB_KEY_cabovedot && sym <= XKB_KEY_scircumflex)
711	    *upper -= (XKB_KEY_cabovedot - XKB_KEY_Cabovedot);
712	break;
713    case 3: /* Latin 4 */
714	/* Assume the KeySym is a legal value (ignore discontinuities) */
715	if (sym >= XKB_KEY_Rcedilla && sym <= XKB_KEY_Tslash)
716	    *lower += (XKB_KEY_rcedilla - XKB_KEY_Rcedilla);
717	else if (sym >= XKB_KEY_rcedilla && sym <= XKB_KEY_tslash)
718	    *upper -= (XKB_KEY_rcedilla - XKB_KEY_Rcedilla);
719	else if (sym == XKB_KEY_ENG)
720	    *lower = XKB_KEY_eng;
721	else if (sym == XKB_KEY_eng)
722	    *upper = XKB_KEY_ENG;
723	else if (sym >= XKB_KEY_Amacron && sym <= XKB_KEY_Umacron)
724	    *lower += (XKB_KEY_amacron - XKB_KEY_Amacron);
725	else if (sym >= XKB_KEY_amacron && sym <= XKB_KEY_umacron)
726	    *upper -= (XKB_KEY_amacron - XKB_KEY_Amacron);
727	break;
728    case 6: /* Cyrillic */
729	/* Assume the KeySym is a legal value (ignore discontinuities) */
730	if (sym >= XKB_KEY_Serbian_DJE && sym <= XKB_KEY_Serbian_DZE)
731	    *lower -= (XKB_KEY_Serbian_DJE - XKB_KEY_Serbian_dje);
732	else if (sym >= XKB_KEY_Serbian_dje && sym <= XKB_KEY_Serbian_dze)
733	    *upper += (XKB_KEY_Serbian_DJE - XKB_KEY_Serbian_dje);
734	else if (sym >= XKB_KEY_Cyrillic_YU && sym <= XKB_KEY_Cyrillic_HARDSIGN)
735	    *lower -= (XKB_KEY_Cyrillic_YU - XKB_KEY_Cyrillic_yu);
736	else if (sym >= XKB_KEY_Cyrillic_yu && sym <= XKB_KEY_Cyrillic_hardsign)
737	    *upper += (XKB_KEY_Cyrillic_YU - XKB_KEY_Cyrillic_yu);
738        break;
739    case 7: /* Greek */
740	/* Assume the KeySym is a legal value (ignore discontinuities) */
741	if (sym >= XKB_KEY_Greek_ALPHAaccent && sym <= XKB_KEY_Greek_OMEGAaccent)
742	    *lower += (XKB_KEY_Greek_alphaaccent - XKB_KEY_Greek_ALPHAaccent);
743	else if (sym >= XKB_KEY_Greek_alphaaccent && sym <= XKB_KEY_Greek_omegaaccent &&
744		 sym != XKB_KEY_Greek_iotaaccentdieresis &&
745		 sym != XKB_KEY_Greek_upsilonaccentdieresis)
746	    *upper -= (XKB_KEY_Greek_alphaaccent - XKB_KEY_Greek_ALPHAaccent);
747	else if (sym >= XKB_KEY_Greek_ALPHA && sym <= XKB_KEY_Greek_OMEGA)
748	    *lower += (XKB_KEY_Greek_alpha - XKB_KEY_Greek_ALPHA);
749	else if (sym >= XKB_KEY_Greek_alpha && sym <= XKB_KEY_Greek_omega &&
750		 sym != XKB_KEY_Greek_finalsmallsigma)
751	    *upper -= (XKB_KEY_Greek_alpha - XKB_KEY_Greek_ALPHA);
752        break;
753    case 0x13: /* Latin 9 */
754        if (sym == XKB_KEY_OE)
755            *lower = XKB_KEY_oe;
756        else if (sym == XKB_KEY_oe)
757            *upper = XKB_KEY_OE;
758        else if (sym == XKB_KEY_Ydiaeresis)
759            *lower = XKB_KEY_ydiaeresis;
760        break;
761    }
762}
763