forked from AuroraMiddleware/gtk
shortcuttrigger: Do elaborate matching for key events
Copy the logic from GtkKeyHash for matching key events to shortcuts. Adapt shortcuts test to work with the better matching, by creating more complete key events.
This commit is contained in:
parent
904835d4b1
commit
586e7749d5
@ -40,6 +40,7 @@
|
||||
#include "gtkshortcuttrigger.h"
|
||||
|
||||
#include "gtkaccelgroupprivate.h"
|
||||
#include "gtkprivate.h"
|
||||
|
||||
typedef struct _GtkShortcutTriggerClass GtkShortcutTriggerClass;
|
||||
|
||||
@ -499,25 +500,99 @@ gtk_keyval_trigger_trigger (GtkShortcutTrigger *trigger,
|
||||
gboolean enable_mnemonics)
|
||||
{
|
||||
GtkKeyvalTrigger *self = (GtkKeyvalTrigger *) trigger;
|
||||
GdkModifierType modifiers;
|
||||
guint keycode;
|
||||
GdkModifierType state;
|
||||
GdkModifierType mask;
|
||||
int group;
|
||||
GdkKeymap *keymap;
|
||||
guint keyval;
|
||||
int effective_group;
|
||||
int level;
|
||||
GdkModifierType consumed_modifiers;
|
||||
GdkModifierType shift_group_mask;
|
||||
gboolean group_mod_is_accel_mod = FALSE;
|
||||
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;
|
||||
GdkModifierType modifiers;
|
||||
|
||||
if (gdk_event_get_event_type (event) != GDK_KEY_PRESS)
|
||||
return GTK_SHORTCUT_TRIGGER_MATCH_NONE;
|
||||
|
||||
/* XXX: This needs to deal with groups */
|
||||
modifiers = gdk_event_get_modifier_state (event);
|
||||
keyval = gdk_key_event_get_keyval (event);
|
||||
mask = gtk_accelerator_get_default_mod_mask ();
|
||||
|
||||
if (keyval == GDK_KEY_ISO_Left_Tab)
|
||||
keyval = GDK_KEY_Tab;
|
||||
else
|
||||
keyval = gdk_keyval_to_lower (keyval);
|
||||
keycode = gdk_key_event_get_keycode (event);
|
||||
state = gdk_event_get_modifier_state (event);
|
||||
group = gdk_key_event_get_group (event);
|
||||
keymap = gdk_display_get_keymap (gdk_event_get_display (event));
|
||||
|
||||
if (keyval != self->keyval || modifiers != self->modifiers)
|
||||
return GTK_SHORTCUT_TRIGGER_MATCH_NONE;
|
||||
/* We don't want Caps_Lock to affect keybinding lookups.
|
||||
*/
|
||||
state &= ~GDK_LOCK_MASK;
|
||||
|
||||
return GTK_SHORTCUT_TRIGGER_MATCH_EXACT;
|
||||
_gtk_translate_keyboard_accel_state (keymap,
|
||||
keycode, state, mask, group,
|
||||
&keyval,
|
||||
&effective_group, &level,
|
||||
&consumed_modifiers);
|
||||
|
||||
/* if the group-toggling modifier is part of the default accel mod
|
||||
* mask, and it is active, disable it for matching
|
||||
*/
|
||||
shift_group_mask = gdk_keymap_get_modifier_mask (keymap,
|
||||
GDK_MODIFIER_INTENT_SHIFT_GROUP);
|
||||
if (mask & shift_group_mask)
|
||||
group_mod_is_accel_mod = TRUE;
|
||||
|
||||
gdk_keymap_map_virtual_modifiers (keymap, &mask);
|
||||
gdk_keymap_add_virtual_modifiers (keymap, &state);
|
||||
|
||||
modifiers = self->modifiers;
|
||||
if (gdk_keymap_map_virtual_modifiers (keymap, &modifiers) &&
|
||||
((modifiers & ~consumed_modifiers & mask & ~vmods) == (state & ~consumed_modifiers & mask & ~vmods) ||
|
||||
(modifiers & ~consumed_modifiers & mask & ~xmods) == (state & ~consumed_modifiers & mask & ~xmods)))
|
||||
{
|
||||
/* modifier match */
|
||||
GdkKeymapKey *keys;
|
||||
int n_keys;
|
||||
int i;
|
||||
guint key;
|
||||
|
||||
/* Shift gets consumed and applied for the event,
|
||||
* so apply it to our keyval to match
|
||||
*/
|
||||
key = self->keyval;
|
||||
if (self->modifiers & GDK_SHIFT_MASK)
|
||||
key = gdk_keyval_to_upper (key);
|
||||
|
||||
if (keyval == key && /* exact match */
|
||||
(!group_mod_is_accel_mod ||
|
||||
(state & shift_group_mask) == (self->modifiers & shift_group_mask)))
|
||||
return GTK_SHORTCUT_TRIGGER_MATCH_EXACT;
|
||||
|
||||
gdk_keymap_get_entries_for_keyval (keymap,
|
||||
self->keyval,
|
||||
&keys, &n_keys);
|
||||
|
||||
for (i = 0; i < n_keys; i++)
|
||||
{
|
||||
if (keys[i].keycode == keycode &&
|
||||
keys[i].level == level &&
|
||||
/* Only match for group if it's an accel mod */
|
||||
(!group_mod_is_accel_mod ||
|
||||
keys[i].group == effective_group))
|
||||
{
|
||||
/* partial match */
|
||||
g_free (keys);
|
||||
|
||||
return GTK_SHORTCUT_TRIGGER_MATCH_PARTIAL;
|
||||
}
|
||||
}
|
||||
|
||||
g_free (keys);
|
||||
}
|
||||
|
||||
|
||||
return GTK_SHORTCUT_TRIGGER_MATCH_NONE;
|
||||
}
|
||||
|
||||
static guint
|
||||
|
@ -186,7 +186,7 @@ test_trigger_parse (void)
|
||||
static void
|
||||
test_trigger_trigger (void)
|
||||
{
|
||||
GtkShortcutTrigger *trigger1, *trigger2, *trigger3, *trigger4;
|
||||
GtkShortcutTrigger *trigger[4];
|
||||
GdkDisplay *display;
|
||||
GdkSurface *surface;
|
||||
GdkDevice *device;
|
||||
@ -204,13 +204,13 @@ test_trigger_trigger (void)
|
||||
{ GDK_KEY_u, GDK_SHIFT_MASK, FALSE, { GTK_SHORTCUT_TRIGGER_MATCH_NONE, GTK_SHORTCUT_TRIGGER_MATCH_NONE, GTK_SHORTCUT_TRIGGER_MATCH_NONE, GTK_SHORTCUT_TRIGGER_MATCH_NONE } },
|
||||
{ GDK_KEY_u, GDK_SHIFT_MASK, TRUE, { GTK_SHORTCUT_TRIGGER_MATCH_NONE, GTK_SHORTCUT_TRIGGER_MATCH_NONE, GTK_SHORTCUT_TRIGGER_MATCH_EXACT, GTK_SHORTCUT_TRIGGER_MATCH_EXACT } },
|
||||
};
|
||||
int i;
|
||||
int i, j;
|
||||
|
||||
trigger1 = gtk_shortcut_trigger_ref (gtk_never_trigger_get ());
|
||||
trigger2 = gtk_keyval_trigger_new (GDK_KEY_a, GDK_CONTROL_MASK);
|
||||
trigger3 = gtk_mnemonic_trigger_new (GDK_KEY_u);
|
||||
trigger4 = gtk_alternative_trigger_new (gtk_shortcut_trigger_ref (trigger2),
|
||||
gtk_shortcut_trigger_ref (trigger3));
|
||||
trigger[0] = gtk_shortcut_trigger_ref (gtk_never_trigger_get ());
|
||||
trigger[1] = gtk_keyval_trigger_new (GDK_KEY_a, GDK_CONTROL_MASK);
|
||||
trigger[2] = gtk_mnemonic_trigger_new (GDK_KEY_u);
|
||||
trigger[3] = gtk_alternative_trigger_new (gtk_shortcut_trigger_ref (trigger[1]),
|
||||
gtk_shortcut_trigger_ref (trigger[2]));
|
||||
|
||||
display = gdk_display_get_default ();
|
||||
device = gdk_seat_get_keyboard (gdk_display_get_default_seat (display));
|
||||
@ -218,6 +218,13 @@ test_trigger_trigger (void)
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (tests); i++)
|
||||
{
|
||||
GdkKeymapKey *keys;
|
||||
int n_keys;
|
||||
|
||||
if (!gdk_keymap_get_entries_for_keyval (gdk_display_get_keymap (display),
|
||||
tests[i].keyval, &keys, &n_keys))
|
||||
continue;
|
||||
|
||||
event = gdk_event_key_new (GDK_KEY_PRESS,
|
||||
surface,
|
||||
device,
|
||||
@ -225,24 +232,22 @@ test_trigger_trigger (void)
|
||||
GDK_CURRENT_TIME,
|
||||
tests[i].state,
|
||||
tests[i].keyval,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
keys[0].keycode,
|
||||
keys[0].keycode,
|
||||
keys[0].group,
|
||||
FALSE);
|
||||
g_assert_cmpint (gtk_shortcut_trigger_trigger (trigger1, event, tests[i].mnemonic), ==, tests[i].result[0]);
|
||||
g_assert_cmpint (gtk_shortcut_trigger_trigger (trigger2, event, tests[i].mnemonic), ==, tests[i].result[1]);
|
||||
g_assert_cmpint (gtk_shortcut_trigger_trigger (trigger3, event, tests[i].mnemonic), ==, tests[i].result[2]);
|
||||
g_assert_cmpint (gtk_shortcut_trigger_trigger (trigger4, event, tests[i].mnemonic), ==, tests[i].result[3]);
|
||||
for (j = 0; j < 4; j++)
|
||||
g_assert_cmpint (gtk_shortcut_trigger_trigger (trigger[j], event, tests[i].mnemonic), ==, tests[i].result[j]);
|
||||
|
||||
gdk_event_unref (event);
|
||||
}
|
||||
|
||||
g_object_unref (surface);
|
||||
|
||||
gtk_shortcut_trigger_unref (trigger1);
|
||||
gtk_shortcut_trigger_unref (trigger2);
|
||||
gtk_shortcut_trigger_unref (trigger3);
|
||||
gtk_shortcut_trigger_unref (trigger4);
|
||||
gtk_shortcut_trigger_unref (trigger[0]);
|
||||
gtk_shortcut_trigger_unref (trigger[1]);
|
||||
gtk_shortcut_trigger_unref (trigger[2]);
|
||||
gtk_shortcut_trigger_unref (trigger[3]);
|
||||
}
|
||||
|
||||
static int callback_count;
|
||||
|
Loading…
Reference in New Issue
Block a user