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