summaryrefslogtreecommitdiff
path: root/gtk/gtkshortcuttrigger.c
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2020-03-22 09:54:15 -0400
committerMatthias Clasen <mclasen@redhat.com>2020-03-25 23:14:45 -0400
commit586e7749d5aba9f2251cc1a345c68ea4d22d0138 (patch)
treeb5f682393561ec03740689484cd9961cc64db031 /gtk/gtkshortcuttrigger.c
parent904835d4b1ad1f04743e7bd51a3479a4e71b82c7 (diff)
downloadgtk+-586e7749d5aba9f2251cc1a345c68ea4d22d0138.tar.gz
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.
Diffstat (limited to 'gtk/gtkshortcuttrigger.c')
-rw-r--r--gtk/gtkshortcuttrigger.c99
1 files changed, 87 insertions, 12 deletions
diff --git a/gtk/gtkshortcuttrigger.c b/gtk/gtkshortcuttrigger.c
index 828a8486d2..15ec8ebd91 100644
--- a/gtk/gtkshortcuttrigger.c
+++ b/gtk/gtkshortcuttrigger.c
@@ -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);
-
- if (keyval == GDK_KEY_ISO_Left_Tab)
- keyval = GDK_KEY_Tab;
- else
- keyval = gdk_keyval_to_lower (keyval);
+ mask = gtk_accelerator_get_default_mod_mask ();
+
+ 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));
+
+ /* We don't want Caps_Lock to affect keybinding lookups.
+ */
+ state &= ~GDK_LOCK_MASK;
+
+ _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);
+ }
- if (keyval != self->keyval || modifiers != self->modifiers)
- return GTK_SHORTCUT_TRIGGER_MATCH_NONE;
- return GTK_SHORTCUT_TRIGGER_MATCH_EXACT;
+ return GTK_SHORTCUT_TRIGGER_MATCH_NONE;
}
static guint