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