8ec7af1176e10633a170f02def807b3331bd5f6c
[platform/upstream/efl.git] / src / lib / ecore_x / xcb / ecore_xcb_keymap.c
1 #include "ecore_xcb_private.h"
2 #define NEED_KEYSYM_TABLE
3 #define NEED_VTABLE
4 #include "ecore_xcb_keysym_table.h"
5 #include <xcb/xcb_keysyms.h>
6 #include <X11/keysym.h>
7
8 /* local function prototypes */
9 static int          _ecore_xcb_keymap_mask_get(void        *reply,
10                                                xcb_keysym_t sym);
11 static xcb_keysym_t _ecore_xcb_keymap_string_to_keysym(const char *str);
12 static int          _ecore_xcb_keymap_translate_key(xcb_keycode_t keycode,
13                                                     unsigned int  modifiers,
14                                                     unsigned int *modifiers_return,
15                                                     xcb_keysym_t *keysym_return);
16 static int _ecore_xcb_keymap_translate_keysym(xcb_keysym_t keysym,
17                                               unsigned int modifiers,
18                                               char        *buffer,
19                                               int          bytes);
20
21 /* local variables */
22 static xcb_key_symbols_t *_ecore_xcb_keysyms;
23 static int _ecore_xcb_mode_switch = 0;
24
25 /* public variables */
26 EAPI int ECORE_X_MODIFIER_SHIFT = 0;
27 EAPI int ECORE_X_MODIFIER_CTRL = 0;
28 EAPI int ECORE_X_MODIFIER_ALT = 0;
29 EAPI int ECORE_X_MODIFIER_WIN = 0;
30 EAPI int ECORE_X_MODIFIER_ALTGR = 0;
31 EAPI int ECORE_X_LOCK_SCROLL = 0;
32 EAPI int ECORE_X_LOCK_NUM = 0;
33 EAPI int ECORE_X_LOCK_CAPS = 0;
34 EAPI int ECORE_X_LOCK_SHIFT = 0;
35
36 void
37 _ecore_xcb_keymap_init(void)
38 {
39    LOGFN(__FILE__, __LINE__, __FUNCTION__);
40
41    _ecore_xcb_keysyms = xcb_key_symbols_alloc(_ecore_xcb_conn);
42 }
43
44 void
45 _ecore_xcb_keymap_finalize(void)
46 {
47    xcb_get_modifier_mapping_cookie_t cookie;
48    xcb_get_modifier_mapping_reply_t *reply;
49
50    LOGFN(__FILE__, __LINE__, __FUNCTION__);
51    CHECK_XCB_CONN;
52
53    cookie = xcb_get_modifier_mapping_unchecked(_ecore_xcb_conn);
54    reply = xcb_get_modifier_mapping_reply(_ecore_xcb_conn, cookie, NULL);
55    if (!reply)
56      {
57         xcb_key_symbols_free(_ecore_xcb_keysyms);
58         return;
59      }
60
61    _ecore_xcb_mode_switch = _ecore_xcb_keymap_mask_get(reply, XK_Mode_switch);
62
63    ECORE_X_MODIFIER_SHIFT = _ecore_xcb_keymap_mask_get(reply, XK_Shift_L);
64    ECORE_X_MODIFIER_CTRL = _ecore_xcb_keymap_mask_get(reply, XK_Control_L);
65
66    ECORE_X_MODIFIER_ALT = _ecore_xcb_keymap_mask_get(reply, XK_Alt_L);
67    if (!ECORE_X_MODIFIER_ALT)
68      ECORE_X_MODIFIER_ALT = _ecore_xcb_keymap_mask_get(reply, XK_Meta_L);
69    if (!ECORE_X_MODIFIER_ALT)
70      ECORE_X_MODIFIER_ALT = _ecore_xcb_keymap_mask_get(reply, XK_Super_L);
71
72    ECORE_X_MODIFIER_WIN = _ecore_xcb_keymap_mask_get(reply, XK_Super_L);
73    if (!ECORE_X_MODIFIER_WIN)
74      ECORE_X_MODIFIER_WIN = _ecore_xcb_keymap_mask_get(reply, XK_Meta_L);
75
76    ECORE_X_MODIFIER_ALTGR = _ecore_xcb_keymap_mask_get(reply, XK_Mode_switch);
77
78    if (ECORE_X_MODIFIER_WIN == ECORE_X_MODIFIER_ALT)
79      ECORE_X_MODIFIER_WIN = 0;
80    if (ECORE_X_MODIFIER_ALT == ECORE_X_MODIFIER_CTRL)
81      ECORE_X_MODIFIER_ALT = 0;
82
83    if (ECORE_X_MODIFIER_ALTGR)
84      {
85         if ((ECORE_X_MODIFIER_ALTGR == ECORE_X_MODIFIER_SHIFT) ||
86             (ECORE_X_MODIFIER_ALTGR == ECORE_X_MODIFIER_CTRL) ||
87             (ECORE_X_MODIFIER_ALTGR == ECORE_X_MODIFIER_ALT) ||
88             (ECORE_X_MODIFIER_ALTGR == ECORE_X_MODIFIER_WIN))
89           {
90              ERR("ALTGR conflicts with other modifiers. IGNORE ALTGR");
91              ECORE_X_MODIFIER_ALTGR = 0;
92           }
93      }
94
95    if (ECORE_X_MODIFIER_ALT)
96      {
97         if ((ECORE_X_MODIFIER_ALT == ECORE_X_MODIFIER_SHIFT) ||
98             (ECORE_X_MODIFIER_ALT == ECORE_X_MODIFIER_CTRL) ||
99             (ECORE_X_MODIFIER_ALT == ECORE_X_MODIFIER_WIN))
100           {
101              ERR("ALT conflicts with other modifiers. IGNORE ALT");
102              ECORE_X_MODIFIER_ALT = 0;
103           }
104      }
105
106    if (ECORE_X_MODIFIER_WIN)
107      {
108         if ((ECORE_X_MODIFIER_WIN == ECORE_X_MODIFIER_SHIFT) ||
109             (ECORE_X_MODIFIER_WIN == ECORE_X_MODIFIER_CTRL))
110           {
111              ERR("WIN conflicts with other modifiers. IGNORE WIN");
112              ECORE_X_MODIFIER_WIN = 0;
113           }
114      }
115
116    if (ECORE_X_MODIFIER_SHIFT)
117      {
118         if ((ECORE_X_MODIFIER_SHIFT == ECORE_X_MODIFIER_CTRL))
119           {
120              ERR("CTRL conflicts with other modifiers. IGNORE CTRL");
121              ECORE_X_MODIFIER_CTRL = 0;
122           }
123      }
124
125    ECORE_X_LOCK_SCROLL = _ecore_xcb_keymap_mask_get(reply, XK_Scroll_Lock);
126    ECORE_X_LOCK_NUM = _ecore_xcb_keymap_mask_get(reply, XK_Num_Lock);
127    ECORE_X_LOCK_CAPS = _ecore_xcb_keymap_mask_get(reply, XK_Caps_Lock);
128    ECORE_X_LOCK_SHIFT = _ecore_xcb_keymap_mask_get(reply, XK_Shift_Lock);
129    free(reply);
130 }
131
132 void
133 _ecore_xcb_modifiers_get(void)
134 {
135    _ecore_xcb_keymap_finalize();
136 }
137
138 void
139 _ecore_xcb_keymap_shutdown(void)
140 {
141    LOGFN(__FILE__, __LINE__, __FUNCTION__);
142
143    if (_ecore_xcb_keysyms) xcb_key_symbols_free(_ecore_xcb_keysyms);
144 }
145
146 void
147 _ecore_xcb_keymap_refresh(xcb_mapping_notify_event_t *event)
148 {
149    CHECK_XCB_CONN;
150    xcb_refresh_keyboard_mapping(_ecore_xcb_keysyms, event);
151 }
152
153 xcb_keysym_t
154 _ecore_xcb_keymap_keycode_to_keysym(xcb_keycode_t keycode,
155                                     int           col)
156 {
157    xcb_keysym_t key0, key1;
158
159    CHECK_XCB_CONN;
160    if (col & _ecore_xcb_mode_switch)
161      {
162         key0 = xcb_key_symbols_get_keysym(_ecore_xcb_keysyms, keycode, 4);
163         key1 = xcb_key_symbols_get_keysym(_ecore_xcb_keysyms, keycode, 5);
164      }
165    else
166      {
167         key0 = xcb_key_symbols_get_keysym(_ecore_xcb_keysyms, keycode, 0);
168         key1 = xcb_key_symbols_get_keysym(_ecore_xcb_keysyms, keycode, 1);
169      }
170
171    if (key1 == XCB_NO_SYMBOL)
172      key1 = key0;
173
174    if ((col & ECORE_X_LOCK_NUM) &&
175        ((xcb_is_keypad_key(key1)) || (xcb_is_private_keypad_key(key1))))
176      {
177         if ((col & XCB_MOD_MASK_SHIFT) ||
178             ((col & XCB_MOD_MASK_LOCK) && (col & ECORE_X_LOCK_SHIFT)))
179           return key0;
180         else
181           return key1;
182      }
183    else if (!(col & XCB_MOD_MASK_SHIFT) && !(col & XCB_MOD_MASK_LOCK))
184      return key0;
185    else if (!(col & XCB_MOD_MASK_SHIFT) &&
186             (col & XCB_MOD_MASK_LOCK && (col & ECORE_X_LOCK_CAPS)))
187      return key1;
188    else if ((col & XCB_MOD_MASK_SHIFT) &&
189             (col & XCB_MOD_MASK_LOCK) && (col & ECORE_X_LOCK_CAPS))
190      return key0;
191    else if ((col & XCB_MOD_MASK_SHIFT) ||
192             (col & XCB_MOD_MASK_LOCK && (col & ECORE_X_LOCK_SHIFT)))
193      return key1;
194
195    return XCB_NO_SYMBOL;
196 }
197
198 xcb_keycode_t *
199 _ecore_xcb_keymap_keysym_to_keycode(xcb_keysym_t keysym)
200 {
201    CHECK_XCB_CONN;
202    return xcb_key_symbols_get_keycode(_ecore_xcb_keysyms, keysym);
203 }
204
205 char *
206 _ecore_xcb_keymap_keysym_to_string(xcb_keysym_t keysym)
207 {
208    int i = 0, n = 0, h = 0, idx = 0;
209    const unsigned char *entry;
210    unsigned char val1, val2, val3, val4;
211
212    CHECK_XCB_CONN;
213    if (!keysym) return NULL;
214    if (keysym == XK_VoidSymbol) keysym = 0;
215    if (keysym <= 0x1fffffff)
216      {
217         val1 = (keysym >> 24);
218         val2 = ((keysym >> 16) & 0xff);
219         val3 = ((keysym >> 8) & 0xff);
220         val4 = (keysym & 0xff);
221         i = keysym % VTABLESIZE;
222         h = i + 1;
223         n = VMAXHASH;
224         while ((idx = hashKeysym[i]))
225           {
226              entry = &_ecore_xcb_keytable[idx];
227              if ((entry[0] == val1) && (entry[1] == val2) &&
228                  (entry[2] == val3) && (entry[3] == val4))
229                return (char *)entry + 4;
230              if (!--n) break;
231              i += h;
232              if (i >= VTABLESIZE) i -= VTABLESIZE;
233           }
234      }
235
236    if ((keysym >= 0x01000100) && (keysym <= 0x0110ffff))
237      {
238         xcb_keysym_t val;
239         char *s = NULL;
240         int i = 0;
241
242         val = (keysym & 0xffffff);
243         if (val & 0xff0000)
244           i = 10;
245         else
246           i = 6;
247
248         if (!(s = malloc(i))) return NULL;
249         i--;
250         s[i--] = '\0';
251         for (; i; i--)
252           {
253              val1 = (val & 0xf);
254              val >>= 4;
255              if (val1 < 10)
256                s[i] = '0' + val1;
257              else
258                s[i] = 'A' + val1 - 10;
259           }
260         s[i] = 'U';
261         return s;
262      }
263
264    return NULL;
265 }
266
267 xcb_keycode_t
268 _ecore_xcb_keymap_string_to_keycode(const char *key)
269 {
270    if (!strncmp(key, "Keycode-", 8))
271      return atoi(key + 8);
272    else
273      {
274         xcb_keysym_t keysym = XCB_NO_SYMBOL;
275         xcb_keycode_t *keycodes, keycode = 0;
276         int i = 0;
277
278         CHECK_XCB_CONN;
279
280         keysym = _ecore_xcb_keymap_string_to_keysym(key);
281         if (keysym == XCB_NO_SYMBOL) return XCB_NO_SYMBOL;
282
283         keycodes = _ecore_xcb_keymap_keysym_to_keycode(keysym);
284         if (!keycodes) return XCB_NO_SYMBOL;
285
286         while (keycodes[i] != XCB_NO_SYMBOL)
287           {
288              if (keycodes[i] != 0)
289                {
290                   keycode = keycodes[i];
291                   break;
292                }
293              i++;
294           }
295         return keycode;
296      }
297 }
298
299 int
300 _ecore_xcb_keymap_lookup_string(xcb_keycode_t keycode,
301                                 int           state,
302                                 char         *buffer,
303                                 int           bytes,
304                                 xcb_keysym_t *sym)
305 {
306    unsigned int modifiers = 0;
307    xcb_keysym_t keysym;
308
309    CHECK_XCB_CONN;
310    if (!_ecore_xcb_keymap_translate_key(keycode, state, &modifiers, &keysym))
311      return 0;
312
313    if (sym) *sym = keysym;
314
315    return _ecore_xcb_keymap_translate_keysym(keysym, state, buffer, bytes);
316 }
317
318 EAPI const char *
319 ecore_x_keysym_string_get(int keysym)
320 {
321    LOGFN(__FILE__, __LINE__, __FUNCTION__);
322
323    return _ecore_xcb_keymap_keysym_to_string(keysym);
324 }
325
326 EAPI int 
327 ecore_x_keysym_keycode_get(const char *keyname)
328 {
329    LOGFN(__FILE__, __LINE__, __FUNCTION__);
330
331    return _ecore_xcb_keymap_string_to_keycode(keyname);
332 }
333
334 EAPI unsigned int
335 ecore_x_keysym_get(const char *string)
336 {
337    return _ecore_xcb_keymap_string_to_keysym(string);
338 }
339
340 /* local functions */
341 static int
342 _ecore_xcb_keymap_mask_get(void        *reply,
343                            xcb_keysym_t sym)
344 {
345    xcb_get_modifier_mapping_reply_t *rep;
346    xcb_keysym_t sym2;
347    int mask = 0;
348    const int masks[8] =
349    {
350       XCB_MOD_MASK_SHIFT, XCB_MOD_MASK_LOCK, XCB_MOD_MASK_CONTROL,
351       XCB_MOD_MASK_1, XCB_MOD_MASK_2, XCB_MOD_MASK_3, XCB_MOD_MASK_4,
352       XCB_MOD_MASK_5
353    };
354
355    LOGFN(__FILE__, __LINE__, __FUNCTION__);
356    CHECK_XCB_CONN;
357
358    rep = (xcb_get_modifier_mapping_reply_t *)reply;
359    if ((rep) && (rep->keycodes_per_modifier > 0))
360      {
361         int i = 0;
362         xcb_keycode_t *modmap;
363
364         modmap = xcb_get_modifier_mapping_keycodes(rep);
365         for (i = 0; i < (8 * rep->keycodes_per_modifier); i++)
366           {
367              int j = 0;
368
369              for (j = 0; j < 8; j++)
370                {
371                   sym2 = xcb_key_symbols_get_keysym(_ecore_xcb_keysyms,
372                                                     modmap[i], j);
373                   if (sym2 != 0) break;
374                }
375              if (sym2 == sym) mask = masks[i / rep->keycodes_per_modifier];
376           }
377      }
378    return mask;
379 }
380
381 static xcb_keysym_t
382 _ecore_xcb_keymap_string_to_keysym(const char *str)
383 {
384    int i = 0, n = 0, h = 0;
385    unsigned long sig = 0;
386    const char *p = NULL;
387    int c = 0, idx = 0;
388    const unsigned char *entry;
389    unsigned char sig1, sig2;
390    long unsigned int val;
391
392    p = str;
393    while ((c = *p++))
394      sig = (sig << 1) + c;
395
396    i = (sig % KTABLESIZE);
397    h = i + 1;
398    sig1 = (sig >> 8) & 0xff;
399    sig2 = sig & 0xff;
400    n = KMAXHASH;
401
402    while ((idx = hashString[i]))
403      {
404         entry = &_ecore_xcb_keytable[idx];
405         if ((entry[0] == sig1) && (entry[1] == sig2) &&
406             !strcmp(str, (char *)entry + 6))
407           {
408              val = ((entry[2] << 24) | (entry[3] << 16) |
409                     (entry[4] << 8) | (entry[5]));
410              if (!val) val = 0xffffff;
411              return val;
412           }
413         if (!--n) break;
414         i += h;
415         if (i >= KTABLESIZE) i -= KTABLESIZE;
416      }
417
418    if (*str == 'U')
419      {
420         val = 0;
421         for (p = &str[1]; *p; p++)
422           {
423              c = *p;
424              if (('0' <= c) && (c <= '9'))
425                val = (val << 4) + c - '0';
426              else if (('a' <= c) && (c <= 'f'))
427                val = (val << 4) + c - 'a' + 10;
428              else if (('A' <= c) && (c <= 'F'))
429                val = (val << 4) + c - 'A' + 10;
430              else
431                return XCB_NO_SYMBOL;
432              if (val > 0x10ffff) return XCB_NO_SYMBOL;
433           }
434         if ((val < 0x20) || ((val > 0x7e) && (val < 0xa0)))
435           return XCB_NO_SYMBOL;
436         if (val < 0x100) return val;
437         return val | 0x01000000;
438      }
439
440    if ((strlen(str) > 2) && (str[0] == '0') && (str[1] == 'x'))
441      {
442         char *tmp = NULL;
443
444         val = strtoul(str, &tmp, 16);
445         if ((val == ULONG_MAX) || ((tmp) && (*tmp != '\0')))
446           return XCB_NO_SYMBOL;
447         else
448           return val;
449      }
450
451    if (!strncmp(str, "XF86_", 5))
452      {
453         long unsigned int ret;
454         char *tmp;
455
456         tmp = strdup(str);
457         if (!tmp) return XCB_NO_SYMBOL;
458         memmove(&tmp[4], &tmp[5], strlen(str) - 5 + 1);
459         ret = _ecore_xcb_keymap_string_to_keysym(tmp);
460         free(tmp);
461         return ret;
462      }
463
464    return XCB_NO_SYMBOL;
465 }
466
467 static int
468 _ecore_xcb_keymap_translate_key(xcb_keycode_t keycode,
469                                 unsigned int  modifiers,
470                                 unsigned int *modifiers_return,
471                                 xcb_keysym_t *keysym_return)
472 {
473    xcb_keysym_t sym;
474
475    if (!_ecore_xcb_keysyms) return 0;
476
477    sym = _ecore_xcb_keymap_keycode_to_keysym(keycode, modifiers);
478
479    if (modifiers_return)
480      *modifiers_return = ((XCB_MOD_MASK_SHIFT | XCB_MOD_MASK_LOCK) |
481                           _ecore_xcb_mode_switch | ECORE_X_LOCK_NUM);
482    if (keysym_return)
483      *keysym_return = sym;
484
485    return 1;
486 }
487
488 static int
489 _ecore_xcb_keymap_translate_keysym(xcb_keysym_t keysym,
490                                    unsigned int modifiers,
491                                    char        *buffer,
492                                    int          bytes)
493 {
494    unsigned long hbytes = 0;
495    unsigned char c;
496
497    if (!keysym) return 0;
498    hbytes = (keysym >> 8);
499
500    if (!(bytes &&
501          ((hbytes == 0) ||
502           ((hbytes == 0xFF) &&
503            (((keysym >= XK_BackSpace) && (keysym <= XK_Clear)) ||
504             (keysym == XK_Return) || (keysym == XK_Escape) ||
505             (keysym == XK_KP_Space) || (keysym == XK_KP_Tab) ||
506             (keysym == XK_KP_Enter) ||
507             ((keysym >= XK_KP_Multiply) && (keysym <= XK_KP_9)) ||
508             (keysym == XK_KP_Equal) || (keysym == XK_Delete))))))
509      return 0;
510
511    if (keysym == XK_KP_Space)
512      c = (XK_space & 0x7F);
513    else if (hbytes == 0xFF)
514      c = (keysym & 0x7F);
515    else
516      c = (keysym & 0xFF);
517
518    if (modifiers & ECORE_X_MODIFIER_CTRL)
519      {
520         if (((c >= '@') && (c < '\177')) || c == ' ')
521           c &= 0x1F;
522         else if (c == '2')
523           c = '\000';
524         else if ((c >= '3') && (c <= '7'))
525           c -= ('3' - '\033');
526         else if (c == '8')
527           c = '\177';
528         else if (c == '/')
529           c = '_' & 0x1F;
530      }
531    buffer[0] = c;
532    return 1;
533 }
534