summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2020-04-04 17:51:32 -0400
committerMatthias Clasen <mclasen@redhat.com>2020-04-04 17:51:32 -0400
commitc9da5e9043e2980cd8914fb0c647e837060d4977 (patch)
tree99968c69398fae75323da56f1ecadcaa263731c0
parent1149502767da6e175625fd14a3961c36a65c034f (diff)
downloadgtk+-c9da5e9043e2980cd8914fb0c647e837060d4977.tar.gz
Add gdk_event_matches
Move the elaborate key event matching code from GtkShortcutTrigger to GdkEvent, which greatly reduces the amount of keymap api use outside of GDK.
-rw-r--r--gdk/gdkevents.c156
-rw-r--r--gdk/gdkevents.h11
-rw-r--r--gtk/gtkshortcutcontroller.c6
-rw-r--r--gtk/gtkshortcuttrigger.c123
-rw-r--r--gtk/gtkshortcuttrigger.h21
-rw-r--r--testsuite/gtk/shortcuts.c14
6 files changed, 191 insertions, 140 deletions
diff --git a/gdk/gdkevents.c b/gdk/gdkevents.c
index 097198ef29..1d53d9c30b 100644
--- a/gdk/gdkevents.c
+++ b/gdk/gdkevents.c
@@ -2110,3 +2110,159 @@ gdk_grab_broken_event_get_grab_surface (GdkEvent *event)
return event->grab_broken.grab_surface;
}
+
+static gboolean
+translate_keyboard_accel_state (GdkKeymap *keymap,
+ guint hardware_keycode,
+ GdkModifierType state,
+ gint group,
+ guint *keyval,
+ gint *effective_group,
+ gint *level,
+ GdkModifierType *consumed_modifiers)
+{
+ GdkModifierType mask;
+ GdkModifierType shift_group_mask;
+ gboolean group_mask_disabled = FALSE;
+ gboolean retval;
+
+ mask = gdk_keymap_get_modifier_mask (keymap,
+ GDK_MODIFIER_INTENT_DEFAULT_MOD_MASK);
+
+ /* if the group-toggling modifier is part of the 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 & state & shift_group_mask)
+ {
+ state &= ~shift_group_mask;
+ group = 0;
+ group_mask_disabled = TRUE;
+ }
+
+ retval = gdk_keymap_translate_keyboard_state (keymap,
+ hardware_keycode, state, group,
+ keyval,
+ effective_group, level,
+ consumed_modifiers);
+
+ /* add back the group mask, we want to match against the modifier,
+ * but not against the keyval from its group
+ */
+ if (group_mask_disabled)
+ {
+ if (effective_group)
+ *effective_group = 1;
+
+ if (consumed_modifiers)
+ *consumed_modifiers &= ~shift_group_mask;
+ }
+
+ return retval;
+}
+
+
+GdkEventMatch
+gdk_event_matches (GdkEvent *event,
+ guint match_keyval,
+ GdkModifierType match_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 GDK_EVENT_MATCH_NONE;
+
+ 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));
+
+ mask = gdk_keymap_get_modifier_mask (keymap,
+ GDK_MODIFIER_INTENT_DEFAULT_MOD_MASK);
+
+ /* We don't want Caps_Lock to affect keybinding lookups.
+ */
+ state &= ~GDK_LOCK_MASK;
+
+ translate_keyboard_accel_state (keymap,
+ keycode, state, 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 = match_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 = match_keyval;
+ if (match_modifiers & GDK_SHIFT_MASK)
+ {
+ if (key == GDK_KEY_Tab)
+ key = GDK_KEY_ISO_Left_Tab;
+ else
+ key = gdk_keyval_to_upper (key);
+ }
+
+ if (keyval == key && /* exact match */
+ (!group_mod_is_accel_mod ||
+ (state & shift_group_mask) == (match_modifiers & shift_group_mask)))
+ return GDK_EVENT_MATCH_EXACT;
+
+ gdk_keymap_get_entries_for_keyval (keymap, match_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 GDK_EVENT_MATCH_PARTIAL;
+ }
+ }
+
+ g_free (keys);
+ }
+
+
+ return GDK_EVENT_MATCH_NONE;
+}
diff --git a/gdk/gdkevents.h b/gdk/gdkevents.h
index 888ca9e5c5..944047d946 100644
--- a/gdk/gdkevents.h
+++ b/gdk/gdkevents.h
@@ -428,6 +428,17 @@ gboolean gdk_events_get_center (GdkEvent *event1,
double *x,
double *y);
+typedef enum {
+ GDK_EVENT_MATCH_NONE,
+ GDK_EVENT_MATCH_PARTIAL,
+ GDK_EVENT_MATCH_EXACT
+} GdkEventMatch;
+
+GDK_AVAILABLE_IN_ALL
+GdkEventMatch gdk_event_matches (GdkEvent *event,
+ guint keyval,
+ GdkModifierType modifiers);
+
G_END_DECLS
#endif /* __GDK_EVENTS_H__ */
diff --git a/gtk/gtkshortcutcontroller.c b/gtk/gtkshortcutcontroller.c
index 8fa081f977..9a817ac286 100644
--- a/gtk/gtkshortcutcontroller.c
+++ b/gtk/gtkshortcutcontroller.c
@@ -313,16 +313,16 @@ gtk_shortcut_controller_run_controllers (GtkEventController *controller,
switch (gtk_shortcut_trigger_trigger (gtk_shortcut_get_trigger (shortcut), event, enable_mnemonics))
{
- case GTK_SHORTCUT_TRIGGER_MATCH_PARTIAL:
+ case GDK_EVENT_MATCH_PARTIAL:
if (!has_exact)
break;
G_GNUC_FALLTHROUGH;
- case GTK_SHORTCUT_TRIGGER_MATCH_NONE:
+ case GDK_EVENT_MATCH_NONE:
g_object_unref (shortcut);
continue;
- case GTK_SHORTCUT_TRIGGER_MATCH_EXACT:
+ case GDK_EVENT_MATCH_EXACT:
if (!has_exact)
{
g_slist_free_full (shortcuts, shortcut_data_free);
diff --git a/gtk/gtkshortcuttrigger.c b/gtk/gtkshortcuttrigger.c
index 722a41fafd..ad58a14c80 100644
--- a/gtk/gtkshortcuttrigger.c
+++ b/gtk/gtkshortcuttrigger.c
@@ -59,8 +59,7 @@ struct _GtkShortcutTriggerClass
{
GObjectClass parent_class;
- GtkShortcutTriggerMatch
- (* trigger) (GtkShortcutTrigger *trigger,
+ GdkEventMatch (* trigger) (GtkShortcutTrigger *trigger,
GdkEvent *event,
gboolean enable_mnemonics);
guint (* hash) (GtkShortcutTrigger *trigger);
@@ -97,12 +96,12 @@ gtk_shortcut_trigger_init (GtkShortcutTrigger *self)
*
* Returns: Whether the event triggered the shortcut
**/
-GtkShortcutTriggerMatch
+GdkEventMatch
gtk_shortcut_trigger_trigger (GtkShortcutTrigger *self,
GdkEvent *event,
gboolean enable_mnemonics)
{
- g_return_val_if_fail (GTK_IS_SHORTCUT_TRIGGER (self), GTK_SHORTCUT_TRIGGER_MATCH_NONE);
+ g_return_val_if_fail (GTK_IS_SHORTCUT_TRIGGER (self), GDK_EVENT_MATCH_NONE);
return GTK_SHORTCUT_TRIGGER_GET_CLASS (self)->trigger (self, event, enable_mnemonics);
}
@@ -410,12 +409,12 @@ gtk_never_trigger_finalize (GObject *gobject)
G_OBJECT_CLASS (gtk_never_trigger_parent_class)->finalize (gobject);
}
-static GtkShortcutTriggerMatch
+static GdkEventMatch
gtk_never_trigger_trigger (GtkShortcutTrigger *trigger,
GdkEvent *event,
gboolean enable_mnemonics)
{
- return GTK_SHORTCUT_TRIGGER_MATCH_NONE;
+ return GDK_EVENT_MATCH_NONE;
}
static guint
@@ -510,110 +509,14 @@ enum
static GParamSpec *keyval_props[KEYVAL_N_PROPS];
-static GtkShortcutTriggerMatch
+static GdkEventMatch
gtk_keyval_trigger_trigger (GtkShortcutTrigger *trigger,
GdkEvent *event,
gboolean enable_mnemonics)
{
GtkKeyvalTrigger *self = GTK_KEYVAL_TRIGGER (trigger);
- 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;
-
- 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)
- {
- if (key == GDK_KEY_Tab)
- key = GDK_KEY_ISO_Left_Tab;
- else
- 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;
+ return gdk_event_matches (event, self->keyval, self->modifiers);
}
static guint
@@ -849,7 +752,7 @@ enum
static GParamSpec *mnemonic_props[MNEMONIC_N_PROPS];
-static GtkShortcutTriggerMatch
+static GdkEventMatch
gtk_mnemonic_trigger_trigger (GtkShortcutTrigger *trigger,
GdkEvent *event,
gboolean enable_mnemonics)
@@ -858,10 +761,10 @@ gtk_mnemonic_trigger_trigger (GtkShortcutTrigger *trigger,
guint keyval;
if (!enable_mnemonics)
- return GTK_SHORTCUT_TRIGGER_MATCH_NONE;
+ return GDK_EVENT_MATCH_NONE;
if (gdk_event_get_event_type (event) != GDK_KEY_PRESS)
- return GTK_SHORTCUT_TRIGGER_MATCH_NONE;
+ return GDK_EVENT_MATCH_NONE;
/* XXX: This needs to deal with groups */
keyval = gdk_key_event_get_keyval (event);
@@ -872,9 +775,9 @@ gtk_mnemonic_trigger_trigger (GtkShortcutTrigger *trigger,
keyval = gdk_keyval_to_lower (keyval);
if (keyval != self->keyval)
- return GTK_SHORTCUT_TRIGGER_MATCH_NONE;
+ return GDK_EVENT_MATCH_NONE;
- return GTK_SHORTCUT_TRIGGER_MATCH_EXACT;
+ return GDK_EVENT_MATCH_EXACT;
}
static guint
@@ -1085,7 +988,7 @@ gtk_alternative_trigger_dispose (GObject *gobject)
G_OBJECT_CLASS (gtk_alternative_trigger_parent_class)->dispose (gobject);
}
-static GtkShortcutTriggerMatch
+static GdkEventMatch
gtk_alternative_trigger_trigger (GtkShortcutTrigger *trigger,
GdkEvent *event,
gboolean enable_mnemonics)
diff --git a/gtk/gtkshortcuttrigger.h b/gtk/gtkshortcuttrigger.h
index eba7bde4f4..36f092339d 100644
--- a/gtk/gtkshortcuttrigger.h
+++ b/gtk/gtkshortcuttrigger.h
@@ -36,25 +36,6 @@ G_BEGIN_DECLS
* A trigger for a key shortcut.
*/
-/**
- * GtkShortcutTriggerMatch:
- * @GTK_SHORTCUT_TRIGGER_MATCH_NONE: The key event does not
- * match the trigger
- * @GTK_SHORTCUT_TRIGGER_MATCH_PARTIAL: The key event matches
- * the trigger if keyboard state (specifically, the currently
- * active group) is ignored
- * @GTK_SHORTCUT_TRIGGER_MATCH_EXACT: The key event matches
- * the trigger
- *
- * The possible return values from gtk_shortcut_trigger_trigger()
- * describe if a key event triggers a shortcut.
- */
-typedef enum {
- GTK_SHORTCUT_TRIGGER_MATCH_NONE,
- GTK_SHORTCUT_TRIGGER_MATCH_PARTIAL,
- GTK_SHORTCUT_TRIGGER_MATCH_EXACT,
-} GtkShortcutTriggerMatch;
-
GDK_AVAILABLE_IN_ALL
GDK_DECLARE_INTERNAL_TYPE (GtkShortcutTrigger, gtk_shortcut_trigger, GTK, SHORTCUT_TRIGGER, GObject)
@@ -84,7 +65,7 @@ gint gtk_shortcut_trigger_compare (gconstpointer
gconstpointer trigger2);
GDK_AVAILABLE_IN_ALL
-GtkShortcutTriggerMatch gtk_shortcut_trigger_trigger (GtkShortcutTrigger *self,
+GdkEventMatch gtk_shortcut_trigger_trigger (GtkShortcutTrigger *self,
GdkEvent *event,
gboolean enable_mnemonics);
diff --git a/testsuite/gtk/shortcuts.c b/testsuite/gtk/shortcuts.c
index 916a8f0424..174d3aba87 100644
--- a/testsuite/gtk/shortcuts.c
+++ b/testsuite/gtk/shortcuts.c
@@ -340,14 +340,14 @@ test_trigger_trigger (void)
guint keyval;
GdkModifierType state;
gboolean mnemonic;
- GtkShortcutTriggerMatch result[4];
+ GdkEventMatch result[4];
} tests[] = {
- { GDK_KEY_a, GDK_CONTROL_MASK, FALSE, { GTK_SHORTCUT_TRIGGER_MATCH_NONE, GTK_SHORTCUT_TRIGGER_MATCH_EXACT, GTK_SHORTCUT_TRIGGER_MATCH_NONE, GTK_SHORTCUT_TRIGGER_MATCH_EXACT } },
- { GDK_KEY_a, GDK_CONTROL_MASK, TRUE, { GTK_SHORTCUT_TRIGGER_MATCH_NONE, GTK_SHORTCUT_TRIGGER_MATCH_EXACT, GTK_SHORTCUT_TRIGGER_MATCH_NONE, GTK_SHORTCUT_TRIGGER_MATCH_EXACT } },
- { GDK_KEY_a, 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_a, GDK_SHIFT_MASK, TRUE, { 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, 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 } },
+ { GDK_KEY_a, GDK_CONTROL_MASK, FALSE, { GDK_EVENT_MATCH_NONE, GDK_EVENT_MATCH_EXACT, GDK_EVENT_MATCH_NONE, GDK_EVENT_MATCH_EXACT } },
+ { GDK_KEY_a, GDK_CONTROL_MASK, TRUE, { GDK_EVENT_MATCH_NONE, GDK_EVENT_MATCH_EXACT, GDK_EVENT_MATCH_NONE, GDK_EVENT_MATCH_EXACT } },
+ { GDK_KEY_a, GDK_SHIFT_MASK, FALSE, { GDK_EVENT_MATCH_NONE, GDK_EVENT_MATCH_NONE, GDK_EVENT_MATCH_NONE, GDK_EVENT_MATCH_NONE } },
+ { GDK_KEY_a, GDK_SHIFT_MASK, TRUE, { GDK_EVENT_MATCH_NONE, GDK_EVENT_MATCH_NONE, GDK_EVENT_MATCH_NONE, GDK_EVENT_MATCH_NONE } },
+ { GDK_KEY_u, GDK_SHIFT_MASK, FALSE, { GDK_EVENT_MATCH_NONE, GDK_EVENT_MATCH_NONE, GDK_EVENT_MATCH_NONE, GDK_EVENT_MATCH_NONE } },
+ { GDK_KEY_u, GDK_SHIFT_MASK, TRUE, { GDK_EVENT_MATCH_NONE, GDK_EVENT_MATCH_NONE, GDK_EVENT_MATCH_EXACT, GDK_EVENT_MATCH_EXACT } },
};
int i, j;