Commit 03b179c5 authored by Matthias Clasen's avatar Matthias Clasen

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.
parent 60e0183a
......@@ -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
<SUBSECTION>
gdk_keyval_name
......
......@@ -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
......
......@@ -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
*/
......
......@@ -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"
......@@ -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,
/* 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.
*/
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))
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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment