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