keybindings: handle multiple keycodes for keysym

A single keysym can resolve to multiple keycodes. Instead of only using
the first one and ignoring the others, we store all codes in
MetaResolvedKeyCombo and then handle all of them in keybinding
resolution. If we already have bound a keycode for a keybinding with a
specific keysym then this can get overwritten by a new keybinding with a
different keysym that resolves to the same keycode. Now that we resolve
and bind all keycodes for a keysym this might happen more often; in that
case warn but still overwrite, but only for the first keycode for each
keysym. If a secondary (i.e. all non-first keycodes) is already indexed
we just ignore that; this should resemble the old behavior  where we
only took the first keycode for any keysym as close as possible.

https://bugzilla.gnome.org/show_bug.cgi?id=781223
This commit is contained in:
Christian Kellner 2017-04-25 13:17:02 +02:00
parent dd82f4afcd
commit 68dacb531b
2 changed files with 233 additions and 176 deletions

View File

@ -44,7 +44,8 @@ struct _MetaKeyHandler
}; };
typedef struct _MetaResolvedKeyCombo { typedef struct _MetaResolvedKeyCombo {
xkb_keycode_t keycode; xkb_keycode_t *keycodes;
int len;
xkb_mod_mask_t mask; xkb_mod_mask_t mask;
} MetaResolvedKeyCombo; } MetaResolvedKeyCombo;
@ -102,7 +103,7 @@ typedef struct
MetaKeyCombo overlay_key_combo; MetaKeyCombo overlay_key_combo;
MetaResolvedKeyCombo overlay_resolved_key_combo; MetaResolvedKeyCombo overlay_resolved_key_combo;
gboolean overlay_key_only_pressed; gboolean overlay_key_only_pressed;
MetaResolvedKeyCombo *iso_next_group_combos; MetaResolvedKeyCombo iso_next_group_combo[2];
int n_iso_next_group_combos; int n_iso_next_group_combos;
xkb_level_index_t keymap_num_levels; xkb_level_index_t keymap_num_levels;

View File

