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



commit 18d7d9a5063c1297ae2790d83ecc5e1925aa72bb
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]