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