@ -64,16 +64,63 @@ static gboolean add_builtin_keybinding (MetaDisplay *display,
MetaKeyHandlerFunc handler, MetaKeyHandlerFunc handler,
int handler_arg); int handler_arg);
static void
resolved_key_combo_reset (MetaResolvedKeyCombo *resolved_combo)
{
g_free (resolved_combo->keycodes);
resolved_combo->len = 0;
resolved_combo->keycodes = NULL;
}
static void
resolved_key_combo_copy (MetaResolvedKeyCombo *from,
MetaResolvedKeyCombo *to)
{
to->len = from->len;
to->keycodes = g_memdup (from->keycodes,
from->len * sizeof (xkb_keycode_t));
}
static gboolean
resolved_key_combo_has_keycode (MetaResolvedKeyCombo *resolved_combo,
int keycode)
{
int i;
for (i = 0; i < resolved_combo->len; i++)
if ((int) resolved_combo->keycodes[i] == keycode)
return TRUE;
return FALSE;
}
static gboolean
resolved_key_combo_intersect (MetaResolvedKeyCombo *a,
MetaResolvedKeyCombo *b)
{
int i;
for (i = 0; i < a->len; i++)
if (resolved_key_combo_has_keycode (b, a->keycodes[i]))
return TRUE;
return FALSE;
}
static void static void
meta_key_binding_free (MetaKeyBinding *binding) meta_key_binding_free (MetaKeyBinding *binding)
{ {
resolved_key_combo_reset (&binding->resolved_combo);
g_slice_free (MetaKeyBinding, binding); g_slice_free (MetaKeyBinding, binding);
} }
static MetaKeyBinding * static MetaKeyBinding *
meta_key_binding_copy (MetaKeyBinding *binding) meta_key_binding_copy (MetaKeyBinding *binding)
{ {
return g_slice_dup (MetaKeyBinding, binding); MetaKeyBinding *clone = g_slice_dup (MetaKeyBinding, binding);
resolved_key_combo_copy (&binding->resolved_combo,
&clone->resolved_combo);
return clone;
} }
G_DEFINE_BOXED_TYPE(MetaKeyBinding, G_DEFINE_BOXED_TYPE(MetaKeyBinding,
@ -163,7 +210,8 @@ meta_key_grab_free (MetaKeyGrab *grab)
} }
static guint32 static guint32
key_combo_key (MetaResolvedKeyCombo *resolved_combo) key_combo_key (MetaResolvedKeyCombo *resolved_combo,
int i)
{ {
/* On X, keycodes are only 8 bits while libxkbcommon supports 32 bit /* On X, keycodes are only 8 bits while libxkbcommon supports 32 bit
keycodes, but since we're using the same XKB keymaps that X uses, keycodes, but since we're using the same XKB keymaps that X uses,
@ -173,7 +221,7 @@ key_combo_key (MetaResolvedKeyCombo *resolved_combo)
can use a 32 bit integer to safely concatenate both keycode and can use a 32 bit integer to safely concatenate both keycode and
mask and thus making it easy to use them as an index in a mask and thus making it easy to use them as an index in a
GHashTable. */ GHashTable. */
guint32 key = resolved_combo->keycode & 0xffff; guint32 key = resolved_combo->keycodes[i] & 0xffff;
return (key << 16) | (resolved_combo->mask & 0xffff); return (key << 16) | (resolved_combo->mask & 0xffff);
} }
@ -274,21 +322,34 @@ get_keycodes_for_keysym_iter (struct xkb_keymap *keymap,
xkb_level_index_t level = search_data->level; xkb_level_index_t level = search_data->level;
if (is_keycode_for_keysym (keymap, layout, level, keycode, keysym)) if (is_keycode_for_keysym (keymap, layout, level, keycode, keysym))
g_array_append_val (keycodes, keycode); {
guint i;
gboolean missing = TRUE;
/* duplicate keycode detection */
for (i = 0; i < keycodes->len; i++)
if (g_array_index (keycodes, xkb_keysym_t, i) == keycode)
{
missing = FALSE;
break;
}
if (missing)
g_array_append_val (keycodes, keycode);
}
} }
/* Original code from gdk_x11_keymap_get_entries_for_keyval() in /* Original code from gdk_x11_keymap_get_entries_for_keyval() in
* gdkkeys-x11.c */ * gdkkeys-x11.c */
static int static void
get_keycodes_for_keysym (MetaKeyBindingManager *keys, get_keycodes_for_keysym (MetaKeyBindingManager *keys,
int keysym, int keysym,
int **keycodes) MetaResolvedKeyCombo *resolved_combo)
{ {
GArray *retval; GArray *retval;
int n_keycodes;
int keycode; int keycode;
retval = g_array_new (FALSE, FALSE, sizeof (int)); retval = g_array_new (FALSE, FALSE, sizeof (xkb_keysym_t));
/* Special-case: Fake mutter keysym */ /* Special-case: Fake mutter keysym */
if (keysym == META_KEY_ABOVE_TAB) if (keysym == META_KEY_ABOVE_TAB)
@ -313,28 +374,8 @@ get_keycodes_for_keysym (MetaKeyBindingManager *keys,
} }
out: out:
n_keycodes = retval->len; resolved_combo->len = retval->len;
*keycodes = (int*) g_array_free (retval, n_keycodes == 0 ? TRUE : FALSE); resolved_combo->keycodes = (xkb_keycode_t *) g_array_free (retval, retval->len == 0 ? TRUE : FALSE);
return n_keycodes;
}
static guint
get_first_keycode_for_keysym (MetaKeyBindingManager *keys,
guint keysym)
{
int *keycodes;
int n_keycodes;
int keycode;
n_keycodes = get_keycodes_for_keysym (keys, keysym, &keycodes);
if (n_keycodes > 0)
keycode = keycodes[0];
else
keycode = 0;
g_free (keycodes);
return keycode;
} }
static void static void
@ -367,20 +408,23 @@ static void
reload_iso_next_group_combos (MetaKeyBindingManager *keys) reload_iso_next_group_combos (MetaKeyBindingManager *keys)
{ {
const char *iso_next_group_option; const char *iso_next_group_option;
MetaResolvedKeyCombo *combos;
int *keycodes;
int n_keycodes;
int n_combos;
int i; int i;
g_clear_pointer (&keys->iso_next_group_combos, g_free); for (i = 0; i < keys->n_iso_next_group_combos; i++)
resolved_key_combo_reset (&keys->iso_next_group_combo[i]);
keys->n_iso_next_group_combos = 0; keys->n_iso_next_group_combos = 0;
iso_next_group_option = meta_prefs_get_iso_next_group_option (); iso_next_group_option = meta_prefs_get_iso_next_group_option ();
if (iso_next_group_option == NULL) if (iso_next_group_option == NULL)
return; return;
n_keycodes = get_keycodes_for_keysym (keys, XKB_KEY_ISO_Next_Group, &keycodes); get_keycodes_for_keysym (keys, XKB_KEY_ISO_Next_Group, keys->iso_next_group_combo);
if (keys->iso_next_group_combo[0].len == 0)
return;
keys->n_iso_next_group_combos = 1;
if (g_str_equal (iso_next_group_option, "toggle") || if (g_str_equal (iso_next_group_option, "toggle") ||
g_str_equal (iso_next_group_option, "lalt_toggle") || g_str_equal (iso_next_group_option, "lalt_toggle") ||
@ -394,94 +438,53 @@ reload_iso_next_group_combos (MetaKeyBindingManager *keys)
g_str_equal (iso_next_group_option, "menu_toggle") || g_str_equal (iso_next_group_option, "menu_toggle") ||
g_str_equal (iso_next_group_option, "caps_toggle")) g_str_equal (iso_next_group_option, "caps_toggle"))
{ {
n_combos = n_keycodes; keys->iso_next_group_combo[0].mask = 0;
combos = g_new (MetaResolvedKeyCombo, n_combos);
for (i = 0; i < n_keycodes; ++i)
{
combos[i].keycode = keycodes[i];
combos[i].mask = 0;
}
} }
else if (g_str_equal (iso_next_group_option, "shift_caps_toggle") || else if (g_str_equal (iso_next_group_option, "shift_caps_toggle") ||
g_str_equal (iso_next_group_option, "shifts_toggle")) g_str_equal (iso_next_group_option, "shifts_toggle"))
{ {
n_combos = n_keycodes; keys->iso_next_group_combo[0].mask = ShiftMask;
combos = g_new (MetaResolvedKeyCombo, n_combos);
for (i = 0; i < n_keycodes; ++i)
{
combos[i].keycode = keycodes[i];
combos[i].mask = ShiftMask;
}
} }
else if (g_str_equal (iso_next_group_option, "alt_caps_toggle") || else if (g_str_equal (iso_next_group_option, "alt_caps_toggle") ||
g_str_equal (iso_next_group_option, "alt_space_toggle")) g_str_equal (iso_next_group_option, "alt_space_toggle"))
{ {
n_combos = n_keycodes; keys->iso_next_group_combo[0].mask = Mod1Mask;
combos = g_new (MetaResolvedKeyCombo, n_combos);
for (i = 0; i < n_keycodes; ++i)
{
combos[i].keycode = keycodes[i];
combos[i].mask = Mod1Mask;
}
} }
else if (g_str_equal (iso_next_group_option, "ctrl_shift_toggle") || else if (g_str_equal (iso_next_group_option, "ctrl_shift_toggle") ||
g_str_equal (iso_next_group_option, "lctrl_lshift_toggle") || g_str_equal (iso_next_group_option, "lctrl_lshift_toggle") ||
g_str_equal (iso_next_group_option, "rctrl_rshift_toggle")) g_str_equal (iso_next_group_option, "rctrl_rshift_toggle"))
{ {
n_combos = n_keycodes * 2; resolved_key_combo_copy (&keys->iso_next_group_combo[0],
combos = g_new (MetaResolvedKeyCombo, n_combos); &keys->iso_next_group_combo[1]);
for (i = 0; i < n_keycodes; ++i) keys->iso_next_group_combo[0].mask = ShiftMask;
{ keys->iso_next_group_combo[1].mask = ControlMask;
combos[i].keycode = keycodes[i]; keys->n_iso_next_group_combos = 2;
combos[i].mask = ShiftMask;
combos[i + n_keycodes].keycode = keycodes[i];
combos[i + n_keycodes].mask = ControlMask;
}
} }
else if (g_str_equal (iso_next_group_option, "ctrl_alt_toggle")) else if (g_str_equal (iso_next_group_option, "ctrl_alt_toggle"))
{ {
n_combos = n_keycodes * 2; resolved_key_combo_copy (&keys->iso_next_group_combo[0],
combos = g_new (MetaResolvedKeyCombo, n_combos); &keys->iso_next_group_combo[1]);
for (i = 0; i < n_keycodes; ++i) keys->iso_next_group_combo[0].mask = Mod1Mask;
{ keys->iso_next_group_combo[1].mask = ControlMask;
combos[i].keycode = keycodes[i]; keys->n_iso_next_group_combos = 2;
combos[i].mask = Mod1Mask;
combos[i + n_keycodes].keycode = keycodes[i];
combos[i + n_keycodes].mask = ControlMask;
}
} }
else if (g_str_equal (iso_next_group_option, "alt_shift_toggle") || else if (g_str_equal (iso_next_group_option, "alt_shift_toggle") ||
g_str_equal (iso_next_group_option, "lalt_lshift_toggle")) g_str_equal (iso_next_group_option, "lalt_lshift_toggle"))
{ {
n_combos = n_keycodes * 2; resolved_key_combo_copy (&keys->iso_next_group_combo[0],
combos = g_new (MetaResolvedKeyCombo, n_combos); &keys->iso_next_group_combo[1]);
for (i = 0; i < n_keycodes; ++i) keys->iso_next_group_combo[0].mask = Mod1Mask;
{ keys->iso_next_group_combo[1].mask = ShiftMask;
combos[i].keycode = keycodes[i]; keys->n_iso_next_group_combos = 2;
combos[i].mask = Mod1Mask;
combos[i + n_keycodes].keycode = keycodes[i];
combos[i + n_keycodes].mask = ShiftMask;
}
} }
else else
{ {
n_combos = 0; resolved_key_combo_reset (keys->iso_next_group_combo);
combos = NULL; keys->n_iso_next_group_combos = 0;
} }
g_free (keycodes);
keys->n_iso_next_group_combos = n_combos;
keys->iso_next_group_combos = combos;
} }
static void static void
@ -517,11 +520,35 @@ static void
index_binding (MetaKeyBindingManager *keys, index_binding (MetaKeyBindingManager *keys,
MetaKeyBinding *binding) MetaKeyBinding *binding)
{ {
guint32 index_key; int i;
index_key = key_combo_key (&binding->resolved_combo); for (i = 0; i < binding->resolved_combo.len; i++)
g_hash_table_replace (keys->key_bindings_index, {
GINT_TO_POINTER (index_key), binding); MetaKeyBinding *existing;
guint32 index_key;
index_key = key_combo_key (&binding->resolved_combo, i);
existing = g_hash_table_lookup (keys->key_bindings_index,
GINT_TO_POINTER (index_key));
if (existing != NULL)
{
/* Overwrite already indexed keycodes only for the first
* keycode, i.e. we give those primary keycodes precedence
* over non-first ones. */
if (i > 0)
continue;
meta_warning ("Overwriting existing binding of keysym %x"
" with keysym %x (keycode %x).\n",
binding->combo.keysym,
existing->combo.keysym,
binding->resolved_combo.keycodes[i]);
}
g_hash_table_replace (keys->key_bindings_index,
GINT_TO_POINTER (index_key), binding);
}
} }
static void static void
@ -529,10 +556,19 @@ resolve_key_combo (MetaKeyBindingManager *keys,
MetaKeyCombo *combo, MetaKeyCombo *combo,
MetaResolvedKeyCombo *resolved_combo) MetaResolvedKeyCombo *resolved_combo)
{ {
resolved_key_combo_reset (resolved_combo);
if (combo->keysym != 0) if (combo->keysym != 0)
resolved_combo->keycode = get_first_keycode_for_keysym (keys, combo->keysym); {
else get_keycodes_for_keysym (keys, combo->keysym, resolved_combo);
resolved_combo->keycode = combo->keycode; }
else if (combo->keycode != 0)
{
resolved_combo->keycodes = g_new0 (xkb_keycode_t, 1);
resolved_combo->keycodes[0] = combo->keycode;
resolved_combo->len = 1;
}
devirtualize_modifiers (keys, combo->modifiers, &resolved_combo->mask); devirtualize_modifiers (keys, combo->modifiers, &resolved_combo->mask);
} }
@ -691,9 +727,22 @@ static MetaKeyBinding *
get_keybinding (MetaKeyBindingManager *keys, get_keybinding (MetaKeyBindingManager *keys,
MetaResolvedKeyCombo *resolved_combo) MetaResolvedKeyCombo *resolved_combo)
{ {
guint32 key; MetaKeyBinding *binding = NULL;
key = key_combo_key (resolved_combo); int i;
return g_hash_table_lookup (keys->key_bindings_index, GINT_TO_POINTER (key));
for (i = 0; i < resolved_combo->len; i++)
{
guint32 key;
key = key_combo_key (resolved_combo, i);
binding = g_hash_table_lookup (keys->key_bindings_index,
GINT_TO_POINTER (key));
if (binding != NULL)
break;
}
return binding;
} }
static guint static guint
@ -823,7 +872,8 @@ get_keybinding_action (MetaKeyBindingManager *keys,
* of mutter keybindings while holding a grab, the overlay-key-only-pressed * of mutter keybindings while holding a grab, the overlay-key-only-pressed
* tracking is left to the plugin here. * tracking is left to the plugin here.
*/ */
if (resolved_combo->keycode == (unsigned int)keys->overlay_resolved_key_combo.keycode) if (resolved_key_combo_intersect (resolved_combo,
&keys->overlay_resolved_key_combo))
return META_KEYBINDING_ACTION_OVERLAY_KEY; return META_KEYBINDING_ACTION_OVERLAY_KEY;
binding = get_keybinding (keys, resolved_combo); binding = get_keybinding (keys, resolved_combo);
@ -841,14 +891,11 @@ get_keybinding_action (MetaKeyBindingManager *keys,
} }
} }
static void static xkb_mod_mask_t
resolved_combo_from_event_params (MetaResolvedKeyCombo *resolved_combo, mask_from_event_params (MetaKeyBindingManager *keys,
MetaKeyBindingManager *keys, unsigned long mask)
unsigned int keycode,
unsigned long mask)
{ {
resolved_combo->keycode = keycode; return mask & 0xff & ~keys->ignored_modifier_mask;
resolved_combo->mask = mask & 0xff & ~keys->ignored_modifier_mask;
} }
/** /**
@ -871,8 +918,10 @@ meta_display_get_keybinding_action (MetaDisplay *display,
unsigned long mask) unsigned long mask)
{ {
MetaKeyBindingManager *keys = &display->key_binding_manager; MetaKeyBindingManager *keys = &display->key_binding_manager;
MetaResolvedKeyCombo resolved_combo; xkb_keycode_t code = (xkb_keycode_t) keycode;
resolved_combo_from_event_params (&resolved_combo, keys, keycode, mask); MetaResolvedKeyCombo resolved_combo = { &code, 1 };
resolved_combo.mask = mask_from_event_params (keys, mask);
return get_keybinding_action (keys, &resolved_combo); return get_keybinding_action (keys, &resolved_combo);
} }
@ -1165,30 +1214,36 @@ meta_change_keygrab (MetaKeyBindingManager *keys,
MetaBackendX11 *backend = META_BACKEND_X11 (meta_get_backend ()); MetaBackendX11 *backend = META_BACKEND_X11 (meta_get_backend ());
Display *xdisplay = meta_backend_x11_get_xdisplay (backend); Display *xdisplay = meta_backend_x11_get_xdisplay (backend);
GArray *mods; GArray *mods;
int i;
/* Grab keycode/modmask, together with /* Grab keycode/modmask, together with
* all combinations of ignored modifiers. * all combinations of ignored modifiers.
* X provides no better way to do this. * X provides no better way to do this.
*/ */
meta_topic (META_DEBUG_KEYBINDINGS,
"%s keybinding keycode %d mask 0x%x on 0x%lx\n",
grab ? "Grabbing" : "Ungrabbing",
resolved_combo->keycode, resolved_combo->mask, xwindow);
mods = calc_grab_modifiers (keys, resolved_combo->mask); mods = calc_grab_modifiers (keys, resolved_combo->mask);
if (grab) for (i = 0; i < resolved_combo->len; i++)
XIGrabKeycode (xdisplay, {
META_VIRTUAL_CORE_KEYBOARD_ID, xkb_keycode_t keycode = resolved_combo->keycodes[i];
resolved_combo->keycode, xwindow,
XIGrabModeSync, XIGrabModeAsync, meta_topic (META_DEBUG_KEYBINDINGS,
False, &mask, mods->len, (XIGrabModifiers *)mods->data); "%s keybinding keycode %d mask 0x%x on 0x%lx\n",
else grab ? "Grabbing" : "Ungrabbing",
XIUngrabKeycode (xdisplay, keycode, resolved_combo->mask, xwindow);
META_VIRTUAL_CORE_KEYBOARD_ID,
resolved_combo->keycode, xwindow, if (grab)
mods->len, (XIGrabModifiers *)mods->data); XIGrabKeycode (xdisplay,
META_VIRTUAL_CORE_KEYBOARD_ID,
keycode, xwindow,
XIGrabModeSync, XIGrabModeAsync,
False, &mask, mods->len, (XIGrabModifiers *)mods->data);
else
XIUngrabKeycode (xdisplay,
META_VIRTUAL_CORE_KEYBOARD_ID,
keycode, xwindow,
mods->len, (XIGrabModifiers *)mods->data);
}
g_array_free (mods, TRUE); g_array_free (mods, TRUE);
} }
@ -1213,7 +1268,7 @@ change_keygrab_foreach (gpointer key,
if (data->only_per_window != binding_is_per_window) if (data->only_per_window != binding_is_per_window)
return; return;
if (binding->resolved_combo.keycode == 0) if (binding->resolved_combo.len == 0)
return; return;
meta_change_keygrab (data->keys, data->xwindow, data->grab, &binding->resolved_combo); meta_change_keygrab (data->keys, data->xwindow, data->grab, &binding->resolved_combo);
@ -1241,21 +1296,13 @@ meta_screen_change_keygrabs (MetaScreen *screen,
{ {
MetaDisplay *display = screen->display; MetaDisplay *display = screen->display;
MetaKeyBindingManager *keys = &display->key_binding_manager; MetaKeyBindingManager *keys = &display->key_binding_manager;
int i;
if (keys->overlay_resolved_key_combo.keycode != 0) if (keys->overlay_resolved_key_combo.len != 0)
meta_change_keygrab (keys, screen->xroot, grab, &keys->overlay_resolved_key_combo); meta_change_keygrab (keys, screen->xroot, grab, &keys->overlay_resolved_key_combo);
if (keys->iso_next_group_combos) for (i = 0; i < keys->n_iso_next_group_combos; i++)
{ meta_change_keygrab (keys, screen->xroot, grab, &keys->iso_next_group_combo[i]);
int i = 0;
while (i < keys->n_iso_next_group_combos)
{
if (keys->iso_next_group_combos[i].keycode != 0)
meta_change_keygrab (keys, screen->xroot, grab, &keys->iso_next_group_combos[i]);
++i;
}
}
change_binding_keygrabs (keys, screen->xroot, FALSE, grab); change_binding_keygrabs (keys, screen->xroot, FALSE, grab);
} }
@ -1367,7 +1414,7 @@ meta_display_grab_accelerator (MetaDisplay *display,
MetaKeyBinding *binding; MetaKeyBinding *binding;
MetaKeyGrab *grab; MetaKeyGrab *grab;
MetaKeyCombo combo = { 0 }; MetaKeyCombo combo = { 0 };
MetaResolvedKeyCombo resolved_combo = { 0 }; MetaResolvedKeyCombo resolved_combo = { NULL, 0 };
if (!meta_parse_accelerator (accelerator, &combo)) if (!meta_parse_accelerator (accelerator, &combo))
{ {
@ -1380,11 +1427,14 @@ meta_display_grab_accelerator (MetaDisplay *display,
resolve_key_combo (keys, &combo, &resolved_combo); resolve_key_combo (keys, &combo, &resolved_combo);
if (resolved_combo.keycode == 0) if (resolved_combo.len == 0)
return META_KEYBINDING_ACTION_NONE; return META_KEYBINDING_ACTION_NONE;
if (get_keybinding (keys, &resolved_combo)) if (get_keybinding (keys, &resolved_combo))
return META_KEYBINDING_ACTION_NONE; {
resolved_key_combo_reset (&resolved_combo);
return META_KEYBINDING_ACTION_NONE;
}
meta_change_keygrab (keys, display->screen->xroot, TRUE, &resolved_combo); meta_change_keygrab (keys, display->screen->xroot, TRUE, &resolved_combo);
@ -1415,7 +1465,7 @@ meta_display_ungrab_accelerator (MetaDisplay *display,
MetaKeyBinding *binding; MetaKeyBinding *binding;
MetaKeyGrab *grab; MetaKeyGrab *grab;
char *key; char *key;
MetaResolvedKeyCombo resolved_combo; MetaResolvedKeyCombo resolved_combo = { NULL, 0 };
g_return_val_if_fail (action != META_KEYBINDING_ACTION_NONE, FALSE); g_return_val_if_fail (action != META_KEYBINDING_ACTION_NONE, FALSE);
@ -1428,18 +1478,22 @@ meta_display_ungrab_accelerator (MetaDisplay *display,
binding = get_keybinding (keys, &resolved_combo); binding = get_keybinding (keys, &resolved_combo);
if (binding) if (binding)
{ {
guint32 index_key; int i;
meta_change_keygrab (keys, display->screen->xroot, FALSE, &binding->resolved_combo); meta_change_keygrab (keys, display->screen->xroot, FALSE, &binding->resolved_combo);
index_key = key_combo_key (&binding->resolved_combo); for (i = 0; i < binding->resolved_combo.len; i++)
g_hash_table_remove (keys->key_bindings_index, GINT_TO_POINTER (index_key)); {
guint32 index_key = key_combo_key (&binding->resolved_combo, i);
g_hash_table_remove (keys->key_bindings_index, GINT_TO_POINTER (index_key));
}
g_hash_table_remove (keys->key_bindings, binding); g_hash_table_remove (keys->key_bindings, binding);
} }
g_hash_table_remove (external_grabs, key); g_hash_table_remove (external_grabs, key);
g_free (key); g_free (key);
resolved_key_combo_reset (&resolved_combo);
return TRUE; return TRUE;
} }
@ -1645,16 +1699,15 @@ process_event (MetaDisplay *display,
ClutterKeyEvent *event) ClutterKeyEvent *event)
{ {
MetaKeyBindingManager *keys = &display->key_binding_manager; MetaKeyBindingManager *keys = &display->key_binding_manager;
MetaResolvedKeyCombo resolved_combo; xkb_keycode_t keycode = (xkb_keycode_t) event->hardware_keycode;
MetaResolvedKeyCombo resolved_combo = { &keycode, 1 };
MetaKeyBinding *binding; MetaKeyBinding *binding;
/* we used to have release-based bindings but no longer. */ /* we used to have release-based bindings but no longer. */
if (event->type == CLUTTER_KEY_RELEASE) if (event->type == CLUTTER_KEY_RELEASE)
return FALSE; return FALSE;
resolved_combo_from_event_params (&resolved_combo, keys, resolved_combo.mask = mask_from_event_params (keys, event->modifier_state);
event->hardware_keycode,
event->modifier_state);
binding = get_keybinding (keys, &resolved_combo); binding = get_keybinding (keys, &resolved_combo);
@ -1708,7 +1761,8 @@ process_overlay_key (MetaDisplay *display,
if (keys->overlay_key_only_pressed) if (keys->overlay_key_only_pressed)
{ {
if (event->hardware_keycode != (int)keys->overlay_resolved_key_combo.keycode) if (! resolved_key_combo_has_keycode (&keys->overlay_resolved_key_combo,
event->hardware_keycode))
{ {
keys->overlay_key_only_pressed = FALSE; keys->overlay_key_only_pressed = FALSE;
@ -1790,7 +1844,8 @@ process_overlay_key (MetaDisplay *display,
return TRUE; return TRUE;
} }
else if (event->type == CLUTTER_KEY_PRESS && else if (event->type == CLUTTER_KEY_PRESS &&
event->hardware_keycode == (int)keys->overlay_resolved_key_combo.keycode) resolved_key_combo_has_keycode (&keys->overlay_resolved_key_combo,
event->hardware_keycode))
{ {
keys->overlay_key_only_pressed = TRUE; keys->overlay_key_only_pressed = TRUE;
/* We keep the keyboard frozen - this allows us to use ReplayKeyboard /* We keep the keyboard frozen - this allows us to use ReplayKeyboard
@ -1813,30 +1868,31 @@ process_iso_next_group (MetaDisplay *display,
{ {
MetaKeyBindingManager *keys = &display->key_binding_manager; MetaKeyBindingManager *keys = &display->key_binding_manager;
gboolean activate; gboolean activate;
MetaResolvedKeyCombo resolved_combo; xkb_keycode_t keycode = (xkb_keycode_t) event->hardware_keycode;
int i; xkb_mod_mask_t mask;
int i, j;
if (event->type == CLUTTER_KEY_RELEASE) if (event->type == CLUTTER_KEY_RELEASE)
return FALSE; return FALSE;
activate = FALSE; activate = FALSE;
mask = mask_from_event_params (keys, event->modifier_state);
resolved_combo_from_event_params (&resolved_combo, keys,
event->hardware_keycode,
event->modifier_state);
for (i = 0; i < keys->n_iso_next_group_combos; ++i) for (i = 0; i < keys->n_iso_next_group_combos; ++i)
{ {
if (resolved_combo.keycode == keys->iso_next_group_combos[i].keycode && for (j = 0; j < keys->iso_next_group_combo[i].len; ++j)
resolved_combo.mask == keys->iso_next_group_combos[i].mask)
{ {
/* If the signal handler returns TRUE the keyboard will if (keycode == keys->iso_next_group_combo[i].keycodes[j] &&
remain frozen. It's the signal handler's responsibility mask == keys->iso_next_group_combo[i].mask)
to unfreeze it. */ {
if (!meta_display_modifiers_accelerator_activate (display)) /* If the signal handler returns TRUE the keyboard will
meta_display_unfreeze_keyboard (display, event->time); remain frozen. It's the signal handler's responsibility
activate = TRUE; to unfreeze it. */
break; if (!meta_display_modifiers_accelerator_activate (display))
meta_display_unfreeze_keyboard (display, event->time);
activate = TRUE;
break;
}
} }
} }