]> Pileus Git - ~andy/gtk/blob - gdk/wayland/gdkkeys-wayland.c
wayland: Create and expose an xkb_state on the keymap object
[~andy/gtk] / gdk / wayland / gdkkeys-wayland.c
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 "gdkinternals.h"
40 #include "gdkkeysprivate.h"
41
42 #include <xkbcommon/xkbcommon.h>
43
44 typedef struct _GdkWaylandKeymap          GdkWaylandKeymap;
45 typedef struct _GdkWaylandKeymapClass     GdkWaylandKeymapClass;
46
47 struct _GdkWaylandKeymap
48 {
49   GdkKeymap parent_instance;
50
51   struct xkb_keymap *xkb_keymap;
52   struct xkb_state *xkb_state;
53 };
54
55 struct _GdkWaylandKeymapClass
56 {
57   GdkKeymapClass parent_class;
58 };
59
60 #define GDK_TYPE_WAYLAND_KEYMAP          (_gdk_wayland_keymap_get_type ())
61 #define GDK_WAYLAND_KEYMAP(object)       (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_WAYLAND_KEYMAP, GdkWaylandKeymap))
62 #define GDK_IS_WAYLAND_KEYMAP(object)    (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_WAYLAND_KEYMAP))
63
64 G_DEFINE_TYPE (GdkWaylandKeymap, _gdk_wayland_keymap, GDK_TYPE_KEYMAP)
65
66 static void
67 gdk_wayland_keymap_finalize (GObject *object)
68 {
69   G_OBJECT_CLASS (_gdk_wayland_keymap_parent_class)->finalize (object);
70 }
71
72 static PangoDirection
73 gdk_wayland_keymap_get_direction (GdkKeymap *keymap)
74 {
75     return PANGO_DIRECTION_NEUTRAL;
76 }
77
78 static gboolean
79 gdk_wayland_keymap_have_bidi_layouts (GdkKeymap *keymap)
80 {
81     return FALSE;
82 }
83
84 static gboolean
85 gdk_wayland_keymap_get_caps_lock_state (GdkKeymap *keymap)
86 {
87   return FALSE;
88 }
89
90 static gboolean
91 gdk_wayland_keymap_get_num_lock_state (GdkKeymap *keymap)
92 {
93   return FALSE;
94 }
95
96 static gboolean
97 gdk_wayland_keymap_get_entries_for_keyval (GdkKeymap     *keymap,
98                                            guint          keyval,
99                                            GdkKeymapKey **keys,
100                                            gint          *n_keys)
101 {
102 #if 0
103   GArray *retval;
104   uint32_t keycode;
105   struct xkb_desc *xkb;
106
107   xkb = GDK_WAYLAND_KEYMAP (keymap)->xkb;
108   keycode = xkb->min_key_code;
109
110   retval = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
111
112   for (keycode = xkb->min_key_code; keycode <= xkb->max_key_code; keycode++)
113     {
114       gint max_shift_levels = XkbKeyGroupsWidth (xkb, keycode);
115
116       gint group = 0;
117       gint level = 0;
118       gint total_syms = XkbKeyNumSyms (xkb, keycode);
119       gint i = 0;
120       uint32_t *entry;
121
122       /* entry is an array with all syms for group 0, all
123        * syms for group 1, etc. and for each group the
124        * shift level syms are in order
125        */
126       entry = XkbKeySymsPtr (xkb, keycode);
127
128       for (i = 0; i < total_syms; i++)
129         {
130           /* check out our cool loop invariant */
131           g_assert (i == (group * max_shift_levels + level));
132
133           if (entry[i] == keyval)
134             {
135               /* Found a match */
136               GdkKeymapKey key;
137
138               key.keycode = keycode;
139               key.group = group;
140               key.level = level;
141
142               g_array_append_val (retval, key);
143
144               g_assert (XkbKeySymEntry (xkb, keycode, level, group) ==
145                         keyval);
146             }
147
148           level++;
149
150           if (level == max_shift_levels)
151             {
152               level = 0;
153               group++;
154             }
155         }
156     }
157
158   *n_keys = retval->len;
159   *keys = (GdkKeymapKey *) g_array_free (retval, FALSE);
160
161   return *n_keys > 0;
162 #endif
163   return FALSE;
164 }
165
166 static gboolean
167 gdk_wayland_keymap_get_entries_for_keycode (GdkKeymap     *keymap,
168                                             guint          hardware_keycode,
169                                             GdkKeymapKey **keys,
170                                             guint        **keyvals,
171                                             gint          *n_entries)
172 {
173 #if 0
174   GArray *key_array;
175   GArray *keyval_array;
176   struct xkb_desc *xkb;
177   gint max_shift_levels;
178   gint group = 0;
179   gint level = 0;
180   gint total_syms;
181   gint i;
182   uint32_t *entry;
183
184   g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE);
185   g_return_val_if_fail (n_entries != NULL, FALSE);
186
187   xkb = GDK_WAYLAND_KEYMAP (keymap)->xkb;
188
189   if (hardware_keycode < xkb->min_key_code ||
190       hardware_keycode > xkb->max_key_code)
191     {
192       if (keys)
193         *keys = NULL;
194       if (keyvals)
195         *keyvals = NULL;
196
197       *n_entries = 0;
198       return FALSE;
199     }
200
201   if (keys)
202     key_array = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
203   else
204     key_array = NULL;
205
206   if (keyvals)
207     keyval_array = g_array_new (FALSE, FALSE, sizeof (guint));
208   else
209     keyval_array = NULL;
210
211   /* See sec 15.3.4 in XKB docs */
212   max_shift_levels = XkbKeyGroupsWidth (xkb, hardware_keycode);
213   total_syms = XkbKeyNumSyms (xkb, hardware_keycode);
214
215   /* entry is an array with all syms for group 0, all
216    * syms for group 1, etc. and for each group the
217    * shift level syms are in order
218    */
219   entry = XkbKeySymsPtr (xkb, hardware_keycode);
220
221   for (i = 0; i < total_syms; i++)
222     {
223       /* check out our cool loop invariant */
224       g_assert (i == (group * max_shift_levels + level));
225
226       if (key_array)
227         {
228           GdkKeymapKey key;
229
230           key.keycode = hardware_keycode;
231           key.group = group;
232           key.level = level;
233
234           g_array_append_val (key_array, key);
235         }
236
237       if (keyval_array)
238         g_array_append_val (keyval_array, entry[i]);
239
240       ++level;
241
242       if (level == max_shift_levels)
243         {
244           level = 0;
245           ++group;
246         }
247     }
248
249   *n_entries = 0;
250
251   if (keys)
252     {
253       *n_entries = key_array->len;
254       *keys = (GdkKeymapKey*) g_array_free (key_array, FALSE);
255     }
256
257   if (keyvals)
258     {
259       *n_entries = keyval_array->len;
260       *keyvals = (guint*) g_array_free (keyval_array, FALSE);
261     }
262
263   return *n_entries > 0;
264 #endif
265   return FALSE;
266 }
267
268 static guint
269 gdk_wayland_keymap_lookup_key (GdkKeymap          *keymap,
270                                const GdkKeymapKey *key)
271 {
272 #if 0
273   struct xkb_desc *xkb;
274
275   xkb = GDK_WAYLAND_KEYMAP (keymap)->xkb;
276
277   return XkbKeySymEntry (xkb, key->keycode, key->level, key->group);
278 #endif
279   return 0;
280 }
281
282 #if 0
283 /* This is copied straight from XFree86 Xlib, to:
284  *  - add the group and level return.
285  *  - change the interpretation of mods_rtrn as described
286  *    in the docs for gdk_keymap_translate_keyboard_state()
287  * It's unchanged for ease of diff against the Xlib sources; don't
288  * reformat it.
289  */
290 static int
291 MyEnhancedXkbTranslateKeyCode(struct xkb_desc *       xkb,
292                               KeyCode                 key,
293                               unsigned int            mods,
294                               unsigned int *          mods_rtrn,
295                               uint32_t *              keysym_rtrn,
296                               int *                   group_rtrn,
297                               int *                   level_rtrn)
298 {
299     struct xkb_key_type *type;
300     int col,nKeyGroups;
301     unsigned preserve,effectiveGroup;
302     uint32_t *syms;
303
304     if (mods_rtrn!=NULL)
305         *mods_rtrn = 0;
306
307     nKeyGroups= XkbKeyNumGroups(xkb,key);
308     if ((!XkbKeycodeInRange(xkb,key))||(nKeyGroups==0)) {
309         if (keysym_rtrn!=NULL)
310             *keysym_rtrn = 0;
311         return 0;
312     }
313
314     syms = XkbKeySymsPtr(xkb,key);
315
316     /* find the offset of the effective group */
317     col = 0;
318     effectiveGroup= XkbGroupForCoreState(mods);
319     if ( effectiveGroup>=nKeyGroups ) {
320         unsigned groupInfo= XkbKeyGroupInfo(xkb,key);
321         switch (XkbOutOfRangeGroupAction(groupInfo)) {
322             default:
323                 effectiveGroup %= nKeyGroups;
324                 break;
325             case XkbClampIntoRange:
326                 effectiveGroup = nKeyGroups-1;
327                 break;
328             case XkbRedirectIntoRange:
329                 effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo);
330                 if (effectiveGroup>=nKeyGroups)
331                     effectiveGroup= 0;
332                 break;
333         }
334     }
335     col= effectiveGroup*XkbKeyGroupsWidth(xkb,key);
336     type = XkbKeyKeyType(xkb,key,effectiveGroup);
337
338     preserve= 0;
339     if (type->map) { /* find the column (shift level) within the group */
340         register int i;
341         struct xkb_kt_map_entry *entry;
342         /* ---- Begin section modified for GDK  ---- */
343         int found = 0;
344
345         for (i=0,entry=type->map;i<type->map_count;i++,entry++) {
346             if (mods_rtrn) {
347                 int bits = 0;
348                 unsigned long tmp = entry->mods.mask;
349                 while (tmp) {
350                     if ((tmp & 1) == 1)
351                         bits++;
352                     tmp >>= 1;
353                 }
354                 /* We always add one-modifiers levels to mods_rtrn since
355                  * they can't wipe out bits in the state unless the
356                  * level would be triggered. But return other modifiers
357                  *
358                  */
359                 if (bits == 1 || (mods&type->mods.mask)==entry->mods.mask)
360                     *mods_rtrn |= entry->mods.mask;
361             }
362
363             if (!found&&entry->active&&((mods&type->mods.mask)==entry->mods.mask)) {
364                 col+= entry->level;
365                 if (type->preserve)
366                     preserve= type->preserve[i].mask;
367
368                 if (level_rtrn)
369                   *level_rtrn = entry->level;
370
371                 found = 1;
372             }
373         }
374         /* ---- End section modified for GDK ---- */
375     }
376
377     if (keysym_rtrn!=NULL)
378         *keysym_rtrn= syms[col];
379     if (mods_rtrn) {
380         /* ---- Begin section modified for GDK  ---- */
381         *mods_rtrn &= ~preserve;
382         /* ---- End section modified for GDK ---- */
383
384         /* ---- Begin stuff GDK comments out of the original Xlib version ---- */
385         /* This is commented out because xkb_info is a private struct */
386
387 #if 0
388         /* The Motif VTS doesn't get the help callback called if help
389          * is bound to Shift+<whatever>, and it appears as though it
390          * is XkbTranslateKeyCode that is causing the problem.  The
391          * core X version of XTranslateKey always OR's in ShiftMask
392          * and LockMask for mods_rtrn, so this "fix" keeps this behavior
393          * and solves the VTS problem.
394          */
395         if ((xkb->dpy)&&(xkb->dpy->xkb_info)&&
396             (xkb->dpy->xkb_info->xlib_ctrls&XkbLC_AlwaysConsumeShiftAndLock)) {            *mods_rtrn|= (ShiftMask|LockMask);
397         }
398 #endif
399
400         /* ---- End stuff GDK comments out of the original Xlib version ---- */
401     }
402
403     /* ---- Begin stuff GDK adds to the original Xlib version ---- */
404
405     if (group_rtrn)
406       *group_rtrn = effectiveGroup;
407
408     /* ---- End stuff GDK adds to the original Xlib version ---- */
409
410     return (syms[col] != 0);
411 }
412 #endif
413
414 static gboolean
415 gdk_wayland_keymap_translate_keyboard_state (GdkKeymap       *keymap,
416                                              guint            hardware_keycode,
417                                              GdkModifierType  state,
418                                              gint             group,
419                                              guint           *keyval,
420                                              gint            *effective_group,
421                                              gint            *level,
422                                              GdkModifierType *consumed_modifiers)
423 {
424 #if 0
425   GdkWaylandKeymap *wayland_keymap;
426   uint32_t tmp_keyval = 0;
427   guint tmp_modifiers;
428   struct xkb_desc *xkb;
429
430   g_return_val_if_fail (keymap == NULL || GDK_IS_KEYMAP (keymap), FALSE);
431   g_return_val_if_fail (group < 4, FALSE);
432
433   wayland_keymap = GDK_WAYLAND_KEYMAP (keymap);
434   xkb = wayland_keymap->xkb;
435
436   if (keyval)
437     *keyval = 0;
438   if (effective_group)
439     *effective_group = 0;
440   if (level)
441     *level = 0;
442   if (consumed_modifiers)
443     *consumed_modifiers = 0;
444
445   if (hardware_keycode < xkb->min_key_code ||
446       hardware_keycode > xkb->max_key_code)
447     return FALSE;
448
449
450   /* replace bits 13 and 14 with the provided group */
451   state &= ~(1 << 13 | 1 << 14);
452   state |= group << 13;
453
454   MyEnhancedXkbTranslateKeyCode (xkb,
455                                  hardware_keycode,
456                                  state,
457                                  &tmp_modifiers,
458                                  &tmp_keyval,
459                                  effective_group,
460                                  level);
461
462   if (state & ~tmp_modifiers & XKB_COMMON_LOCK_MASK)
463     tmp_keyval = gdk_keyval_to_upper (tmp_keyval);
464
465   /* We need to augment the consumed modifiers with LockMask, since
466    * we handle that ourselves, and also with the group bits
467    */
468   tmp_modifiers |= XKB_COMMON_LOCK_MASK | 1 << 13 | 1 << 14;
469
470
471   if (consumed_modifiers)
472     *consumed_modifiers = tmp_modifiers;
473
474   if (keyval)
475     *keyval = tmp_keyval;
476
477   return tmp_keyval != 0;
478 #endif
479   return FALSE;
480 }
481
482 #if 0
483 static void
484 update_modmap (GdkWaylandKeymap *wayland_keymap)
485 {
486   static struct {
487     const gchar *name;
488     uint32_t atom;
489     GdkModifierType mask;
490   } vmods[] = {
491     { "Meta", 0, GDK_META_MASK },
492     { "Super", 0, GDK_SUPER_MASK },
493     { "Hyper", 0, GDK_HYPER_MASK },
494     { NULL, 0, 0 }
495   };
496
497   gint i, j, k;
498
499   if (!vmods[0].atom)
500     for (i = 0; vmods[i].name; i++)
501       vmods[i].atom = xkb_atom(vmods[i].name);
502
503   for (i = 0; i < 8; i++)
504     wayland_keymap->modmap[i] = 1 << i;
505
506   for (i = 0; i < XkbNumVirtualMods; i++)
507     {
508       for (j = 0; vmods[j].atom; j++)
509         {
510           if (wayland_keymap->xkb->names->vmods[i] == vmods[j].atom)
511             {
512               for (k = 0; k < 8; k++)
513                 {
514                   if (wayland_keymap->xkb->server->vmods[i] & (1 << k))
515                     wayland_keymap->modmap[k] |= vmods[j].mask;
516                 }
517             }
518         }
519     }
520 }
521 #endif
522
523 static void
524 gdk_wayland_keymap_add_virtual_modifiers (GdkKeymap       *keymap,
525                                           GdkModifierType *state)
526 {
527   GdkWaylandKeymap *wayland_keymap;
528   int i;
529
530   wayland_keymap = GDK_WAYLAND_KEYMAP (keymap);
531
532   for (i = 4; i < 8; i++)
533     {
534       if ((1 << i) & *state)
535         {
536           if (wayland_keymap->modmap[i] & GDK_SUPER_MASK)
537             *state |= GDK_SUPER_MASK;
538           if (wayland_keymap->modmap[i] & GDK_HYPER_MASK)
539             *state |= GDK_HYPER_MASK;
540           if (wayland_keymap->modmap[i] & GDK_META_MASK)
541             *state |= GDK_META_MASK;
542         }
543     }
544 }
545
546 static gboolean
547 gdk_wayland_keymap_map_virtual_modifiers (GdkKeymap       *keymap,
548                                           GdkModifierType *state)
549 {
550   const guint vmods[] = {
551     GDK_SUPER_MASK, GDK_HYPER_MASK, GDK_META_MASK
552   };
553   int i, j;
554   GdkWaylandKeymap *wayland_keymap;
555   gboolean retval = TRUE;
556
557   wayland_keymap = GDK_WAYLAND_KEYMAP (keymap);
558
559   for (j = 0; j < 3; j++)
560     {
561       if (*state & vmods[j])
562         {
563           for (i = 4; i < 8; i++)
564             {
565               if (wayland_keymap->modmap[i] & vmods[j])
566                 {
567                   if (*state & (1 << i))
568                     retval = FALSE;
569                   else
570                     *state |= 1 << i;
571                 }
572             }
573         }
574     }
575
576   return retval;
577 }
578
579 static void
580 _gdk_wayland_keymap_class_init (GdkWaylandKeymapClass *klass)
581 {
582   GObjectClass *object_class = G_OBJECT_CLASS (klass);
583   GdkKeymapClass *keymap_class = GDK_KEYMAP_CLASS (klass);
584
585   object_class->finalize = gdk_wayland_keymap_finalize;
586
587   keymap_class->get_direction = gdk_wayland_keymap_get_direction;
588   keymap_class->have_bidi_layouts = gdk_wayland_keymap_have_bidi_layouts;
589   keymap_class->get_caps_lock_state = gdk_wayland_keymap_get_caps_lock_state;
590   keymap_class->get_num_lock_state = gdk_wayland_keymap_get_num_lock_state;
591   keymap_class->get_entries_for_keyval = gdk_wayland_keymap_get_entries_for_keyval;
592   keymap_class->get_entries_for_keycode = gdk_wayland_keymap_get_entries_for_keycode;
593   keymap_class->lookup_key = gdk_wayland_keymap_lookup_key;
594   keymap_class->translate_keyboard_state = gdk_wayland_keymap_translate_keyboard_state;
595   keymap_class->add_virtual_modifiers = gdk_wayland_keymap_add_virtual_modifiers;
596   keymap_class->map_virtual_modifiers = gdk_wayland_keymap_map_virtual_modifiers;
597 }
598
599 static void
600 _gdk_wayland_keymap_init (GdkWaylandKeymap *keymap)
601 {
602 }
603
604 #if 0
605 static void
606 update_keymaps (GdkWaylandKeymap *keymap)
607 {
608   struct xkb_desc *xkb = keymap->xkb;
609   gint keycode, total_syms, i, modifier;
610   uint32_t *entry;
611   guint mask;
612
613   for (keycode = xkb->min_key_code; keycode <= xkb->max_key_code; keycode++)
614     {
615       total_syms = XkbKeyNumSyms (xkb, keycode);
616
617       entry = XkbKeySymsPtr (xkb, keycode);
618       mask = 0;
619       for (i = 0; i < total_syms; i++)
620         {
621           switch (entry[i]) {
622           case GDK_KEY_Meta_L:
623           case GDK_KEY_Meta_R:
624             mask |= GDK_META_MASK;
625             break;
626           case GDK_KEY_Hyper_L:
627           case GDK_KEY_Hyper_R:
628             mask |= GDK_HYPER_MASK;
629             break;
630           case GDK_KEY_Super_L:
631           case GDK_KEY_Super_R:
632             mask |= GDK_SUPER_MASK;
633             break;
634           }
635         }
636
637       modifier = g_bit_nth_lsf(xkb->map->modmap[keycode], -1);
638       keymap->modmap[modifier] |= mask;
639     }
640 }
641 #endif
642
643 GdkKeymap *
644 _gdk_wayland_keymap_new ()
645 {
646   GdkWaylandKeymap *keymap;
647   struct xkb_context *context;
648   struct xkb_rule_names names;
649
650   keymap = g_object_new (_gdk_wayland_keymap_get_type(), NULL);
651
652   context = xkb_context_new (0);
653
654   names.rules = "evdev";
655   names.model = "pc105";
656   names.layout = "us";
657   names.variant = "";
658   names.options = "";
659   keymap->xkb_keymap = xkb_map_new_from_names(context, &names, XKB_MAP_COMPILE_PLACEHOLDER);
660   keymap->xkb_state = xkb_state_new (keymap->xkb_keymap);
661   xkb_context_unref (context);
662
663   return GDK_KEYMAP (keymap);
664 }
665
666 GdkKeymap *
667 _gdk_wayland_keymap_new_from_fd (uint32_t format,
668                                  uint32_t fd, uint32_t size)
669 {
670   GdkWaylandKeymap *keymap;
671   struct xkb_context *context;
672   char *map_str;
673
674   keymap = g_object_new (_gdk_wayland_keymap_get_type(), NULL);
675
676   context = xkb_context_new (0);
677
678   map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
679   if (map_str == MAP_FAILED) {
680     close(fd);
681     return NULL;
682   }
683
684   keymap->xkb_keymap = xkb_map_new_from_string (context, map_str, format, XKB_MAP_COMPILE_PLACEHOLDER);
685   munmap (map_str, size);
686   close (fd);
687   keymap->xkb_state = xkb_state_new (keymap->xkb_keymap);
688   xkb_context_unref (context);
689
690   return GDK_KEYMAP (keymap);
691 }
692
693 struct xkb_keymap *_gdk_wayland_keymap_get_xkb_keymap (GdkKeymap *keymap)
694 {
695   return GDK_WAYLAND_KEYMAP (keymap)->xkb_keymap;
696 }
697
698 struct xkb_state *_gdk_wayland_keymap_get_xkb_state (GdkKeymap *keymap)
699 {
700   return GDK_WAYLAND_KEYMAP (keymap)->xkb_state;
701 }