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 <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <unistd.h>
31#include <limits.h>
32#include <errno.h>
33#include <sys/mman.h>
34
35#include "gdk.h"
36#include "gdkwayland.h"
37
38#include "gdkprivate-wayland.h"
39#include "gdk-private.h"
40#include "gdkkeysprivate.h"
41
42#include <xkbcommon/xkbcommon.h>
43
44typedef struct _GdkWaylandKeymap GdkWaylandKeymap;
45typedef struct _GdkWaylandKeymapClass GdkWaylandKeymapClass;
46
47struct _GdkWaylandKeymap
48{
49 GdkKeymap parent_instance;
50
51 struct xkb_keymap *xkb_keymap;
52 struct xkb_state *xkb_state;
53
54 PangoDirection *direction;
55 gboolean bidi;
56};
57
58struct _GdkWaylandKeymapClass
59{
60 GdkKeymapClass parent_class;
61};
62
63#define GDK_TYPE_WAYLAND_KEYMAP (_gdk_wayland_keymap_get_type ())
64#define GDK_WAYLAND_KEYMAP(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_WAYLAND_KEYMAP, GdkWaylandKeymap))
65#define GDK_IS_WAYLAND_KEYMAP(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_WAYLAND_KEYMAP))
66
67GType _gdk_wayland_keymap_get_type (void);
68
69G_DEFINE_TYPE (GdkWaylandKeymap, _gdk_wayland_keymap, GDK_TYPE_KEYMAP)
70
71static void
72gdk_wayland_keymap_finalize (GObject *object)
73{
74 GdkWaylandKeymap *keymap = GDK_WAYLAND_KEYMAP (object);
75
76 xkb_keymap_unref (keymap: keymap->xkb_keymap);
77 xkb_state_unref (state: keymap->xkb_state);
78 g_free (mem: keymap->direction);
79
80 G_OBJECT_CLASS (_gdk_wayland_keymap_parent_class)->finalize (object);
81}
82
83static PangoDirection
84gdk_wayland_keymap_get_direction (GdkKeymap *keymap)
85{
86 GdkWaylandKeymap *keymap_wayland = GDK_WAYLAND_KEYMAP (keymap);
87 int i;
88
89 for (i = 0; i < xkb_keymap_num_layouts (keymap: keymap_wayland->xkb_keymap); i++)
90 {
91 if (xkb_state_layout_index_is_active (state: keymap_wayland->xkb_state, idx: i, type: XKB_STATE_LAYOUT_EFFECTIVE))
92 return keymap_wayland->direction[i];
93 }
94
95 return PANGO_DIRECTION_NEUTRAL;
96}
97
98static gboolean
99gdk_wayland_keymap_have_bidi_layouts (GdkKeymap *keymap)
100{
101 GdkWaylandKeymap *keymap_wayland = GDK_WAYLAND_KEYMAP (keymap);
102
103 return keymap_wayland->bidi;
104}
105
106static gboolean
107gdk_wayland_keymap_get_caps_lock_state (GdkKeymap *keymap)
108{
109 return xkb_state_led_name_is_active (GDK_WAYLAND_KEYMAP (keymap)->xkb_state,
110 XKB_LED_NAME_CAPS);
111}
112
113static gboolean
114gdk_wayland_keymap_get_num_lock_state (GdkKeymap *keymap)
115{
116 return xkb_state_led_name_is_active (GDK_WAYLAND_KEYMAP (keymap)->xkb_state,
117 XKB_LED_NAME_NUM);
118}
119
120static gboolean
121gdk_wayland_keymap_get_scroll_lock_state (GdkKeymap *keymap)
122{
123 return xkb_state_led_name_is_active (GDK_WAYLAND_KEYMAP (keymap)->xkb_state,
124 XKB_LED_NAME_SCROLL);
125}
126
127static gboolean
128gdk_wayland_keymap_get_entries_for_keyval (GdkKeymap *keymap,
129 guint keyval,
130 GArray *retval)
131{
132 struct xkb_keymap *xkb_keymap = GDK_WAYLAND_KEYMAP (keymap)->xkb_keymap;
133 guint keycode;
134 xkb_keycode_t min_keycode, max_keycode;
135 guint len = retval->len;
136
137 min_keycode = xkb_keymap_min_keycode (keymap: xkb_keymap);
138 max_keycode = xkb_keymap_max_keycode (keymap: xkb_keymap);
139 for (keycode = min_keycode; keycode < max_keycode; keycode++)
140 {
141 int num_layouts, layout;
142 num_layouts = xkb_keymap_num_layouts_for_key (keymap: xkb_keymap, key: keycode);
143 for (layout = 0; layout < num_layouts; layout++)
144 {
145 int num_levels, level;
146 num_levels = xkb_keymap_num_levels_for_key (keymap: xkb_keymap, key: keycode, layout);
147 for (level = 0; level < num_levels; level++)
148 {
149 const xkb_keysym_t *syms;
150 int num_syms, sym;
151 num_syms = xkb_keymap_key_get_syms_by_level (keymap: xkb_keymap, key: keycode, layout, level, syms_out: &syms);
152 for (sym = 0; sym < num_syms; sym++)
153 {
154 if (syms[sym] == keyval)
155 {
156 GdkKeymapKey key;
157
158 key.keycode = keycode;
159 key.group = layout;
160 key.level = level;
161
162 g_array_append_val (retval, key);
163 }
164 }
165 }
166 }
167 }
168
169 return retval->len > len;
170}
171
172static gboolean
173gdk_wayland_keymap_get_entries_for_keycode (GdkKeymap *keymap,
174 guint hardware_keycode,
175 GdkKeymapKey **keys,
176 guint **keyvals,
177 int *n_entries)
178{
179 struct xkb_keymap *xkb_keymap = GDK_WAYLAND_KEYMAP (keymap)->xkb_keymap;
180 int num_layouts, layout;
181 int num_entries;
182 int i;
183
184 num_layouts = xkb_keymap_num_layouts_for_key (keymap: xkb_keymap, key: hardware_keycode);
185
186 num_entries = 0;
187 for (layout = 0; layout < num_layouts; layout++)
188 num_entries += xkb_keymap_num_levels_for_key (keymap: xkb_keymap, key: hardware_keycode, layout);
189
190 if (n_entries)
191 *n_entries = num_entries;
192 if (keys)
193 *keys = g_new0 (GdkKeymapKey, num_entries);
194 if (keyvals)
195 *keyvals = g_new0 (guint, num_entries);
196
197 i = 0;
198 for (layout = 0; layout < num_layouts; layout++)
199 {
200 int num_levels, level;
201 num_levels = xkb_keymap_num_levels_for_key (keymap: xkb_keymap, key: hardware_keycode, layout);
202 for (level = 0; level < num_levels; level++)
203 {
204 const xkb_keysym_t *syms;
205 int num_syms;
206 num_syms = xkb_keymap_key_get_syms_by_level (keymap: xkb_keymap, key: hardware_keycode, layout, level: 0, syms_out: &syms);
207 if (keys)
208 {
209 (*keys)[i].keycode = hardware_keycode;
210 (*keys)[i].group = layout;
211 (*keys)[i].level = level;
212 }
213 if (keyvals && num_syms > 0)
214 (*keyvals)[i] = syms[0];
215
216 i++;
217 }
218 }
219
220 return num_entries > 0;
221}
222
223static guint
224gdk_wayland_keymap_lookup_key (GdkKeymap *keymap,
225 const GdkKeymapKey *key)
226{
227 struct xkb_keymap *xkb_keymap = GDK_WAYLAND_KEYMAP (keymap)->xkb_keymap;
228 const xkb_keysym_t *syms;
229 int num_syms;
230
231 num_syms = xkb_keymap_key_get_syms_by_level (keymap: xkb_keymap,
232 key: key->keycode,
233 layout: key->group,
234 level: key->level,
235 syms_out: &syms);
236 if (num_syms > 0)
237 return syms[0];
238 else
239 return XKB_KEY_NoSymbol;
240}
241
242static guint32
243get_xkb_modifiers (struct xkb_keymap *xkb_keymap,
244 GdkModifierType state)
245{
246 guint32 mods = 0;
247
248 if (state & GDK_SHIFT_MASK)
249 mods |= 1 << xkb_keymap_mod_get_index (keymap: xkb_keymap, XKB_MOD_NAME_SHIFT);
250 if (state & GDK_LOCK_MASK)
251 mods |= 1 << xkb_keymap_mod_get_index (keymap: xkb_keymap, XKB_MOD_NAME_CAPS);
252 if (state & GDK_CONTROL_MASK)
253 mods |= 1 << xkb_keymap_mod_get_index (keymap: xkb_keymap, XKB_MOD_NAME_CTRL);
254 if (state & GDK_ALT_MASK)
255 mods |= 1 << xkb_keymap_mod_get_index (keymap: xkb_keymap, XKB_MOD_NAME_ALT);
256 if (state & GDK_SUPER_MASK)
257 mods |= 1 << xkb_keymap_mod_get_index (keymap: xkb_keymap, name: "Super");
258 if (state & GDK_HYPER_MASK)
259 mods |= 1 << xkb_keymap_mod_get_index (keymap: xkb_keymap, name: "Hyper");
260 if (state & GDK_META_MASK)
261 mods |= 1 << xkb_keymap_mod_get_index (keymap: xkb_keymap, name: "Meta");
262
263 return mods;
264}
265
266static GdkModifierType
267get_gdk_modifiers (struct xkb_keymap *xkb_keymap,
268 guint32 mods)
269{
270 GdkModifierType state = 0;
271
272 if (mods & (1 << xkb_keymap_mod_get_index (keymap: xkb_keymap, XKB_MOD_NAME_SHIFT)))
273 state |= GDK_SHIFT_MASK;
274 if (mods & (1 << xkb_keymap_mod_get_index (keymap: xkb_keymap, XKB_MOD_NAME_CAPS)))
275 state |= GDK_LOCK_MASK;
276 if (mods & (1 << xkb_keymap_mod_get_index (keymap: xkb_keymap, XKB_MOD_NAME_CTRL)))
277 state |= GDK_CONTROL_MASK;
278 if (mods & (1 << xkb_keymap_mod_get_index (keymap: xkb_keymap, XKB_MOD_NAME_ALT)))
279 state |= GDK_ALT_MASK;
280 if (mods & (1 << xkb_keymap_mod_get_index (keymap: xkb_keymap, name: "Super")))
281 state |= GDK_SUPER_MASK;
282 if (mods & (1 << xkb_keymap_mod_get_index (keymap: xkb_keymap, name: "Hyper")))
283 state |= GDK_HYPER_MASK;
284 /* GTK treats MOD1 as a synonym for Alt, and does not expect it to
285 * be mapped around, so we should avoid adding GDK_META_MASK if MOD1
286 * is already included to avoid confusing GTK and applications that
287 * rely on that behavior.
288 */
289 if (mods & (1 << xkb_keymap_mod_get_index (keymap: xkb_keymap, name: "Meta")) &&
290 (state & GDK_ALT_MASK) == 0)
291 state |= GDK_META_MASK;
292
293 return state;
294}
295
296GdkModifierType
297gdk_wayland_keymap_get_gdk_modifiers (GdkKeymap *keymap,
298 guint32 mods)
299{
300 struct xkb_keymap *xkb_keymap = GDK_WAYLAND_KEYMAP (keymap)->xkb_keymap;
301
302 return get_gdk_modifiers (xkb_keymap, mods);
303}
304
305static gboolean
306gdk_wayland_keymap_translate_keyboard_state (GdkKeymap *keymap,
307 guint hardware_keycode,
308 GdkModifierType state,
309 int group,
310 guint *keyval,
311 int *effective_group,
312 int *effective_level,
313 GdkModifierType *consumed_modifiers)
314{
315 struct xkb_keymap *xkb_keymap;
316 struct xkb_state *xkb_state;
317 guint32 modifiers;
318 guint32 consumed;
319 xkb_layout_index_t layout;
320 xkb_level_index_t level;
321 xkb_keysym_t sym;
322
323 g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE);
324 g_return_val_if_fail (group < 4, FALSE);
325
326 xkb_keymap = GDK_WAYLAND_KEYMAP (keymap)->xkb_keymap;
327
328 modifiers = get_xkb_modifiers (xkb_keymap, state);
329
330 xkb_state = xkb_state_new (keymap: xkb_keymap);
331
332 xkb_state_update_mask (state: xkb_state, depressed_mods: modifiers, latched_mods: 0, locked_mods: 0, depressed_layout: group, latched_layout: 0, locked_layout: 0);
333
334 layout = xkb_state_key_get_layout (state: xkb_state, key: hardware_keycode);
335 level = xkb_state_key_get_level (state: xkb_state, key: hardware_keycode, layout);
336 sym = xkb_state_key_get_one_sym (state: xkb_state, key: hardware_keycode);
337 consumed = modifiers & ~xkb_state_mod_mask_remove_consumed (state: xkb_state, key: hardware_keycode, mask: modifiers);
338
339 xkb_state_unref (state: xkb_state);
340
341 if (keyval)
342 *keyval = sym;
343 if (effective_group)
344 *effective_group = layout;
345 if (effective_level)
346 *effective_level = level;
347 if (consumed_modifiers)
348 *consumed_modifiers = get_gdk_modifiers (xkb_keymap, mods: consumed);
349
350 return (sym != XKB_KEY_NoSymbol);
351}
352
353static guint
354gdk_wayland_keymap_get_modifier_state (GdkKeymap *keymap)
355{
356 struct xkb_keymap *xkb_keymap = GDK_WAYLAND_KEYMAP (keymap)->xkb_keymap;
357 struct xkb_state *xkb_state = GDK_WAYLAND_KEYMAP (keymap)->xkb_state;
358 xkb_mod_mask_t mods;
359
360 mods = xkb_state_serialize_mods (state: xkb_state, components: XKB_STATE_MODS_EFFECTIVE);
361
362 return get_gdk_modifiers (xkb_keymap, mods);
363}
364
365static void
366_gdk_wayland_keymap_class_init (GdkWaylandKeymapClass *klass)
367{
368 GObjectClass *object_class = G_OBJECT_CLASS (klass);
369 GdkKeymapClass *keymap_class = GDK_KEYMAP_CLASS (klass);
370
371 object_class->finalize = gdk_wayland_keymap_finalize;
372
373 keymap_class->get_direction = gdk_wayland_keymap_get_direction;
374 keymap_class->have_bidi_layouts = gdk_wayland_keymap_have_bidi_layouts;
375 keymap_class->get_caps_lock_state = gdk_wayland_keymap_get_caps_lock_state;
376 keymap_class->get_num_lock_state = gdk_wayland_keymap_get_num_lock_state;
377 keymap_class->get_scroll_lock_state = gdk_wayland_keymap_get_scroll_lock_state;
378 keymap_class->get_entries_for_keyval = gdk_wayland_keymap_get_entries_for_keyval;
379 keymap_class->get_entries_for_keycode = gdk_wayland_keymap_get_entries_for_keycode;
380 keymap_class->lookup_key = gdk_wayland_keymap_lookup_key;
381 keymap_class->translate_keyboard_state = gdk_wayland_keymap_translate_keyboard_state;
382 keymap_class->get_modifier_state = gdk_wayland_keymap_get_modifier_state;
383}
384
385static void
386_gdk_wayland_keymap_init (GdkWaylandKeymap *keymap)
387{
388}
389
390static void
391update_direction (GdkWaylandKeymap *keymap)
392{
393 int num_layouts;
394 int i;
395 int *rtl;
396 xkb_keycode_t min_keycode, max_keycode;
397 guint key;
398 gboolean have_rtl, have_ltr;
399
400 num_layouts = xkb_keymap_num_layouts (keymap: keymap->xkb_keymap);
401
402 keymap->direction = g_renew (PangoDirection, keymap->direction, num_layouts);
403 rtl = g_newa (int, num_layouts);
404 for (i = 0; i < num_layouts; i++)
405 rtl[i] = 0;
406
407 min_keycode = xkb_keymap_min_keycode (keymap: keymap->xkb_keymap);
408 max_keycode = xkb_keymap_max_keycode (keymap: keymap->xkb_keymap);
409 for (key = min_keycode; key < max_keycode; key++)
410 {
411 int layouts, layout;
412
413 layouts = xkb_keymap_num_layouts_for_key (keymap: keymap->xkb_keymap, key);
414 g_assert (layouts <= num_layouts);
415 for (layout = 0; layout < layouts; layout++)
416 {
417 const xkb_keysym_t *syms;
418 int num_syms;
419 int sym;
420
421 num_syms = xkb_keymap_key_get_syms_by_level (keymap: keymap->xkb_keymap, key, layout, level: 0, syms_out: &syms);
422 for (sym = 0; sym < num_syms; sym++)
423 {
424 PangoDirection dir;
425
426 dir = gdk_unichar_direction (ch: xkb_keysym_to_utf32 (keysym: syms[sym]));
427 switch (dir)
428 {
429 case PANGO_DIRECTION_RTL:
430 rtl[layout]++;
431 break;
432 case PANGO_DIRECTION_LTR:
433 rtl[layout]--;
434 break;
435 case PANGO_DIRECTION_TTB_LTR:
436 case PANGO_DIRECTION_TTB_RTL:
437 case PANGO_DIRECTION_WEAK_LTR:
438 case PANGO_DIRECTION_WEAK_RTL:
439 case PANGO_DIRECTION_NEUTRAL:
440 default:
441 break;
442 }
443 }
444 }
445 }
446
447 have_rtl = have_ltr = FALSE;
448 for (i = 0; i < num_layouts; i++)
449 {
450 if (rtl[i] > 0)
451 {
452 keymap->direction[i] = PANGO_DIRECTION_RTL;
453 have_rtl = TRUE;
454 }
455 else
456 {
457 keymap->direction[i] = PANGO_DIRECTION_LTR;
458 have_ltr = TRUE;
459 }
460 }
461
462 if (have_rtl && have_ltr)
463 keymap->bidi = TRUE;
464}
465
466GdkKeymap *
467_gdk_wayland_keymap_new (GdkDisplay *display)
468{
469 GdkWaylandKeymap *keymap;
470 struct xkb_context *context;
471 struct xkb_rule_names names;
472
473 keymap = g_object_new (object_type: _gdk_wayland_keymap_get_type(), NULL);
474 GDK_KEYMAP (keymap)->display = display;
475
476 context = xkb_context_new (flags: 0);
477
478 names.rules = "evdev";
479 names.model = "pc105";
480 names.layout = "us";
481 names.variant = "";
482 names.options = "";
483 keymap->xkb_keymap = xkb_keymap_new_from_names (context, names: &names, flags: 0);
484 keymap->xkb_state = xkb_state_new (keymap: keymap->xkb_keymap);
485 xkb_context_unref (context);
486
487 update_direction (keymap);
488
489 return GDK_KEYMAP (keymap);
490}
491
492#ifdef G_ENABLE_DEBUG
493static void
494print_modifiers (struct xkb_keymap *keymap)
495{
496 int i, j;
497 uint32_t real;
498 struct xkb_state *state;
499
500 g_print (format: "modifiers:\n");
501 for (i = 0; i < xkb_keymap_num_mods (keymap); i++)
502 g_print (format: "%s ", xkb_keymap_mod_get_name (keymap, idx: i));
503 g_print (format: "\n\n");
504
505 g_print (format: "modifier mapping\n");
506 state = xkb_state_new (keymap);
507 for (i = 0; i < 8; i++)
508 {
509 gboolean need_arrow = TRUE;
510 g_print (format: "%s ", xkb_keymap_mod_get_name (keymap, idx: i));
511 for (j = 8; j < xkb_keymap_num_mods (keymap); j++)
512 {
513 xkb_state_update_mask (state, depressed_mods: 1 << j, latched_mods: 0, locked_mods: 0, depressed_layout: 0, latched_layout: 0, locked_layout: 0);
514 real = xkb_state_serialize_mods (state, components: XKB_STATE_MODS_EFFECTIVE);
515 if (real & (1 << i))
516 {
517 if (need_arrow)
518 {
519 g_print (format: "-> ");
520 need_arrow = FALSE;
521 }
522 g_print (format: "%s ", xkb_keymap_mod_get_name (keymap, idx: j));
523 }
524 }
525 g_print (format: "\n");
526 }
527
528 xkb_state_unref (state);
529}
530#endif
531
532void
533_gdk_wayland_keymap_update_from_fd (GdkKeymap *keymap,
534 uint32_t format,
535 uint32_t fd,
536 uint32_t size)
537{
538 GdkWaylandKeymap *keymap_wayland = GDK_WAYLAND_KEYMAP (keymap);
539 struct xkb_context *context;
540 struct xkb_keymap *xkb_keymap;
541 char *map_str;
542
543 context = xkb_context_new (flags: 0);
544
545 map_str = mmap (NULL, len: size, PROT_READ, MAP_PRIVATE, fd: fd, offset: 0);
546 if (map_str == MAP_FAILED)
547 {
548 close(fd: fd);
549 return;
550 }
551
552 GDK_DISPLAY_NOTE (keymap->display, INPUT, g_message ("keymap:\n%s", map_str));
553
554 xkb_keymap = xkb_keymap_new_from_string (context, string: map_str, format, flags: 0);
555 munmap (addr: map_str, len: size);
556 close (fd: fd);
557
558 if (!xkb_keymap)
559 {
560 g_warning ("Got invalid keymap from compositor, keeping previous/default one");
561 xkb_context_unref (context);
562 return;
563 }
564
565 GDK_DISPLAY_NOTE (keymap->display, INPUT, print_modifiers (xkb_keymap));
566
567 xkb_keymap_unref (keymap: keymap_wayland->xkb_keymap);
568 keymap_wayland->xkb_keymap = xkb_keymap;
569
570 xkb_state_unref (state: keymap_wayland->xkb_state);
571 keymap_wayland->xkb_state = xkb_state_new (keymap: keymap_wayland->xkb_keymap);
572
573 xkb_context_unref (context);
574
575 update_direction (keymap: keymap_wayland);
576}
577
578struct xkb_keymap *
579_gdk_wayland_keymap_get_xkb_keymap (GdkKeymap *keymap)
580{
581 return GDK_WAYLAND_KEYMAP (keymap)->xkb_keymap;
582}
583
584struct xkb_state *
585_gdk_wayland_keymap_get_xkb_state (GdkKeymap *keymap)
586{
587 return GDK_WAYLAND_KEYMAP (keymap)->xkb_state;
588}
589
590gboolean
591_gdk_wayland_keymap_key_is_modifier (GdkKeymap *keymap,
592 guint keycode)
593{
594 struct xkb_keymap *xkb_keymap = GDK_WAYLAND_KEYMAP (keymap)->xkb_keymap;
595 struct xkb_state *xkb_state;
596 gboolean is_modifier;
597
598 is_modifier = FALSE;
599
600 xkb_state = xkb_state_new (keymap: xkb_keymap);
601
602 if (xkb_state_update_key (state: xkb_state, key: keycode, direction: XKB_KEY_DOWN) & XKB_STATE_MODS_EFFECTIVE)
603 is_modifier = TRUE;
604
605 xkb_state_unref (state: xkb_state);
606
607 return is_modifier;
608}
609

source code of gtk/gdk/wayland/gdkkeys-wayland.c