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