[gtk/wip/matthiasc/shortcut-4: 59/85] shortcuttrigger: Do elaborate matching for key events



commit 586e7749d5aba9f2251cc1a345c68ea4d22d0138
Author: Matthias Clasen <mclasen redhat com>
Date:   Sun Mar 22 09:54:15 2020 -0400

    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.

 gtk/gtkshortcuttrigger.c  | 99 +++++++++++++++++++++++++++++++++++++++++------
 testsuite/gtk/shortcuts.c | 41 +++++++++++---------
 2 files changed, 110 insertions(+), 30 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
diff --git a/testsuite/gtk/shortcuts.c b/testsuite/gtk/shortcuts.c
index e06b1814e9..ebf47ae21d 100644
--- a/testsuite/gtk/shortcuts.c
+++ b/testsuite/gtk/shortcuts.c
@@ -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;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]