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