1 | /* GDK - The GIMP Drawing Kit |
2 | * Copyright (C) 2000 Red Hat, Inc. |
3 | * |
4 | * This library is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU Lesser General Public |
6 | * License as published by the Free Software Foundation; either |
7 | * version 2 of the License, or (at your option) any later version. |
8 | * |
9 | * This library is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * Lesser General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU Lesser General Public |
15 | * License along with this library. If not, see <http://www.gnu.org/licenses/>. |
16 | */ |
17 | |
18 | /* |
19 | * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS |
20 | * file for a list of people on the GTK+ Team. See the ChangeLog |
21 | * files for a list of changes. These files are distributed with |
22 | * GTK+ at ftp://ftp.gtk.org/pub/gtk/. |
23 | */ |
24 | |
25 | #include "config.h" |
26 | |
27 | #include "gdkkeys-x11.h" |
28 | |
29 | #include "gdkkeysprivate.h" |
30 | #include "gdkkeysyms.h" |
31 | #include "gdkprivate-x11.h" |
32 | #include "gdkdisplay-x11.h" |
33 | #include "gdk-private.h" |
34 | |
35 | #include <stdio.h> |
36 | #include <stdlib.h> |
37 | #include <string.h> |
38 | #include <unistd.h> |
39 | #include <limits.h> |
40 | #include <errno.h> |
41 | |
42 | #ifdef HAVE_XKB |
43 | #include <X11/XKBlib.h> |
44 | |
45 | /* OSF-4.0 is apparently missing this macro |
46 | */ |
47 | # ifndef XkbKeySymEntry |
48 | # define XkbKeySymEntry(d,k,sl,g) \ |
49 | (XkbKeySym(d,k,((XkbKeyGroupsWidth(d,k)*(g))+(sl)))) |
50 | # endif |
51 | #endif /* HAVE_XKB */ |
52 | |
53 | typedef struct _DirectionCacheEntry DirectionCacheEntry; |
54 | |
55 | struct _DirectionCacheEntry |
56 | { |
57 | guint serial; |
58 | PangoDirection direction; |
59 | Atom group_atom; |
60 | }; |
61 | |
62 | struct _GdkX11Keymap |
63 | { |
64 | GdkKeymap parent_instance; |
65 | |
66 | int min_keycode; |
67 | int max_keycode; |
68 | KeySym* keymap; |
69 | int keysyms_per_keycode; |
70 | XModifierKeymap* mod_keymap; |
71 | guint lock_keysym; |
72 | GdkModifierType group_switch_mask; |
73 | GdkModifierType num_lock_mask; |
74 | GdkModifierType scroll_lock_mask; |
75 | GdkModifierType modmap[8]; |
76 | PangoDirection current_direction; |
77 | guint have_direction : 1; |
78 | guint have_lock_state : 1; |
79 | guint caps_lock_state : 1; |
80 | guint num_lock_state : 1; |
81 | guint scroll_lock_state : 1; |
82 | guint modifier_state; |
83 | guint current_serial; |
84 | |
85 | #ifdef HAVE_XKB |
86 | XkbDescPtr xkb_desc; |
87 | /* We cache the directions */ |
88 | Atom current_group_atom; |
89 | guint current_cache_serial; |
90 | /* A cache of size four should be more than enough, people usually |
91 | * have two groups around, and the xkb limit is four. It still |
92 | * works correct for more than four groups. It's just the |
93 | * cache. |
94 | */ |
95 | DirectionCacheEntry group_direction_cache[4]; |
96 | #endif |
97 | }; |
98 | |
99 | struct _GdkX11KeymapClass |
100 | { |
101 | GdkKeymapClass parent_class; |
102 | }; |
103 | |
104 | #define KEYMAP_USE_XKB(keymap) GDK_X11_DISPLAY ((keymap)->display)->use_xkb |
105 | #define KEYMAP_XDISPLAY(keymap) GDK_DISPLAY_XDISPLAY ((keymap)->display) |
106 | |
107 | G_DEFINE_TYPE (GdkX11Keymap, gdk_x11_keymap, GDK_TYPE_KEYMAP) |
108 | |
109 | static void |
110 | gdk_x11_keymap_init (GdkX11Keymap *keymap) |
111 | { |
112 | keymap->min_keycode = 0; |
113 | keymap->max_keycode = 0; |
114 | |
115 | keymap->keymap = NULL; |
116 | keymap->keysyms_per_keycode = 0; |
117 | keymap->mod_keymap = NULL; |
118 | |
119 | keymap->num_lock_mask = 0; |
120 | keymap->scroll_lock_mask = 0; |
121 | keymap->group_switch_mask = 0; |
122 | keymap->lock_keysym = GDK_KEY_Caps_Lock; |
123 | keymap->have_direction = FALSE; |
124 | keymap->have_lock_state = FALSE; |
125 | keymap->current_serial = 0; |
126 | |
127 | #ifdef HAVE_XKB |
128 | keymap->xkb_desc = NULL; |
129 | keymap->current_group_atom = 0; |
130 | keymap->current_cache_serial = 0; |
131 | #endif |
132 | |
133 | } |
134 | |
135 | static void |
136 | gdk_x11_keymap_finalize (GObject *object) |
137 | { |
138 | GdkX11Keymap *keymap_x11 = GDK_X11_KEYMAP (object); |
139 | |
140 | if (keymap_x11->keymap) |
141 | XFree (keymap_x11->keymap); |
142 | |
143 | if (keymap_x11->mod_keymap) |
144 | XFreeModifiermap (keymap_x11->mod_keymap); |
145 | |
146 | #ifdef HAVE_XKB |
147 | if (keymap_x11->xkb_desc) |
148 | XkbFreeKeyboard (keymap_x11->xkb_desc, XkbAllComponentsMask, True); |
149 | #endif |
150 | |
151 | G_OBJECT_CLASS (gdk_x11_keymap_parent_class)->finalize (object); |
152 | } |
153 | |
154 | static inline void |
155 | update_keyrange (GdkX11Keymap *keymap_x11) |
156 | { |
157 | if (keymap_x11->max_keycode == 0) |
158 | XDisplayKeycodes (KEYMAP_XDISPLAY (GDK_KEYMAP (keymap_x11)), |
159 | &keymap_x11->min_keycode, &keymap_x11->max_keycode); |
160 | } |
161 | |
162 | #ifdef HAVE_XKB |
163 | |
164 | static void |
165 | update_modmap (Display *display, |
166 | GdkX11Keymap *keymap_x11) |
167 | { |
168 | static struct { |
169 | const char *name; |
170 | Atom atom; |
171 | GdkModifierType mask; |
172 | } vmods[] = { |
173 | { "Meta" , 0, GDK_META_MASK }, |
174 | { "Super" , 0, GDK_SUPER_MASK }, |
175 | { "Hyper" , 0, GDK_HYPER_MASK }, |
176 | { NULL, 0, 0 } |
177 | }; |
178 | |
179 | int i, j, k; |
180 | |
181 | if (!vmods[0].atom) |
182 | for (i = 0; vmods[i].name; i++) |
183 | vmods[i].atom = XInternAtom (display, vmods[i].name, FALSE); |
184 | |
185 | for (i = 0; i < 8; i++) |
186 | keymap_x11->modmap[i] = 1 << i; |
187 | |
188 | for (i = 0; i < XkbNumVirtualMods; i++) |
189 | { |
190 | for (j = 0; vmods[j].atom; j++) |
191 | { |
192 | if (keymap_x11->xkb_desc->names->vmods[i] == vmods[j].atom) |
193 | { |
194 | for (k = 0; k < 8; k++) |
195 | { |
196 | if (keymap_x11->xkb_desc->server->vmods[i] & (1 << k)) |
197 | keymap_x11->modmap[k] |= vmods[j].mask; |
198 | } |
199 | } |
200 | } |
201 | } |
202 | } |
203 | |
204 | static XkbDescPtr |
205 | get_xkb (GdkX11Keymap *keymap_x11) |
206 | { |
207 | GdkX11Display *display_x11 = GDK_X11_DISPLAY (GDK_KEYMAP (keymap_x11)->display); |
208 | Display *xdisplay = display_x11->xdisplay; |
209 | |
210 | update_keyrange (keymap_x11); |
211 | |
212 | if (keymap_x11->xkb_desc == NULL) |
213 | { |
214 | keymap_x11->xkb_desc = XkbGetMap (xdisplay, XkbKeySymsMask | XkbKeyTypesMask | XkbModifierMapMask | XkbVirtualModsMask, XkbUseCoreKbd); |
215 | if (keymap_x11->xkb_desc == NULL) |
216 | { |
217 | g_error ("Failed to get keymap" ); |
218 | return NULL; |
219 | } |
220 | |
221 | XkbGetNames (xdisplay, XkbGroupNamesMask | XkbVirtualModNamesMask, keymap_x11->xkb_desc); |
222 | |
223 | update_modmap (display: xdisplay, keymap_x11); |
224 | } |
225 | else if (keymap_x11->current_serial != display_x11->keymap_serial) |
226 | { |
227 | XkbGetUpdatedMap (xdisplay, XkbKeySymsMask | XkbKeyTypesMask | XkbModifierMapMask | XkbVirtualModsMask, |
228 | keymap_x11->xkb_desc); |
229 | XkbGetNames (xdisplay, XkbGroupNamesMask | XkbVirtualModNamesMask, keymap_x11->xkb_desc); |
230 | |
231 | update_modmap (display: xdisplay, keymap_x11); |
232 | } |
233 | |
234 | keymap_x11->current_serial = display_x11->keymap_serial; |
235 | |
236 | if (keymap_x11->num_lock_mask == 0) |
237 | keymap_x11->num_lock_mask = XkbKeysymToModifiers (KEYMAP_XDISPLAY (GDK_KEYMAP (keymap_x11)), GDK_KEY_Num_Lock); |
238 | |
239 | if (keymap_x11->scroll_lock_mask == 0) |
240 | keymap_x11->scroll_lock_mask = XkbKeysymToModifiers (KEYMAP_XDISPLAY (GDK_KEYMAP (keymap_x11)), GDK_KEY_Scroll_Lock); |
241 | |
242 | |
243 | return keymap_x11->xkb_desc; |
244 | } |
245 | #endif /* HAVE_XKB */ |
246 | |
247 | /* Whether we were able to turn on detectable-autorepeat using |
248 | * XkbSetDetectableAutorepeat. If FALSE, we’ll fall back |
249 | * to checking the next event with XPending(). |
250 | */ |
251 | |
252 | /* Find the index of the group/level pair within the keysyms for a key. |
253 | * We round up the number of keysyms per keycode to the next even number, |
254 | * otherwise we lose a whole group of keys |
255 | */ |
256 | #define KEYSYM_INDEX(keymap_impl, group, level) \ |
257 | (2 * ((group) % (int)((keymap_impl->keysyms_per_keycode + 1) / 2)) + (level)) |
258 | #define KEYSYM_IS_KEYPAD(s) (((s) >= 0xff80 && (s) <= 0xffbd) || \ |
259 | ((s) >= 0x11000000 && (s) <= 0x1100ffff)) |
260 | |
261 | static int |
262 | get_symbol (const KeySym *syms, |
263 | GdkX11Keymap *keymap_x11, |
264 | int group, |
265 | int level) |
266 | { |
267 | int index; |
268 | |
269 | index = KEYSYM_INDEX(keymap_x11, group, level); |
270 | if (index >= keymap_x11->keysyms_per_keycode) |
271 | return NoSymbol; |
272 | |
273 | return syms[index]; |
274 | } |
275 | |
276 | static void |
277 | set_symbol (KeySym *syms, |
278 | GdkX11Keymap *keymap_x11, |
279 | int group, |
280 | int level, |
281 | KeySym sym) |
282 | { |
283 | int index; |
284 | |
285 | index = KEYSYM_INDEX(keymap_x11, group, level); |
286 | if (index >= keymap_x11->keysyms_per_keycode) |
287 | return; |
288 | |
289 | syms[index] = sym; |
290 | } |
291 | |
292 | static void |
293 | update_keymaps (GdkX11Keymap *keymap_x11) |
294 | { |
295 | GdkX11Display *display_x11 = GDK_X11_DISPLAY (GDK_KEYMAP (keymap_x11)->display); |
296 | Display *xdisplay = display_x11->xdisplay; |
297 | |
298 | #ifdef HAVE_XKB |
299 | g_assert (!KEYMAP_USE_XKB (GDK_KEYMAP (keymap_x11))); |
300 | #endif |
301 | |
302 | if (keymap_x11->keymap == NULL || |
303 | keymap_x11->current_serial != display_x11->keymap_serial) |
304 | { |
305 | int i; |
306 | int map_size; |
307 | int keycode; |
308 | |
309 | keymap_x11->current_serial = display_x11->keymap_serial; |
310 | |
311 | update_keyrange (keymap_x11); |
312 | |
313 | if (keymap_x11->keymap) |
314 | XFree (keymap_x11->keymap); |
315 | |
316 | if (keymap_x11->mod_keymap) |
317 | XFreeModifiermap (keymap_x11->mod_keymap); |
318 | |
319 | keymap_x11->keymap = XGetKeyboardMapping (xdisplay, keymap_x11->min_keycode, |
320 | keymap_x11->max_keycode - keymap_x11->min_keycode + 1, |
321 | &keymap_x11->keysyms_per_keycode); |
322 | |
323 | |
324 | /* GDK_KEY_ISO_Left_Tab, as usually configured through XKB, really messes |
325 | * up the whole idea of "consumed modifiers" because shift is consumed. |
326 | * However, <shift>Tab is not usually GDK_KEY_ISO_Left_Tab without XKB, |
327 | * we fudge the map here. |
328 | */ |
329 | keycode = keymap_x11->min_keycode; |
330 | while (keycode <= keymap_x11->max_keycode) |
331 | { |
332 | KeySym *syms = keymap_x11->keymap + (keycode - keymap_x11->min_keycode) * keymap_x11->keysyms_per_keycode; |
333 | /* Check both groups */ |
334 | for (i = 0 ; i < 2 ; i++) |
335 | { |
336 | if (get_symbol (syms, keymap_x11, group: i, level: 0) == GDK_KEY_Tab) |
337 | set_symbol (syms, keymap_x11, group: i, level: 1, GDK_KEY_ISO_Left_Tab); |
338 | } |
339 | |
340 | /* |
341 | * If there is one keysym and the key symbol has upper and lower |
342 | * case variants fudge the keymap |
343 | */ |
344 | if (get_symbol (syms, keymap_x11, group: 0, level: 1) == 0) |
345 | { |
346 | guint lower; |
347 | guint upper; |
348 | |
349 | gdk_keyval_convert_case (symbol: get_symbol (syms, keymap_x11, group: 0, level: 0), lower: &lower, upper: &upper); |
350 | if (lower != upper) |
351 | { |
352 | set_symbol (syms, keymap_x11, group: 0, level: 0, sym: lower); |
353 | set_symbol (syms, keymap_x11, group: 0, level: 1, sym: upper); |
354 | } |
355 | } |
356 | |
357 | ++keycode; |
358 | } |
359 | |
360 | keymap_x11->mod_keymap = XGetModifierMapping (xdisplay); |
361 | |
362 | keymap_x11->lock_keysym = GDK_KEY_VoidSymbol; |
363 | keymap_x11->group_switch_mask = 0; |
364 | keymap_x11->num_lock_mask = 0; |
365 | keymap_x11->scroll_lock_mask = 0; |
366 | |
367 | for (i = 0; i < 8; i++) |
368 | keymap_x11->modmap[i] = 1 << i; |
369 | |
370 | /* There are 8 sets of modifiers, with each set containing |
371 | * max_keypermod keycodes. |
372 | */ |
373 | map_size = 8 * keymap_x11->mod_keymap->max_keypermod; |
374 | for (i = 0; i < map_size; i++) |
375 | { |
376 | /* Get the key code at this point in the map. */ |
377 | int code = keymap_x11->mod_keymap->modifiermap[i]; |
378 | int j; |
379 | KeySym *syms; |
380 | guint mask; |
381 | |
382 | /* Ignore invalid keycodes. */ |
383 | if (code < keymap_x11->min_keycode || |
384 | code > keymap_x11->max_keycode) |
385 | continue; |
386 | |
387 | syms = keymap_x11->keymap + (code - keymap_x11->min_keycode) * keymap_x11->keysyms_per_keycode; |
388 | |
389 | mask = 0; |
390 | for (j = 0; j < keymap_x11->keysyms_per_keycode; j++) |
391 | { |
392 | if (syms[j] == GDK_KEY_Meta_L || |
393 | syms[j] == GDK_KEY_Meta_R) |
394 | mask |= GDK_META_MASK; |
395 | else if (syms[j] == GDK_KEY_Hyper_L || |
396 | syms[j] == GDK_KEY_Hyper_R) |
397 | mask |= GDK_HYPER_MASK; |
398 | else if (syms[j] == GDK_KEY_Super_L || |
399 | syms[j] == GDK_KEY_Super_R) |
400 | mask |= GDK_SUPER_MASK; |
401 | } |
402 | |
403 | keymap_x11->modmap[i / keymap_x11->mod_keymap->max_keypermod] |= mask; |
404 | |
405 | /* The fourth modifier, GDK_ALT_MASK is 1 << 3. |
406 | * Each group of max_keypermod entries refers to the same modifier. |
407 | */ |
408 | mask = 1 << (i / keymap_x11->mod_keymap->max_keypermod); |
409 | |
410 | switch (mask) |
411 | { |
412 | case GDK_LOCK_MASK: |
413 | /* Get the Lock keysym. If any keysym bound to the Lock modifier |
414 | * is Caps_Lock, we will interpret the modifier as Caps_Lock; |
415 | * otherwise, if any is bound to Shift_Lock, we will interpret |
416 | * the modifier as Shift_Lock. Otherwise, the lock modifier |
417 | * has no effect. |
418 | */ |
419 | for (j = 0; j < keymap_x11->keysyms_per_keycode; j++) |
420 | { |
421 | if (syms[j] == GDK_KEY_Caps_Lock) |
422 | keymap_x11->lock_keysym = GDK_KEY_Caps_Lock; |
423 | else if (syms[j] == GDK_KEY_Shift_Lock && |
424 | keymap_x11->lock_keysym == GDK_KEY_VoidSymbol) |
425 | keymap_x11->lock_keysym = GDK_KEY_Shift_Lock; |
426 | } |
427 | break; |
428 | |
429 | case GDK_CONTROL_MASK: |
430 | case GDK_SHIFT_MASK: |
431 | case GDK_ALT_MASK: |
432 | /* Some keyboard maps are known to map Mode_Switch as an |
433 | * extra Mod1 key. In circumstances like that, it won't be |
434 | * used to switch groups. |
435 | */ |
436 | break; |
437 | |
438 | default: |
439 | /* Find the Mode_Switch, Num_Lock and Scroll_Lock modifiers. */ |
440 | for (j = 0; j < keymap_x11->keysyms_per_keycode; j++) |
441 | { |
442 | if (syms[j] == GDK_KEY_Mode_switch) |
443 | { |
444 | /* This modifier swaps groups */ |
445 | keymap_x11->group_switch_mask |= mask; |
446 | } |
447 | else if (syms[j] == GDK_KEY_Num_Lock) |
448 | { |
449 | /* This modifier is used for Num_Lock */ |
450 | keymap_x11->num_lock_mask |= mask; |
451 | } |
452 | else if (syms[j] == GDK_KEY_Scroll_Lock) |
453 | { |
454 | /* This modifier is used for Scroll_Lock */ |
455 | keymap_x11->scroll_lock_mask |= mask; |
456 | } |
457 | } |
458 | break; |
459 | } |
460 | } |
461 | } |
462 | } |
463 | |
464 | static const KeySym* |
465 | get_keymap (GdkX11Keymap *keymap_x11) |
466 | { |
467 | update_keymaps (keymap_x11); |
468 | |
469 | return keymap_x11->keymap; |
470 | } |
471 | |
472 | #ifdef HAVE_XKB |
473 | static PangoDirection |
474 | get_direction (XkbDescRec *xkb, |
475 | int group) |
476 | { |
477 | int code; |
478 | |
479 | int rtl_minus_ltr = 0; /* total number of RTL keysyms minus LTR ones */ |
480 | |
481 | for (code = xkb->min_key_code; code <= xkb->max_key_code; code++) |
482 | { |
483 | int level = 0; |
484 | KeySym sym = XkbKeySymEntry (xkb, code, level, group); |
485 | PangoDirection dir = gdk_unichar_direction (ch: gdk_keyval_to_unicode (keyval: sym)); |
486 | |
487 | switch (dir) |
488 | { |
489 | case PANGO_DIRECTION_RTL: |
490 | rtl_minus_ltr++; |
491 | break; |
492 | case PANGO_DIRECTION_LTR: |
493 | rtl_minus_ltr--; |
494 | break; |
495 | case PANGO_DIRECTION_TTB_LTR: |
496 | case PANGO_DIRECTION_TTB_RTL: |
497 | case PANGO_DIRECTION_WEAK_LTR: |
498 | case PANGO_DIRECTION_WEAK_RTL: |
499 | case PANGO_DIRECTION_NEUTRAL: |
500 | default: |
501 | break; |
502 | } |
503 | } |
504 | |
505 | if (rtl_minus_ltr > 0) |
506 | return PANGO_DIRECTION_RTL; |
507 | else |
508 | return PANGO_DIRECTION_LTR; |
509 | } |
510 | |
511 | static PangoDirection |
512 | get_direction_from_cache (GdkX11Keymap *keymap_x11, |
513 | XkbDescPtr xkb, |
514 | int group) |
515 | { |
516 | Atom group_atom = xkb->names->groups[group]; |
517 | |
518 | gboolean cache_hit = FALSE; |
519 | DirectionCacheEntry *cache = keymap_x11->group_direction_cache; |
520 | |
521 | PangoDirection direction = PANGO_DIRECTION_NEUTRAL; |
522 | int i; |
523 | |
524 | if (keymap_x11->have_direction) |
525 | { |
526 | /* lookup in cache */ |
527 | for (i = 0; i < G_N_ELEMENTS (keymap_x11->group_direction_cache); i++) |
528 | { |
529 | if (cache[i].group_atom == group_atom) |
530 | { |
531 | cache_hit = TRUE; |
532 | cache[i].serial = keymap_x11->current_cache_serial++; /* freshen */ |
533 | direction = cache[i].direction; |
534 | group_atom = cache[i].group_atom; |
535 | break; |
536 | } |
537 | } |
538 | } |
539 | else |
540 | { |
541 | /* initialize cache */ |
542 | for (i = 0; i < G_N_ELEMENTS (keymap_x11->group_direction_cache); i++) |
543 | { |
544 | cache[i].group_atom = 0; |
545 | cache[i].serial = keymap_x11->current_cache_serial; |
546 | } |
547 | keymap_x11->current_cache_serial++; |
548 | } |
549 | |
550 | /* insert in cache */ |
551 | if (!cache_hit) |
552 | { |
553 | int oldest = 0; |
554 | |
555 | direction = get_direction (xkb, group); |
556 | |
557 | /* remove the oldest entry */ |
558 | for (i = 0; i < G_N_ELEMENTS (keymap_x11->group_direction_cache); i++) |
559 | { |
560 | if (cache[i].serial < cache[oldest].serial) |
561 | oldest = i; |
562 | } |
563 | |
564 | cache[oldest].group_atom = group_atom; |
565 | cache[oldest].direction = direction; |
566 | cache[oldest].serial = keymap_x11->current_cache_serial++; |
567 | } |
568 | |
569 | return direction; |
570 | } |
571 | |
572 | static int |
573 | get_num_groups (GdkKeymap *keymap, |
574 | XkbDescPtr xkb) |
575 | { |
576 | Display *display = KEYMAP_XDISPLAY (keymap); |
577 | XkbGetControls(display, XkbSlowKeysMask, xkb); |
578 | XkbGetUpdatedMap (display, XkbKeySymsMask | XkbKeyTypesMask | |
579 | XkbModifierMapMask | XkbVirtualModsMask, xkb); |
580 | return xkb->ctrls->num_groups; |
581 | } |
582 | |
583 | static gboolean |
584 | update_direction (GdkX11Keymap *keymap_x11, |
585 | GdkDevice *keyboard, |
586 | int group) |
587 | { |
588 | XkbDescPtr xkb = get_xkb (keymap_x11); |
589 | Atom group_atom; |
590 | gboolean had_direction; |
591 | PangoDirection old_direction; |
592 | |
593 | had_direction = keymap_x11->have_direction; |
594 | old_direction = keymap_x11->current_direction; |
595 | |
596 | group_atom = xkb->names->groups[group]; |
597 | |
598 | /* a group change? */ |
599 | if (!keymap_x11->have_direction || keymap_x11->current_group_atom != group_atom) |
600 | { |
601 | keymap_x11->current_direction = get_direction_from_cache (keymap_x11, xkb, group); |
602 | keymap_x11->current_group_atom = group_atom; |
603 | keymap_x11->have_direction = TRUE; |
604 | } |
605 | |
606 | if (had_direction && old_direction != keymap_x11->current_direction) |
607 | { |
608 | g_object_notify (G_OBJECT (keyboard), property_name: "direction" ); |
609 | return TRUE; |
610 | } |
611 | |
612 | return FALSE; |
613 | } |
614 | |
615 | static gboolean |
616 | update_lock_state (GdkX11Keymap *keymap_x11, |
617 | GdkDevice *keyboard, |
618 | int locked_mods, |
619 | int effective_mods) |
620 | { |
621 | XkbDescPtr xkb G_GNUC_UNUSED; |
622 | gboolean have_lock_state; |
623 | gboolean caps_lock_state; |
624 | gboolean num_lock_state; |
625 | gboolean scroll_lock_state; |
626 | guint modifier_state; |
627 | |
628 | /* ensure keymap_x11->num_lock_mask is initialized */ |
629 | xkb = get_xkb (keymap_x11); |
630 | |
631 | have_lock_state = keymap_x11->have_lock_state; |
632 | caps_lock_state = keymap_x11->caps_lock_state; |
633 | num_lock_state = keymap_x11->num_lock_state; |
634 | scroll_lock_state = keymap_x11->scroll_lock_state; |
635 | modifier_state = keymap_x11->modifier_state; |
636 | |
637 | keymap_x11->have_lock_state = TRUE; |
638 | keymap_x11->caps_lock_state = (locked_mods & GDK_LOCK_MASK) != 0; |
639 | keymap_x11->num_lock_state = (locked_mods & keymap_x11->num_lock_mask) != 0; |
640 | keymap_x11->scroll_lock_state = (locked_mods & keymap_x11->scroll_lock_mask) != 0; |
641 | /* FIXME: sanitize this */ |
642 | keymap_x11->modifier_state = (guint)effective_mods; |
643 | |
644 | if (caps_lock_state != keymap_x11->caps_lock_state) |
645 | g_object_notify (G_OBJECT (keyboard), property_name: "caps-lock-state" ); |
646 | if (num_lock_state != keymap_x11->num_lock_state) |
647 | g_object_notify (G_OBJECT (keyboard), property_name: "num-lock-state" ); |
648 | if (scroll_lock_state != keymap_x11->scroll_lock_state) |
649 | g_object_notify (G_OBJECT (keyboard), property_name: "scroll-lock-state" ); |
650 | if (modifier_state != keymap_x11->modifier_state) |
651 | g_object_notify (G_OBJECT (keyboard), property_name: "modifier-state" ); |
652 | |
653 | return !have_lock_state |
654 | || (caps_lock_state != keymap_x11->caps_lock_state) |
655 | || (num_lock_state != keymap_x11->num_lock_state) |
656 | || (scroll_lock_state != keymap_x11->scroll_lock_state) |
657 | || (modifier_state != keymap_x11->modifier_state); |
658 | } |
659 | |
660 | /* keep this in sync with the XkbSelectEventDetails() |
661 | * call in gdk_display_open() |
662 | */ |
663 | void |
664 | _gdk_x11_keymap_state_changed (GdkDisplay *display, |
665 | const XEvent *xevent) |
666 | { |
667 | GdkX11Display *display_x11 = GDK_X11_DISPLAY (display); |
668 | const XkbEvent *xkb_event = (const XkbEvent *) xevent; |
669 | |
670 | if (display_x11->keymap) |
671 | { |
672 | GdkX11Keymap *keymap_x11 = GDK_X11_KEYMAP (display_x11->keymap); |
673 | GdkDevice *keyboard; |
674 | |
675 | keyboard = gdk_seat_get_keyboard (seat: gdk_display_get_default_seat (display)); |
676 | |
677 | if (update_direction (keymap_x11, keyboard, XkbStateGroup (&xkb_event->state))) |
678 | g_signal_emit_by_name (instance: keymap_x11, detailed_signal: "direction-changed" ); |
679 | |
680 | if (update_lock_state (keymap_x11, |
681 | keyboard, |
682 | locked_mods: xkb_event->state.locked_mods, |
683 | effective_mods: xkb_event->state.mods)) |
684 | g_signal_emit_by_name (instance: keymap_x11, detailed_signal: "state-changed" ); |
685 | } |
686 | } |
687 | |
688 | #endif /* HAVE_XKB */ |
689 | |
690 | static void |
691 | ensure_lock_state (GdkKeymap *keymap) |
692 | { |
693 | #ifdef HAVE_XKB |
694 | if (KEYMAP_USE_XKB (keymap)) |
695 | { |
696 | GdkX11Keymap *keymap_x11 = GDK_X11_KEYMAP (keymap); |
697 | GdkDevice *keyboard; |
698 | |
699 | keyboard = gdk_seat_get_keyboard (seat: gdk_display_get_default_seat (display: keymap->display)); |
700 | |
701 | if (!keymap_x11->have_lock_state) |
702 | { |
703 | GdkDisplay *display = keymap->display; |
704 | XkbStateRec state_rec; |
705 | |
706 | XkbGetState (GDK_DISPLAY_XDISPLAY (display), XkbUseCoreKbd, &state_rec); |
707 | update_lock_state (keymap_x11, keyboard, locked_mods: state_rec.locked_mods, effective_mods: state_rec.mods); |
708 | } |
709 | } |
710 | #endif /* HAVE_XKB */ |
711 | } |
712 | |
713 | void |
714 | _gdk_x11_keymap_keys_changed (GdkDisplay *display) |
715 | { |
716 | GdkX11Display *display_x11 = GDK_X11_DISPLAY (display); |
717 | |
718 | ++display_x11->keymap_serial; |
719 | |
720 | if (display_x11->keymap) |
721 | g_signal_emit_by_name (instance: display_x11->keymap, detailed_signal: "keys_changed" , 0); |
722 | } |
723 | |
724 | static PangoDirection |
725 | gdk_x11_keymap_get_direction (GdkKeymap *keymap) |
726 | { |
727 | #ifdef HAVE_XKB |
728 | if (KEYMAP_USE_XKB (keymap)) |
729 | { |
730 | GdkX11Keymap *keymap_x11 = GDK_X11_KEYMAP (keymap); |
731 | |
732 | if (!keymap_x11->have_direction) |
733 | { |
734 | GdkDisplay *display = keymap->display; |
735 | GdkDevice *keyboard; |
736 | XkbStateRec state_rec; |
737 | |
738 | keyboard = gdk_seat_get_keyboard (seat: gdk_display_get_default_seat (display)); |
739 | |
740 | XkbGetState (GDK_DISPLAY_XDISPLAY (display), XkbUseCoreKbd, |
741 | &state_rec); |
742 | update_direction (keymap_x11, keyboard, XkbStateGroup (&state_rec)); |
743 | } |
744 | |
745 | return keymap_x11->current_direction; |
746 | } |
747 | else |
748 | #endif /* HAVE_XKB */ |
749 | return PANGO_DIRECTION_NEUTRAL; |
750 | } |
751 | |
752 | static gboolean |
753 | gdk_x11_keymap_have_bidi_layouts (GdkKeymap *keymap) |
754 | { |
755 | #ifdef HAVE_XKB |
756 | if (KEYMAP_USE_XKB (keymap)) |
757 | { |
758 | GdkX11Keymap *keymap_x11 = GDK_X11_KEYMAP (keymap); |
759 | XkbDescPtr xkb = get_xkb (keymap_x11); |
760 | int num_groups = get_num_groups (keymap, xkb); |
761 | |
762 | int i; |
763 | gboolean have_ltr_keyboard = FALSE; |
764 | gboolean have_rtl_keyboard = FALSE; |
765 | |
766 | for (i = 0; i < num_groups; i++) |
767 | { |
768 | if (get_direction_from_cache (keymap_x11, xkb, group: i) == PANGO_DIRECTION_RTL) |
769 | have_rtl_keyboard = TRUE; |
770 | else |
771 | have_ltr_keyboard = TRUE; |
772 | } |
773 | |
774 | return have_ltr_keyboard && have_rtl_keyboard; |
775 | } |
776 | else |
777 | #endif /* HAVE_XKB */ |
778 | return FALSE; |
779 | } |
780 | |
781 | static gboolean |
782 | gdk_x11_keymap_get_caps_lock_state (GdkKeymap *keymap) |
783 | { |
784 | GdkX11Keymap *keymap_x11 = GDK_X11_KEYMAP (keymap); |
785 | |
786 | ensure_lock_state (keymap); |
787 | |
788 | return keymap_x11->caps_lock_state; |
789 | } |
790 | |
791 | static gboolean |
792 | gdk_x11_keymap_get_num_lock_state (GdkKeymap *keymap) |
793 | { |
794 | GdkX11Keymap *keymap_x11 = GDK_X11_KEYMAP (keymap); |
795 | |
796 | ensure_lock_state (keymap); |
797 | |
798 | return keymap_x11->num_lock_state; |
799 | } |
800 | |
801 | static gboolean |
802 | gdk_x11_keymap_get_scroll_lock_state (GdkKeymap *keymap) |
803 | { |
804 | GdkX11Keymap *keymap_x11 = GDK_X11_KEYMAP (keymap); |
805 | |
806 | ensure_lock_state (keymap); |
807 | |
808 | return keymap_x11->scroll_lock_state; |
809 | } |
810 | |
811 | static guint |
812 | gdk_x11_keymap_get_modifier_state (GdkKeymap *keymap) |
813 | { |
814 | GdkX11Keymap *keymap_x11 = GDK_X11_KEYMAP (keymap); |
815 | |
816 | ensure_lock_state (keymap); |
817 | |
818 | return keymap_x11->modifier_state; |
819 | } |
820 | |
821 | static gboolean |
822 | gdk_x11_keymap_get_entries_for_keyval (GdkKeymap *keymap, |
823 | guint keyval, |
824 | GArray *retval) |
825 | { |
826 | GdkX11Keymap *keymap_x11 = GDK_X11_KEYMAP (keymap); |
827 | guint len = retval->len; |
828 | |
829 | #ifdef HAVE_XKB |
830 | if (KEYMAP_USE_XKB (keymap)) |
831 | { |
832 | /* See sec 15.3.4 in XKB docs */ |
833 | |
834 | XkbDescRec *xkb = get_xkb (keymap_x11); |
835 | int keycode; |
836 | |
837 | keycode = keymap_x11->min_keycode; |
838 | |
839 | while (keycode <= keymap_x11->max_keycode) |
840 | { |
841 | int max_shift_levels = XkbKeyGroupsWidth (xkb, keycode); /* "key width" */ |
842 | int group = 0; |
843 | int level = 0; |
844 | int total_syms = XkbKeyNumSyms (xkb, keycode); |
845 | int i = 0; |
846 | KeySym *entry; |
847 | |
848 | /* entry is an array with all syms for group 0, all |
849 | * syms for group 1, etc. and for each group the |
850 | * shift level syms are in order |
851 | */ |
852 | entry = XkbKeySymsPtr (xkb, keycode); |
853 | |
854 | while (i < total_syms) |
855 | { |
856 | /* check out our cool loop invariant */ |
857 | g_assert (i == (group * max_shift_levels + level)); |
858 | |
859 | if (entry[i] == keyval) |
860 | { |
861 | /* Found a match */ |
862 | GdkKeymapKey key; |
863 | |
864 | key.keycode = keycode; |
865 | key.group = group; |
866 | key.level = level; |
867 | |
868 | g_array_append_val (retval, key); |
869 | |
870 | g_assert (XkbKeySymEntry (xkb, keycode, level, group) == keyval); |
871 | } |
872 | |
873 | ++level; |
874 | |
875 | if (level == max_shift_levels) |
876 | { |
877 | level = 0; |
878 | ++group; |
879 | } |
880 | |
881 | ++i; |
882 | } |
883 | |
884 | ++keycode; |
885 | } |
886 | } |
887 | else |
888 | #endif |
889 | { |
890 | const KeySym *map = get_keymap (keymap_x11); |
891 | int keycode; |
892 | |
893 | keycode = keymap_x11->min_keycode; |
894 | while (keycode <= keymap_x11->max_keycode) |
895 | { |
896 | const KeySym *syms = map + (keycode - keymap_x11->min_keycode) * keymap_x11->keysyms_per_keycode; |
897 | int i = 0; |
898 | |
899 | while (i < keymap_x11->keysyms_per_keycode) |
900 | { |
901 | if (syms[i] == keyval) |
902 | { |
903 | /* found a match */ |
904 | GdkKeymapKey key; |
905 | |
906 | key.keycode = keycode; |
907 | |
908 | /* The "classic" non-XKB keymap has 2 levels per group */ |
909 | key.group = i / 2; |
910 | key.level = i % 2; |
911 | |
912 | g_array_append_val (retval, key); |
913 | } |
914 | |
915 | ++i; |
916 | } |
917 | |
918 | ++keycode; |
919 | } |
920 | } |
921 | |
922 | return retval->len > len; |
923 | } |
924 | |
925 | static gboolean |
926 | gdk_x11_keymap_get_entries_for_keycode (GdkKeymap *keymap, |
927 | guint hardware_keycode, |
928 | GdkKeymapKey **keys, |
929 | guint **keyvals, |
930 | int *n_entries) |
931 | { |
932 | GdkX11Keymap *keymap_x11 = GDK_X11_KEYMAP (keymap); |
933 | GArray *key_array; |
934 | GArray *keyval_array; |
935 | |
936 | update_keyrange (keymap_x11); |
937 | |
938 | if (hardware_keycode < keymap_x11->min_keycode || |
939 | hardware_keycode > keymap_x11->max_keycode) |
940 | { |
941 | if (keys) |
942 | *keys = NULL; |
943 | if (keyvals) |
944 | *keyvals = NULL; |
945 | |
946 | *n_entries = 0; |
947 | return FALSE; |
948 | } |
949 | |
950 | if (keys) |
951 | key_array = g_array_new (FALSE, FALSE, element_size: sizeof (GdkKeymapKey)); |
952 | else |
953 | key_array = NULL; |
954 | |
955 | if (keyvals) |
956 | keyval_array = g_array_new (FALSE, FALSE, element_size: sizeof (guint)); |
957 | else |
958 | keyval_array = NULL; |
959 | |
960 | #ifdef HAVE_XKB |
961 | if (KEYMAP_USE_XKB (keymap)) |
962 | { |
963 | /* See sec 15.3.4 in XKB docs */ |
964 | |
965 | XkbDescRec *xkb = get_xkb (keymap_x11); |
966 | int max_shift_levels; |
967 | int group = 0; |
968 | int level = 0; |
969 | int total_syms; |
970 | int i = 0; |
971 | KeySym *entry; |
972 | |
973 | max_shift_levels = XkbKeyGroupsWidth (xkb, hardware_keycode); /* "key width" */ |
974 | total_syms = XkbKeyNumSyms (xkb, hardware_keycode); |
975 | |
976 | /* entry is an array with all syms for group 0, all |
977 | * syms for group 1, etc. and for each group the |
978 | * shift level syms are in order |
979 | */ |
980 | entry = XkbKeySymsPtr (xkb, hardware_keycode); |
981 | |
982 | while (i < total_syms) |
983 | { |
984 | /* check out our cool loop invariant */ |
985 | g_assert (i == (group * max_shift_levels + level)); |
986 | |
987 | if (key_array) |
988 | { |
989 | GdkKeymapKey key; |
990 | |
991 | key.keycode = hardware_keycode; |
992 | key.group = group; |
993 | key.level = level; |
994 | |
995 | g_array_append_val (key_array, key); |
996 | } |
997 | |
998 | if (keyval_array) |
999 | g_array_append_val (keyval_array, entry[i]); |
1000 | |
1001 | ++level; |
1002 | |
1003 | if (level == max_shift_levels) |
1004 | { |
1005 | level = 0; |
1006 | ++group; |
1007 | } |
1008 | |
1009 | ++i; |
1010 | } |
1011 | } |
1012 | else |
1013 | #endif |
1014 | { |
1015 | const KeySym *map = get_keymap (keymap_x11); |
1016 | const KeySym *syms; |
1017 | int i = 0; |
1018 | |
1019 | syms = map + (hardware_keycode - keymap_x11->min_keycode) * keymap_x11->keysyms_per_keycode; |
1020 | |
1021 | while (i < keymap_x11->keysyms_per_keycode) |
1022 | { |
1023 | if (key_array) |
1024 | { |
1025 | GdkKeymapKey key; |
1026 | |
1027 | key.keycode = hardware_keycode; |
1028 | |
1029 | /* The "classic" non-XKB keymap has 2 levels per group */ |
1030 | key.group = i / 2; |
1031 | key.level = i % 2; |
1032 | |
1033 | g_array_append_val (key_array, key); |
1034 | } |
1035 | |
1036 | if (keyval_array) |
1037 | g_array_append_val (keyval_array, syms[i]); |
1038 | |
1039 | ++i; |
1040 | } |
1041 | } |
1042 | |
1043 | *n_entries = 0; |
1044 | |
1045 | if (keys) |
1046 | { |
1047 | *n_entries = key_array->len; |
1048 | *keys = (GdkKeymapKey*) g_array_free (array: key_array, FALSE); |
1049 | } |
1050 | |
1051 | if (keyvals) |
1052 | { |
1053 | *n_entries = keyval_array->len; |
1054 | *keyvals = (guint*) g_array_free (array: keyval_array, FALSE); |
1055 | } |
1056 | |
1057 | return *n_entries > 0; |
1058 | } |
1059 | |
1060 | static guint |
1061 | gdk_x11_keymap_lookup_key (GdkKeymap *keymap, |
1062 | const GdkKeymapKey *key) |
1063 | { |
1064 | GdkX11Keymap *keymap_x11 = GDK_X11_KEYMAP (keymap); |
1065 | |
1066 | g_return_val_if_fail (key->group < 4, 0); |
1067 | |
1068 | #ifdef HAVE_XKB |
1069 | if (KEYMAP_USE_XKB (keymap)) |
1070 | { |
1071 | XkbDescRec *xkb = get_xkb (keymap_x11); |
1072 | |
1073 | return XkbKeySymEntry (xkb, key->keycode, key->level, key->group); |
1074 | } |
1075 | else |
1076 | #endif |
1077 | { |
1078 | const KeySym *map = get_keymap (keymap_x11); |
1079 | const KeySym *syms = map + (key->keycode - keymap_x11->min_keycode) * keymap_x11->keysyms_per_keycode; |
1080 | return get_symbol (syms, keymap_x11, group: key->group, level: key->level); |
1081 | } |
1082 | } |
1083 | |
1084 | #ifdef HAVE_XKB |
1085 | /* This is copied straight from XFree86 Xlib, to: |
1086 | * - add the group and level return. |
1087 | * - change the interpretation of mods_rtrn as described |
1088 | * in the docs for gdk_keymap_translate_keyboard_state() |
1089 | * It’s unchanged for ease of diff against the Xlib sources; don't |
1090 | * reformat it. |
1091 | */ |
1092 | static Bool |
1093 | MyEnhancedXkbTranslateKeyCode(register XkbDescPtr xkb, |
1094 | KeyCode key, |
1095 | register unsigned int mods, |
1096 | unsigned int * mods_rtrn, |
1097 | KeySym * keysym_rtrn, |
1098 | int * group_rtrn, |
1099 | int * level_rtrn) |
1100 | { |
1101 | XkbKeyTypeRec *type; |
1102 | int col,nKeyGroups; |
1103 | unsigned preserve,effectiveGroup; |
1104 | KeySym *syms; |
1105 | int found_col = 0; |
1106 | |
1107 | if (mods_rtrn!=NULL) |
1108 | *mods_rtrn = 0; |
1109 | |
1110 | nKeyGroups= XkbKeyNumGroups(xkb,key); |
1111 | if ((!XkbKeycodeInRange(xkb,key))||(nKeyGroups==0)) { |
1112 | if (keysym_rtrn!=NULL) |
1113 | *keysym_rtrn = NoSymbol; |
1114 | return False; |
1115 | } |
1116 | |
1117 | syms = XkbKeySymsPtr(xkb,key); |
1118 | |
1119 | /* find the offset of the effective group */ |
1120 | col = 0; |
1121 | effectiveGroup= XkbGroupForCoreState(mods); |
1122 | if ( effectiveGroup>=nKeyGroups ) { |
1123 | unsigned groupInfo= XkbKeyGroupInfo(xkb,key); |
1124 | switch (XkbOutOfRangeGroupAction(groupInfo)) { |
1125 | default: |
1126 | effectiveGroup %= nKeyGroups; |
1127 | break; |
1128 | case XkbClampIntoRange: |
1129 | effectiveGroup = nKeyGroups-1; |
1130 | break; |
1131 | case XkbRedirectIntoRange: |
1132 | effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo); |
1133 | if (effectiveGroup>=nKeyGroups) |
1134 | effectiveGroup= 0; |
1135 | break; |
1136 | } |
1137 | } |
1138 | found_col = col= effectiveGroup*XkbKeyGroupsWidth(xkb,key); |
1139 | type = XkbKeyKeyType(xkb,key,effectiveGroup); |
1140 | |
1141 | preserve= 0; |
1142 | if (type->map) { /* find the column (shift level) within the group */ |
1143 | register int i; |
1144 | register XkbKTMapEntryPtr entry; |
1145 | /* ---- Begin section modified for GDK ---- */ |
1146 | int found = 0; |
1147 | |
1148 | for (i=0,entry=type->map;i<type->map_count;i++,entry++) { |
1149 | if (!entry->active || syms[col+entry->level] == syms[col]) |
1150 | continue; |
1151 | if (mods_rtrn) { |
1152 | int bits = 0; |
1153 | unsigned long tmp = entry->mods.mask; |
1154 | while (tmp) { |
1155 | if ((tmp & 1) == 1) |
1156 | bits++; |
1157 | tmp >>= 1; |
1158 | } |
1159 | /* We always add one-modifiers levels to mods_rtrn since |
1160 | * they can't wipe out bits in the state unless the |
1161 | * level would be triggered. But not if they don't change |
1162 | * the symbol (otherwise we can't discriminate Shift-F10 |
1163 | * and F10 anymore). And don't add modifiers that are |
1164 | * explicitly marked as preserved, either. |
1165 | */ |
1166 | if (bits == 1 || |
1167 | (mods&type->mods.mask) == entry->mods.mask) |
1168 | { |
1169 | if (type->preserve) |
1170 | *mods_rtrn |= (entry->mods.mask & ~type->preserve[i].mask); |
1171 | else |
1172 | *mods_rtrn |= entry->mods.mask; |
1173 | } |
1174 | } |
1175 | |
1176 | if (!found && ((mods&type->mods.mask) == entry->mods.mask)) { |
1177 | found_col= col + entry->level; |
1178 | if (type->preserve) |
1179 | preserve= type->preserve[i].mask; |
1180 | |
1181 | if (level_rtrn) |
1182 | *level_rtrn = entry->level; |
1183 | |
1184 | found = 1; |
1185 | } |
1186 | } |
1187 | /* ---- End section modified for GDK ---- */ |
1188 | } |
1189 | |
1190 | if (keysym_rtrn!=NULL) |
1191 | *keysym_rtrn= syms[found_col]; |
1192 | if (mods_rtrn) { |
1193 | /* ---- Begin section modified for GDK ---- */ |
1194 | *mods_rtrn &= ~preserve; |
1195 | /* ---- End section modified for GDK ---- */ |
1196 | |
1197 | /* ---- Begin stuff GDK comments out of the original Xlib version ---- */ |
1198 | /* This is commented out because xkb_info is a private struct */ |
1199 | |
1200 | #if 0 |
1201 | /* The Motif VTS doesn't get the help callback called if help |
1202 | * is bound to Shift+<whatever>, and it appears as though it |
1203 | * is XkbTranslateKeyCode that is causing the problem. The |
1204 | * core X version of XTranslateKey always OR's in ShiftMask |
1205 | * and LockMask for mods_rtrn, so this "fix" keeps this behavior |
1206 | * and solves the VTS problem. |
1207 | */ |
1208 | if ((xkb->dpy)&&(xkb->dpy->xkb_info)&& |
1209 | (xkb->dpy->xkb_info->xlib_ctrls&XkbLC_AlwaysConsumeShiftAndLock)) { *mods_rtrn|= (ShiftMask|LockMask); |
1210 | } |
1211 | #endif |
1212 | |
1213 | /* ---- End stuff GDK comments out of the original Xlib version ---- */ |
1214 | } |
1215 | |
1216 | /* ---- Begin stuff GDK adds to the original Xlib version ---- */ |
1217 | |
1218 | if (group_rtrn) |
1219 | *group_rtrn = effectiveGroup; |
1220 | |
1221 | /* ---- End stuff GDK adds to the original Xlib version ---- */ |
1222 | |
1223 | return (syms[found_col] != NoSymbol); |
1224 | } |
1225 | #endif /* HAVE_XKB */ |
1226 | |
1227 | /* Translates from keycode/state to keysymbol using the traditional interpretation |
1228 | * of the keyboard map. See section 12.7 of the Xlib reference manual |
1229 | */ |
1230 | static guint |
1231 | translate_keysym (GdkX11Keymap *keymap_x11, |
1232 | guint hardware_keycode, |
1233 | int group, |
1234 | GdkModifierType state, |
1235 | int *effective_group, |
1236 | int *effective_level) |
1237 | { |
1238 | const KeySym *map = get_keymap (keymap_x11); |
1239 | const KeySym *syms = map + (hardware_keycode - keymap_x11->min_keycode) * keymap_x11->keysyms_per_keycode; |
1240 | |
1241 | #define SYM(k,g,l) get_symbol (syms, k,g,l) |
1242 | |
1243 | GdkModifierType shift_modifiers; |
1244 | int shift_level; |
1245 | guint tmp_keyval; |
1246 | |
1247 | shift_modifiers = GDK_SHIFT_MASK; |
1248 | if (keymap_x11->lock_keysym == GDK_KEY_Shift_Lock) |
1249 | shift_modifiers |= GDK_LOCK_MASK; |
1250 | |
1251 | /* Fall back to the first group if the passed in group is empty |
1252 | */ |
1253 | if (!(SYM (keymap_x11, group, 0) || SYM (keymap_x11, group, 1)) && |
1254 | (SYM (keymap_x11, 0, 0) || SYM (keymap_x11, 0, 1))) |
1255 | group = 0; |
1256 | |
1257 | if ((state & keymap_x11->num_lock_mask) && |
1258 | KEYSYM_IS_KEYPAD (SYM (keymap_x11, group, 1))) |
1259 | { |
1260 | /* Shift, Shift_Lock cancel Num_Lock |
1261 | */ |
1262 | shift_level = (state & shift_modifiers) ? 0 : 1; |
1263 | if (!SYM (keymap_x11, group, shift_level) && SYM (keymap_x11, group, 0)) |
1264 | shift_level = 0; |
1265 | |
1266 | tmp_keyval = SYM (keymap_x11, group, shift_level); |
1267 | } |
1268 | else |
1269 | { |
1270 | /* Fall back to the first level if no symbol for the level |
1271 | * we were passed. |
1272 | */ |
1273 | shift_level = (state & shift_modifiers) ? 1 : 0; |
1274 | if (!SYM (keymap_x11, group, shift_level) && SYM (keymap_x11, group, 0)) |
1275 | shift_level = 0; |
1276 | |
1277 | tmp_keyval = SYM (keymap_x11, group, shift_level); |
1278 | |
1279 | if (keymap_x11->lock_keysym == GDK_KEY_Caps_Lock && (state & GDK_LOCK_MASK) != 0) |
1280 | { |
1281 | guint upper = gdk_keyval_to_upper (keyval: tmp_keyval); |
1282 | if (upper != tmp_keyval) |
1283 | tmp_keyval = upper; |
1284 | } |
1285 | } |
1286 | |
1287 | if (effective_group) |
1288 | *effective_group = group; |
1289 | |
1290 | if (effective_level) |
1291 | *effective_level = shift_level; |
1292 | |
1293 | return tmp_keyval; |
1294 | |
1295 | #undef SYM |
1296 | } |
1297 | |
1298 | static gboolean |
1299 | gdk_x11_keymap_translate_keyboard_state (GdkKeymap *keymap, |
1300 | guint hardware_keycode, |
1301 | GdkModifierType state, |
1302 | int group, |
1303 | guint *keyval, |
1304 | int *effective_group, |
1305 | int *level, |
1306 | GdkModifierType *consumed_modifiers) |
1307 | { |
1308 | GdkX11Keymap *keymap_x11 = GDK_X11_KEYMAP (keymap); |
1309 | KeySym tmp_keyval = NoSymbol; |
1310 | guint tmp_modifiers; |
1311 | |
1312 | g_return_val_if_fail (group < 4, FALSE); |
1313 | |
1314 | if (keyval) |
1315 | *keyval = NoSymbol; |
1316 | if (effective_group) |
1317 | *effective_group = 0; |
1318 | if (level) |
1319 | *level = 0; |
1320 | if (consumed_modifiers) |
1321 | *consumed_modifiers = 0; |
1322 | |
1323 | update_keyrange (keymap_x11); |
1324 | |
1325 | if (hardware_keycode < keymap_x11->min_keycode || |
1326 | hardware_keycode > keymap_x11->max_keycode) |
1327 | return FALSE; |
1328 | |
1329 | #ifdef HAVE_XKB |
1330 | if (KEYMAP_USE_XKB (keymap)) |
1331 | { |
1332 | XkbDescRec *xkb = get_xkb (keymap_x11); |
1333 | |
1334 | /* replace bits 13 and 14 with the provided group */ |
1335 | state &= ~(1 << 13 | 1 << 14); |
1336 | state |= group << 13; |
1337 | |
1338 | MyEnhancedXkbTranslateKeyCode (xkb, |
1339 | key: hardware_keycode, |
1340 | mods: state, |
1341 | mods_rtrn: &tmp_modifiers, |
1342 | keysym_rtrn: &tmp_keyval, |
1343 | group_rtrn: effective_group, |
1344 | level_rtrn: level); |
1345 | |
1346 | if (state & ~tmp_modifiers & LockMask) |
1347 | tmp_keyval = gdk_keyval_to_upper (keyval: tmp_keyval); |
1348 | |
1349 | /* We need to augment the consumed modifiers with LockMask, since |
1350 | * we handle that ourselves, and also with the group bits |
1351 | */ |
1352 | tmp_modifiers |= LockMask | 1 << 13 | 1 << 14; |
1353 | } |
1354 | else |
1355 | #endif |
1356 | { |
1357 | GdkModifierType bit; |
1358 | |
1359 | tmp_modifiers = 0; |
1360 | |
1361 | /* We see what modifiers matter by trying the translation with |
1362 | * and without each possible modifier |
1363 | */ |
1364 | for (bit = GDK_SHIFT_MASK; bit < GDK_BUTTON1_MASK; bit <<= 1) |
1365 | { |
1366 | /* Handling of the group here is a bit funky; a traditional |
1367 | * X keyboard map can have more than two groups, but no way |
1368 | * of accessing the extra groups is defined. We allow a |
1369 | * caller to pass in any group to this function, but we |
1370 | * only can represent switching between group 0 and 1 in |
1371 | * consumed modifiers. |
1372 | */ |
1373 | if (translate_keysym (keymap_x11, hardware_keycode, |
1374 | group: (bit == keymap_x11->group_switch_mask) ? 0 : group, |
1375 | state: state & ~bit, |
1376 | NULL, NULL) != |
1377 | translate_keysym (keymap_x11, hardware_keycode, |
1378 | group: (bit == keymap_x11->group_switch_mask) ? 1 : group, |
1379 | state: state | bit, |
1380 | NULL, NULL)) |
1381 | tmp_modifiers |= bit; |
1382 | } |
1383 | |
1384 | tmp_keyval = translate_keysym (keymap_x11, hardware_keycode, |
1385 | group, state, |
1386 | effective_group, effective_level: level); |
1387 | } |
1388 | |
1389 | if (consumed_modifiers) |
1390 | *consumed_modifiers = tmp_modifiers; |
1391 | |
1392 | if (keyval) |
1393 | *keyval = tmp_keyval; |
1394 | |
1395 | return tmp_keyval != NoSymbol; |
1396 | } |
1397 | |
1398 | /*< private > |
1399 | * gdk_x11_keymap_get_group_for_state: |
1400 | * @keymap: (type GdkX11Keymap): a `GdkX11Keymap` |
1401 | * @state: raw state returned from X |
1402 | * |
1403 | * Extracts the group from the state field sent in an X Key event. |
1404 | * This is only needed for code processing raw X events, since `GdkEventKey` |
1405 | * directly includes an is_modifier field. |
1406 | * |
1407 | * Returns: the index of the active keyboard group for the event |
1408 | */ |
1409 | int |
1410 | gdk_x11_keymap_get_group_for_state (GdkKeymap *keymap, |
1411 | guint state) |
1412 | { |
1413 | GdkDisplay *display; |
1414 | GdkX11Display *display_x11; |
1415 | |
1416 | g_return_val_if_fail (GDK_IS_X11_KEYMAP (keymap), 0); |
1417 | |
1418 | display = keymap->display; |
1419 | display_x11 = GDK_X11_DISPLAY (display); |
1420 | |
1421 | #ifdef HAVE_XKB |
1422 | if (display_x11->use_xkb) |
1423 | { |
1424 | return XkbGroupForCoreState (state); |
1425 | } |
1426 | else |
1427 | #endif |
1428 | { |
1429 | GdkX11Keymap *keymap_impl = GDK_X11_KEYMAP (gdk_display_get_keymap (display)); |
1430 | update_keymaps (keymap_x11: keymap_impl); |
1431 | return (state & keymap_impl->group_switch_mask) ? 1 : 0; |
1432 | } |
1433 | } |
1434 | |
1435 | void |
1436 | _gdk_x11_keymap_add_virt_mods (GdkKeymap *keymap, |
1437 | GdkModifierType *modifiers) |
1438 | { |
1439 | GdkX11Keymap *keymap_x11 = GDK_X11_KEYMAP (keymap); |
1440 | int i; |
1441 | |
1442 | /* This loop used to start at 3, which included MOD1 in the |
1443 | * virtual mapping. However, all of GTK+ treats MOD1 as a |
1444 | * synonym for Alt, and does not expect it to be mapped around, |
1445 | * therefore it's more sane to simply treat MOD1 like SHIFT and |
1446 | * CONTROL, which are not mappable either. |
1447 | */ |
1448 | for (i = 4; i < 8; i++) |
1449 | { |
1450 | if ((1 << i) & *modifiers) |
1451 | { |
1452 | if (keymap_x11->modmap[i] & GDK_SUPER_MASK) |
1453 | *modifiers |= GDK_SUPER_MASK; |
1454 | else if (keymap_x11->modmap[i] & GDK_HYPER_MASK) |
1455 | *modifiers |= GDK_HYPER_MASK; |
1456 | else if (keymap_x11->modmap[i] & GDK_META_MASK) |
1457 | *modifiers |= GDK_META_MASK; |
1458 | } |
1459 | } |
1460 | } |
1461 | |
1462 | /*< private > |
1463 | * gdk_x11_keymap_key_is_modifier: |
1464 | * @keymap: (type GdkX11Keymap): a `GdkX11Keymap` |
1465 | * @keycode: the hardware keycode from a key event |
1466 | * |
1467 | * Determines whether a particular key code represents a key that |
1468 | * is a modifier. That is, it’s a key that normally just affects |
1469 | * the keyboard state and the behavior of other keys rather than |
1470 | * producing a direct effect itself. This is only needed for code |
1471 | * processing raw X events, since `GdkEventKey` directly includes |
1472 | * an is_modifier field. |
1473 | * |
1474 | * Returns: %TRUE if the hardware keycode is a modifier key |
1475 | */ |
1476 | gboolean |
1477 | gdk_x11_keymap_key_is_modifier (GdkKeymap *keymap, |
1478 | guint keycode) |
1479 | { |
1480 | GdkX11Keymap *keymap_x11 = GDK_X11_KEYMAP (keymap); |
1481 | int i; |
1482 | |
1483 | g_return_val_if_fail (GDK_IS_X11_KEYMAP (keymap), FALSE); |
1484 | |
1485 | update_keyrange (keymap_x11); |
1486 | if (keycode < keymap_x11->min_keycode || |
1487 | keycode > keymap_x11->max_keycode) |
1488 | return FALSE; |
1489 | |
1490 | #ifdef HAVE_XKB |
1491 | if (KEYMAP_USE_XKB (keymap)) |
1492 | { |
1493 | XkbDescRec *xkb = get_xkb (keymap_x11); |
1494 | |
1495 | if (xkb->map->modmap && xkb->map->modmap[keycode] != 0) |
1496 | return TRUE; |
1497 | } |
1498 | else |
1499 | #endif |
1500 | { |
1501 | for (i = 0; i < 8 * keymap_x11->mod_keymap->max_keypermod; i++) |
1502 | { |
1503 | if (keycode == keymap_x11->mod_keymap->modifiermap[i]) |
1504 | return TRUE; |
1505 | } |
1506 | } |
1507 | |
1508 | return FALSE; |
1509 | } |
1510 | |
1511 | static void |
1512 | gdk_x11_keymap_class_init (GdkX11KeymapClass *klass) |
1513 | { |
1514 | GObjectClass *object_class = G_OBJECT_CLASS (klass); |
1515 | GdkKeymapClass *keymap_class = GDK_KEYMAP_CLASS (klass); |
1516 | |
1517 | object_class->finalize = gdk_x11_keymap_finalize; |
1518 | |
1519 | keymap_class->get_direction = gdk_x11_keymap_get_direction; |
1520 | keymap_class->have_bidi_layouts = gdk_x11_keymap_have_bidi_layouts; |
1521 | keymap_class->get_caps_lock_state = gdk_x11_keymap_get_caps_lock_state; |
1522 | keymap_class->get_num_lock_state = gdk_x11_keymap_get_num_lock_state; |
1523 | keymap_class->get_scroll_lock_state = gdk_x11_keymap_get_scroll_lock_state; |
1524 | keymap_class->get_modifier_state = gdk_x11_keymap_get_modifier_state; |
1525 | keymap_class->get_entries_for_keyval = gdk_x11_keymap_get_entries_for_keyval; |
1526 | keymap_class->get_entries_for_keycode = gdk_x11_keymap_get_entries_for_keycode; |
1527 | keymap_class->lookup_key = gdk_x11_keymap_lookup_key; |
1528 | keymap_class->translate_keyboard_state = gdk_x11_keymap_translate_keyboard_state; |
1529 | } |
1530 | |