From d1c3745b07fe04814279dfa4a4fd03ca8b244976 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Mon, 21 Dec 2009 11:15:28 -0500 Subject: [PATCH] Try harder to handle accelerators involving virtual modifiers This patch changes GDK to add all matching virtual modifiers in the state field of the key event. The corresponding GTK+ change makes use of a new GdkKeymap function to map virtual modifiers back to real modifiers and detect conflicts while doing so. This should fix bug 603190 and bug 427409. --- docs/reference/gdk/gdk-sections.txt | 1 + gdk/gdk.symbols | 1 + gdk/gdkkeys.h | 2 + gdk/x11/gdkkeys-x11.c | 61 +++++++++++++++++++++++++++-- gtk/gtkkeyhash.c | 29 ++++++++------ 5 files changed, 80 insertions(+), 14 deletions(-) diff --git a/docs/reference/gdk/gdk-sections.txt b/docs/reference/gdk/gdk-sections.txt index 43d000c709..e81c3be566 100644 --- a/docs/reference/gdk/gdk-sections.txt +++ b/docs/reference/gdk/gdk-sections.txt @@ -1005,6 +1005,7 @@ gdk_keymap_get_entries_for_keycode gdk_keymap_get_direction gdk_keymap_have_bidi_layouts gdk_keymap_get_caps_lock_state +gdk_keymap_map_virtual_modifiers gdk_keyval_name diff --git a/gdk/gdk.symbols b/gdk/gdk.symbols index c49568d907..12967c425f 100644 --- a/gdk/gdk.symbols +++ b/gdk/gdk.symbols @@ -852,6 +852,7 @@ gdk_keymap_have_bidi_layouts gdk_keymap_get_caps_lock_state gdk_keymap_lookup_key gdk_keymap_translate_keyboard_state +gdk_keymap_map_virtual_modifiers gdk_keyval_convert_case gdk_keyval_from_name gdk_keyval_name G_GNUC_CONST diff --git a/gdk/gdkkeys.h b/gdk/gdkkeys.h index 63a226620b..6fe55f7bb2 100644 --- a/gdk/gdkkeys.h +++ b/gdk/gdkkeys.h @@ -108,6 +108,8 @@ gboolean gdk_keymap_get_entries_for_keycode (GdkKeymap *keymap, PangoDirection gdk_keymap_get_direction (GdkKeymap *keymap); gboolean gdk_keymap_have_bidi_layouts (GdkKeymap *keymap); gboolean gdk_keymap_get_caps_lock_state (GdkKeymap *keymap); +gboolean gdk_keymap_map_virtual_modifiers (GdkKeymap *keymap, + GdkModifierType *state); /* Key values */ diff --git a/gdk/x11/gdkkeys-x11.c b/gdk/x11/gdkkeys-x11.c index 8cb5b3bcf5..97727c644d 100644 --- a/gdk/x11/gdkkeys-x11.c +++ b/gdk/x11/gdkkeys-x11.c @@ -1672,11 +1672,11 @@ _gdk_keymap_add_virtual_modifiers (GdkKeymap *keymap, { if (keymap_x11->modmap[i] & GDK_MOD1_MASK) *modifiers |= GDK_MOD1_MASK; - else if (keymap_x11->modmap[i] & GDK_SUPER_MASK) + if (keymap_x11->modmap[i] & GDK_SUPER_MASK) *modifiers |= GDK_SUPER_MASK; - else if (keymap_x11->modmap[i] & GDK_HYPER_MASK) + if (keymap_x11->modmap[i] & GDK_HYPER_MASK) *modifiers |= GDK_HYPER_MASK; - else if (keymap_x11->modmap[i] & GDK_META_MASK) + if (keymap_x11->modmap[i] & GDK_META_MASK) *modifiers |= GDK_META_MASK; } } @@ -1717,6 +1717,61 @@ _gdk_keymap_key_is_modifier (GdkKeymap *keymap, return FALSE; } +/* + * gdk_keymap_map_virtual_modifiers: + * @keymap: a #GdkKeymap + * @state: pointer to the modifier state to map + * + * Maps the virtual modifiers (i.e. Super, Hyper and Meta) which + * are set in @state to their non-virtual counterparts (i.e. Mod2, + * Mod3,...) and set the corresponding bits in @state. + * + * This function is useful when matching key events against + * accelerators. + * + * Returns: %TRUE if no virtual modifiers were mapped to the + * same non-virtual modifier. Note that %FALSE is also returned + * if a virtual modifier is mapped to a non-virtual modifier that + * was already set in @state. + * + * Since: 2.20 + */ +gboolean +gdk_keymap_map_virtual_modifiers (GdkKeymap *keymap, + GdkModifierType *state) +{ + GdkKeymapX11 *keymap_x11; + const guint vmods[] = { + GDK_SUPER_MASK, GDK_HYPER_MASK, GDK_META_MASK + }; + int i, j; + gboolean retval; + + keymap = GET_EFFECTIVE_KEYMAP (keymap); + keymap_x11 = GDK_KEYMAP_X11 (keymap); + + retval = TRUE; + + for (j = 0; j < 3; j++) + { + if (*state & vmods[j]) + { + for (i = 3; i < 8; i++) + { + if (keymap_x11->modmap[i] & vmods[j]) + { + if (*state & (1 << i)) + retval = FALSE; + else + *state |= 1 << i; + } + } + } + } + + return retval; +} + #define __GDK_KEYS_X11_C__ #include "gdkaliasdef.c" diff --git a/gtk/gtkkeyhash.c b/gtk/gtkkeyhash.c index 0bd8f16a2e..368699cc18 100644 --- a/gtk/gtkkeyhash.c +++ b/gtk/gtkkeyhash.c @@ -390,12 +390,17 @@ _gtk_key_hash_lookup (GtkKeyHash *key_hash, guint keyval; gint effective_group; gint level; + GdkModifierType modifiers; GdkModifierType consumed_modifiers; + const GdkModifierType xmods = GDK_MOD2_MASK|GDK_MOD3_MASK|GDK_MOD4_MASK|GDK_MOD5_MASK; + const GdkModifierType vmods = GDK_SUPER_MASK|GDK_HYPER_MASK|GDK_META_MASK; /* We don't want Caps_Lock to affect keybinding lookups. */ state &= ~GDK_LOCK_MASK; - + + gdk_keymap_map_virtual_modifiers (key_hash->keymap, &mask); + gdk_keymap_translate_keyboard_state (key_hash->keymap, hardware_keycode, state, group, &keyval, &effective_group, &level, &consumed_modifiers); @@ -411,17 +416,19 @@ _gtk_key_hash_lookup (GtkKeyHash *key_hash, while (tmp_list) { GtkKeyHashEntry *entry = tmp_list->data; - GdkModifierType xmods, vmods; - - /* If the virtual super, hyper or meta modifiers are present, - * they will also be mapped to some of the mod2 - mod5 modifiers, - * so we compare them twice, ignoring either set. - */ - xmods = GDK_MOD2_MASK|GDK_MOD3_MASK|GDK_MOD4_MASK|GDK_MOD5_MASK; - vmods = GDK_SUPER_MASK|GDK_HYPER_MASK|GDK_META_MASK; - if ((entry->modifiers & ~consumed_modifiers & mask) == (state & ~consumed_modifiers & mask & ~vmods) || - (entry->modifiers & ~consumed_modifiers & mask) == (state & ~consumed_modifiers & mask & ~xmods)) + /* If the virtual Super, Hyper or Meta modifiers are present, + * they will also be mapped to some of the Mod2 - Mod5 modifiers, + * so we compare them twice, ignoring either set. + * We accept combinations involving virtual modifiers only if they + * are mapped to separate modifiers; i.e. if Super and Hyper are + * both mapped to Mod4, then pressing a key that is mapped to Mod4 + * will not match a Super+Hyper entry. + */ + modifiers = entry->modifiers; + if (gdk_keymap_map_virtual_modifiers (key_hash->keymap, &modifiers) && + ((modifiers & ~consumed_modifiers & mask & ~vmods) == (state & ~consumed_modifiers & mask & ~vmods) || + (modifiers & ~consumed_modifiers & mask & ~xmods) == (state & ~consumed_modifiers & mask & ~xmods))) { gint i;