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