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