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