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