diff options
author | Matthias Clasen <mclasen@redhat.com> | 2016-04-15 22:20:25 -0400 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2016-04-15 22:22:48 -0400 |
commit | 64c2a65cc07e8beb11ada231a9f8e13b2e9abbb1 (patch) | |
tree | 1e2184a875f7b4fb4406aa0416b0b5934d5d7761 /gdk/wayland/gdkkeys-wayland.c | |
parent | 101cecf7248f7b1ff7d1f66c782a26832a392dbb (diff) | |
download | gtk+-64c2a65cc07e8beb11ada231a9f8e13b2e9abbb1.tar.gz |
wayland: Implement virtual modifiers
Since Wayland is using libxkbcommon, it inherits X unfortunate
real/virtual modifier distinction, so we have to do the same
gymnastics we do for X to map between the two.
This should fix matching of accelerators using virtual modifiers
(modulo gnome-shell bugs regarding the handling of Super).
https://bugzilla.gnome.org/show_bug.cgi?id=764424
Diffstat (limited to 'gdk/wayland/gdkkeys-wayland.c')
-rw-r--r-- | gdk/wayland/gdkkeys-wayland.c | 52 |
1 files changed, 50 insertions, 2 deletions
diff --git a/gdk/wayland/gdkkeys-wayland.c b/gdk/wayland/gdkkeys-wayland.c index 46d2631046..d73199f42c 100644 --- a/gdk/wayland/gdkkeys-wayland.c +++ b/gdk/wayland/gdkkeys-wayland.c @@ -373,14 +373,62 @@ static void gdk_wayland_keymap_add_virtual_modifiers (GdkKeymap *keymap, GdkModifierType *state) { - return; + struct xkb_keymap *xkb_keymap; + struct xkb_state *xkb_state; + xkb_mod_index_t idx; + uint32_t mods, real; + struct { const char *name; GdkModifierType mask; } vmods[] = { + { "Super", GDK_SUPER_MASK }, + { "Hyper", GDK_HYPER_MASK }, + { "Meta", GDK_META_MASK }, + { NULL, 0 } + }; + int i; + + xkb_keymap = GDK_WAYLAND_KEYMAP (keymap)->xkb_keymap; + mods = get_xkb_modifiers (xkb_keymap, *state); + + xkb_state = xkb_state_new (xkb_keymap); + + for (i = 0; vmods[i].name; i++) + { + idx = xkb_keymap_mod_get_index (xkb_keymap, vmods[i].name); + if (idx == XKB_MOD_INVALID) + continue; + + xkb_state_update_mask (xkb_state, 1 << idx, 0, 0, 0, 0, 0); + real = xkb_state_serialize_mods (xkb_state, XKB_STATE_MODS_EFFECTIVE); + real &= 0xff; + if (mods & real) + *state |= vmods[i].mask; + xkb_state_update_mask (xkb_state, 0, 0, 0, 0, 0, 0); + } + + xkb_state_unref (xkb_state); } static gboolean gdk_wayland_keymap_map_virtual_modifiers (GdkKeymap *keymap, GdkModifierType *state) { - return TRUE; + struct xkb_keymap *xkb_keymap; + struct xkb_state *xkb_state; + uint32_t mods, mapped; + gboolean ret = TRUE; + + xkb_keymap = GDK_WAYLAND_KEYMAP (keymap)->xkb_keymap; + mods = get_xkb_modifiers (xkb_keymap, *state); + + xkb_state = xkb_state_new (xkb_keymap); + xkb_state_update_mask (xkb_state, mods, 0, 0, 0, 0, 0); + mapped = xkb_state_serialize_mods (xkb_state, XKB_STATE_MODS_EFFECTIVE); + if ((mapped & mods & 0xff) != 0) + ret = FALSE; + *state = get_gdk_modifiers (xkb_keymap, mapped); + + xkb_state_unref (xkb_state); + + return ret; } static void |