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