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