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