[Xfce4-commits] <libxfce4ui:master> Merge branch 'jeromeg/keyboard-shortcuts-rework'

Jérôme Guelfucci noreply at xfce.org
Thu Jun 2 23:46:13 CEST 2011


Updating branch refs/heads/master
         to 1b78f177b7b604b8fb846fab600bff712d7f5578 (commit)
       from f04158b0edbaece61b0397ebfa7b28db85377600 (commit)

commit 1b78f177b7b604b8fb846fab600bff712d7f5578
Merge: f04158b 6bd3a41
Author: Jérôme Guelfucci <jeromeg at xfce.org>
Date:   Thu Jun 2 23:44:01 2011 +0200

    Merge branch 'jeromeg/keyboard-shortcuts-rework'

commit 6bd3a4156da0f4a334a3887451f984ff507e78bf
Author: Jérôme Guelfucci <jeromeg at xfce.org>
Date:   Thu Jun 2 15:00:04 2011 +0200

    Improve indentation.

commit a3d141ec2665de548da5073366fcbc873468d0f1
Author: Jérôme Guelfucci <jeromeg at xfce.org>
Date:   Thu Jun 2 14:56:34 2011 +0200

    Also grab with MOD5 modifier.

commit 56f8e3858e6d84850f51c1772f8f4617bae4dd9b
Author: Jérôme Guelfucci <jeromeg at xfce.org>
Date:   Thu Jun 2 14:54:07 2011 +0200

    Add more debbuging information.

commit 5e50a7d5f6f868c12b1d439ff54600b984b2d5bd
Author: Jérôme Guelfucci <jeromeg at xfce.org>
Date:   Sun May 29 18:09:45 2011 +0200

    Use the current group when translating the keyboard state

commit 83770eec38278dd1e05577b48908d4b0b0d68dfc
Author: Jérôme Guelfucci <jeromeg at xfce.org>
Date:   Sun May 29 18:09:19 2011 +0200

    Improve code comments and error handling.

commit 13251f7a7ab201dd20186d81ca11e21922d35628
Author: Jérôme Guelfucci <jeromeg at xfce.org>
Date:   Sun May 29 17:41:53 2011 +0200

    Rework grabbing/ungrabbing code.
    
    The code has been reworked to grab all keycodes generating the keyval
    needed for the shortcut which should fix a number of issues where the
    shortcut was not grabbed.
    
    Error handling needs to be improved.

commit 310a4d7d9d3834e7ee074359973f52cc1e186502
Author: Jérôme Guelfucci <jeromeg at xfce.org>
Date:   Sun May 29 16:40:39 2011 +0200

    Remove gobject boilerplate.

commit a0fb8ffefa37d61e7f4724b5b422276902f4445b
Author: Jérôme Guelfucci <jeromeg at xfce.org>
Date:   Sun May 22 16:18:32 2011 +0200

    Fix shortcut comparing.
    
    Because GDK functions do very useful stuff like echoing <Mod4><Super>
    when Windows key is pressed or <Alt><Meta> is pressed we need to ignore
    some modifiers in those cases...
    
    This needs testing to ensure that it works in all cases.

commit 4868a7bac5234af48748bce09e2a848dfb37a628
Author: Jérôme Guelfucci <jeromeg at xfce.org>
Date:   Sun May 22 16:17:53 2011 +0200

    Rework shortcut parsing using gdk functions.

commit 5a4cbdd01c7712934c26a068af8b027b7ac3e1cc
Author: Jérôme Guelfucci <jeromeg at xfce.org>
Date:   Fri Apr 22 17:09:46 2011 +0200

    Simplify code monitoring key press events.

commit 899aaa97827f263c877faab3f8d0686fd9784b66
Author: Jérôme Guelfucci <jeromeg at xfce.org>
Date:   Fri Apr 22 09:16:51 2011 +0200

    Simplify computing of shortcut name in the dialog.
    
    Instead of handling the key-pressed event with XKB code, we now use
    gdk/gtk functions directly which simplifies things a lot.
    
    This needs testing to ensure that there is no regression and that
    shortcuts with Numlock work.

 libxfce4kbd-private/xfce-shortcut-dialog.c   |  108 +-----
 libxfce4kbd-private/xfce-shortcuts-grabber.c |  541 +++++++++++---------------
 2 files changed, 252 insertions(+), 397 deletions(-)

diff --git a/libxfce4kbd-private/xfce-shortcut-dialog.c b/libxfce4kbd-private/xfce-shortcut-dialog.c
index 8049467..5f1b058 100644
--- a/libxfce4kbd-private/xfce-shortcut-dialog.c
+++ b/libxfce4kbd-private/xfce-shortcut-dialog.c
@@ -43,9 +43,6 @@ static gboolean xfce_shortcut_dialog_key_pressed      (XfceShortcutDialog      *
                                                        GdkEventKey             *event);
 static gboolean xfce_shortcut_dialog_key_released     (XfceShortcutDialog      *dialog,
                                                        GdkEventKey             *event);
-static gchar   *xfce_shortcut_dialog_shortcut_name    (XfceShortcutDialog      *dialog,
-                                                       guint                    keyval,
-                                                       guint                    modifiers);
 
 
 
@@ -312,13 +309,29 @@ static gboolean
 xfce_shortcut_dialog_key_pressed (XfceShortcutDialog *dialog,
                                   GdkEventKey        *event)
 {
-  gchar *text;
-  gchar *shortcut;
+  GdkKeymap       *keymap;
+  GdkModifierType  consumed, modifiers;
+  guint            keyval, mod_mask;
+  gchar           *text;
+  gchar           *shortcut;
 
   g_free (dialog->shortcut);
 
-  /* Determine and remember the current shortcut */
-  dialog->shortcut = xfce_shortcut_dialog_shortcut_name (dialog, event->keyval, event->state);
+  /* Get the keyboard state */
+  mod_mask = gtk_accelerator_get_default_mod_mask ();
+  keymap = gdk_keymap_get_default ();
+  modifiers = event->state;
+
+  gdk_keymap_translate_keyboard_state (keymap, event->hardware_keycode,
+                                       modifiers, 0,
+                                       &keyval, NULL, NULL, &consumed);
+
+  /* Get the modifiers */
+  modifiers &= ~consumed;
+  modifiers &= mod_mask;
+
+  /* Get and store the pressed shortcut */
+  dialog->shortcut = gtk_accelerator_name (keyval, modifiers);
 
   shortcut = g_markup_escape_text (dialog->shortcut, -1);
   text = g_strdup_printf ("<span size='large'><b>%s</b></span>", shortcut);
@@ -362,87 +375,6 @@ xfce_shortcut_dialog_key_released (XfceShortcutDialog *dialog,
 
 
 
-static gchar *
-xfce_shortcut_dialog_shortcut_name (XfceShortcutDialog *dialog,
-                                    guint               keyval,
-                                    guint               modifiers)
-{
-  XModifierKeymap *modmap;
-  Display         *display;
-  const KeySym    *keysyms;
-  KeyCode          keycode;
-  KeySym          *keymap;
-  gint             keysyms_per_keycode = 0;
-  gint             min_keycode = 0;
-  gint             max_keycode = 0;
-  gint             mask;
-  gint             i;
-  gint             j;
-
-  g_return_val_if_fail (XFCE_IS_SHORTCUT_DIALOG (dialog), NULL);
-
-  display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
-
-  gdk_error_trap_push ();
-
-  XDisplayKeycodes (display, &min_keycode, &max_keycode);
-
-  keymap = XGetKeyboardMapping (display, min_keycode, max_keycode - min_keycode + 1, &keysyms_per_keycode);
-
-  if (G_LIKELY (keymap != NULL))
-    {
-      modmap = XGetModifierMapping (display);
-
-      if (G_LIKELY (modmap != NULL))
-        {
-          for (i = 0; i < 8 * modmap->max_keypermod; ++i)
-            {
-              keycode = modmap->modifiermap[i];
-
-              if (keycode == 0 || keycode < min_keycode || keycode > max_keycode)
-                continue;
-
-              keysyms = keymap + (keycode - min_keycode) * keysyms_per_keycode;
-              mask = 1 << (i / modmap->max_keypermod);
-
-              for (j = 0; j < keysyms_per_keycode; ++j)
-                {
-                  if (keysyms[j] == GDK_Super_L || keysyms[j] == GDK_Super_R)
-                    modifiers &= ~mask;
-
-#if 0
-                  if (keysyms[j] == GDK_Meta_L || keysyms[j] == GDK_Meta_R)
-                    modifiers &= ~mask;
-#endif
-
-                  if (keysyms[j] == GDK_Hyper_L || keysyms[j] == GDK_Hyper_R)
-                    modifiers &= ~mask;
-
-                  if (keysyms[j] == GDK_Scroll_Lock)
-                    modifiers &= ~mask;
-
-                  if (keysyms[j] == GDK_Num_Lock)
-                    modifiers &= ~mask;
-
-                  if (keysyms[j] == GDK_Caps_Lock)
-                    modifiers &= ~mask;
-                }
-            }
-
-          XFreeModifiermap (modmap);
-        }
-
-      XFree (keymap);
-    }
-
-  gdk_flush ();
-  gdk_error_trap_pop ();
-
-  return gtk_accelerator_name (keyval, modifiers);
-}
-
-
-
 const gchar*
 xfce_shortcut_dialog_get_shortcut (XfceShortcutDialog *dialog)
 {
diff --git a/libxfce4kbd-private/xfce-shortcuts-grabber.c b/libxfce4kbd-private/xfce-shortcuts-grabber.c
index e1a4f97..9faec07 100644
--- a/libxfce4kbd-private/xfce-shortcuts-grabber.c
+++ b/libxfce4kbd-private/xfce-shortcuts-grabber.c
@@ -26,6 +26,7 @@
 #include <glib-object.h>
 
 #include <X11/Xlib.h>
+#include <X11/XKBlib.h>
 
 #include <gdk/gdk.h>
 #include <gdk/gdkx.h>
@@ -41,45 +42,8 @@
 
 
 #define XFCE_SHORTCUTS_GRABBER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), XFCE_TYPE_SHORTCUTS_GRABBER, XfceShortcutsGrabberPrivate))
-
-
-
-#define MODIFIER_MASK (GDK_SHIFT_MASK | \
-                       GDK_CONTROL_MASK | \
-                       GDK_MOD1_MASK | \
-                       GDK_MOD2_MASK | \
-                       GDK_MOD3_MASK | \
-                       GDK_MOD4_MASK | \
-                       GDK_MOD5_MASK)
-
-#define IGNORE_MASK   (0x2000 | \
-                       GDK_LOCK_MASK | \
-                       GDK_HYPER_MASK | \
-                       GDK_SUPER_MASK | \
-                       GDK_META_MASK)
-
-
-
-/* Property identifiers */
-enum
-{
-  PROP_0,
-};
-
-
-
-/* Cache indices for modifiers */
-enum
-{
-  CACHE_SUPER,
-  CACHE_HYPER,
-  CACHE_META,
-  CACHE_CAPS_LOCK,
-  CACHE_NUM_LOCK,
-  CACHE_SCROLL_LOCK,
-  CACHE_LAST,
-};
-
+#define MODIFIERS_ERROR ((GdkModifierType)(-1))
+#define MODIFIERS_NONE 0
 
 
 typedef struct _XfceKey XfceKey;
@@ -88,27 +52,13 @@ typedef struct _XfceKey XfceKey;
 
 static void            xfce_shortcuts_grabber_constructed      (GObject                   *object);
 static void            xfce_shortcuts_grabber_finalize         (GObject                   *object);
-static void            xfce_shortcuts_grabber_get_property     (GObject                   *object,
-                                                                guint                      prop_id,
-                                                                GValue                    *value,
-                                                                GParamSpec                *pspec);
-static void            xfce_shortcuts_grabber_set_property     (GObject                   *object,
-                                                                guint                      prop_id,
-                                                                const GValue              *value,
-                                                                GParamSpec                *pspec);
 static void            xfce_shortcuts_grabber_keys_changed     (GdkKeymap                 *keymap,
                                                                 XfceShortcutsGrabber      *grabber);
 static void            xfce_shortcuts_grabber_grab_all         (XfceShortcutsGrabber      *grabber);
 static void            xfce_shortcuts_grabber_ungrab_all       (XfceShortcutsGrabber      *grabber);
-static void            xfce_shortcuts_grabber_reload_modifiers (XfceShortcutsGrabber      *grabber);
-static void            xfce_shortcuts_grabber_parse_shortcut   (XfceShortcutsGrabber      *grabber,
-                                                                const gchar               *shortcut,
-                                                                guint                     *keycode,
-                                                                guint                     *modifiers);
 static void            xfce_shortcuts_grabber_grab             (XfceShortcutsGrabber      *grabber,
                                                                 XfceKey                   *key,
                                                                 gboolean                   grab);
-static guint           xfce_shortcuts_grabber_get_ignore_mask  (XfceShortcutsGrabber      *grabber);
 static GdkFilterReturn xfce_shortcuts_grabber_event_filter     (GdkXEvent                 *gdk_xevent,
                                                                 GdkEvent                  *event,
                                                                 XfceShortcutsGrabber      *grabber);
@@ -118,12 +68,11 @@ static GdkFilterReturn xfce_shortcuts_grabber_event_filter     (GdkXEvent
 struct _XfceShortcutsGrabberPrivate
 {
   GHashTable *keys;
-  guint       modifiers[CACHE_LAST];
 };
 
 struct _XfceKey
 {
-  guint keycode;
+  guint keyval;
   guint modifiers;
 };
 
@@ -143,8 +92,6 @@ xfce_shortcuts_grabber_class_init (XfceShortcutsGrabberClass *klass)
   gobject_class = G_OBJECT_CLASS (klass);
   gobject_class->constructed = xfce_shortcuts_grabber_constructed;
   gobject_class->finalize = xfce_shortcuts_grabber_finalize;
-  gobject_class->get_property = xfce_shortcuts_grabber_get_property;
-  gobject_class->set_property = xfce_shortcuts_grabber_set_property;
 
   g_signal_new ("shortcut-activated",
                 XFCE_TYPE_SHORTCUTS_GRABBER,
@@ -166,7 +113,12 @@ xfce_shortcuts_grabber_init (XfceShortcutsGrabber *grabber)
   grabber->priv = XFCE_SHORTCUTS_GRABBER_GET_PRIVATE (grabber);
   grabber->priv->keys = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
 
-  xfce_shortcuts_grabber_reload_modifiers (grabber);
+  /* Workaround: Make sure modmap is up to date
+   * There is possibly a bug in GTK+ where virtual modifiers are not
+   * mapped because the modmap is not updated. The following function
+   * updates it.
+   */
+  (void) gdk_keymap_have_bidi_layouts (gdk_keymap_get_default ());
 }
 
 
@@ -208,53 +160,14 @@ xfce_shortcuts_grabber_finalize (GObject *object)
 
 
 static void
-xfce_shortcuts_grabber_get_property (GObject    *object,
-                                     guint       prop_id,
-                                     GValue     *value,
-                                     GParamSpec *pspec)
-{
-#if 0
-  XfceShortcutsGrabber *grabber = XFCE_SHORTCUTS_GRABBER (object);
-#endif
-
-  switch (prop_id)
-    {
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
-
-
-
-static void
-xfce_shortcuts_grabber_set_property (GObject      *object,
-                                     guint         prop_id,
-                                     const GValue *value,
-                                     GParamSpec   *pspec)
-{
-#if 0
-  XfceShortcutsGrabber *grabber = XFCE_SHORTCUTS_GRABBER (object);
-#endif
-
-  switch (prop_id)
-    {
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
-
-
-
-static void
 xfce_shortcuts_grabber_keys_changed (GdkKeymap            *keymap,
                                      XfceShortcutsGrabber *grabber)
 {
   g_return_if_fail (XFCE_IS_SHORTCUTS_GRABBER (grabber));
 
+  TRACE ("Keys changed, regrabbing");
+
   xfce_shortcuts_grabber_ungrab_all (grabber);
-  xfce_shortcuts_grabber_reload_modifiers (grabber);
   xfce_shortcuts_grabber_grab_all (grabber);
 }
 
@@ -300,246 +213,214 @@ xfce_shortcuts_grabber_ungrab_all (XfceShortcutsGrabber *grabber)
 
 
 
-static void
-xfce_shortcuts_grabber_reload_modifiers (XfceShortcutsGrabber *grabber)
+/* Return the modifier mask that needs to be pressed to produce key in the
+ * given group (keyboard layout) and level ("shift level").
+ *
+ * Taken from libkeybinder
+ * Copyright (C) 2010 Ulrik Sverdrup <ulrik.sverdrup at gmail.com>
+ */
+static GdkModifierType
+FinallyGetModifiersForKeycode (XkbDescPtr xkb,
+                               KeyCode    key,
+                               uint       group,
+                               uint       level)
 {
-  XModifierKeymap *modmap;
-  const KeySym    *keysyms;
-  Display         *display;
-  KeyCode          keycode;
-  KeySym          *keymap;
-  gint             keysyms_per_keycode = 0;
-  gint             min_keycode = 0;
-  gint             max_keycode = 0;
-  gint             mask;
-  gint             i;
-  gint             j;
-
-  g_return_if_fail (XFCE_IS_SHORTCUTS_GRABBER (grabber));
-
-  for (i = 0; i < CACHE_LAST; ++i)
-    grabber->priv->modifiers[i] = 0;
-
-  display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
+  XkbKeyTypeRec *type;
+  int            nKeyGroups;
+  int            effectiveGroup;
+  int            k;
 
-  gdk_error_trap_push ();
-
-  XDisplayKeycodes (display, &min_keycode, &max_keycode);
-
-  keymap = XGetKeyboardMapping (display, min_keycode, max_keycode - min_keycode + 1,
-                                &keysyms_per_keycode);
+  nKeyGroups = XkbKeyNumGroups (xkb, key);
 
-  if (G_UNLIKELY (keymap == NULL))
-    return;
+  if ((!XkbKeycodeInRange (xkb, key)) || (nKeyGroups == 0))
+    return MODIFIERS_ERROR;
 
-  modmap = XGetModifierMapping (display);
+  /* Taken from GDK's MyEnhancedXkbTranslateKeyCode */
+  /* find the offset of the effective group */
+  effectiveGroup = group;
 
-  if (G_UNLIKELY (modmap == NULL))
+  if (effectiveGroup >= nKeyGroups)
     {
-      XFree (keymap);
-      return;
-    }
-
-  for (i = 0; i < 8 * modmap->max_keypermod; ++i)
-    {
-      keycode = modmap->modifiermap[i];
-
-      if (keycode == 0 || keycode < min_keycode || keycode > max_keycode)
-        continue;
-
-      keysyms = keymap + (keycode - min_keycode) * keysyms_per_keycode;
-      mask = 1 << (i / modmap->max_keypermod);
+      unsigned groupInfo = XkbKeyGroupInfo (xkb,key);
 
-      for (j = 0; j < keysyms_per_keycode; ++j)
+      switch (XkbOutOfRangeGroupAction(groupInfo))
         {
-          if (keysyms[j] == GDK_Super_L || keysyms[j] == GDK_Super_R)
-            grabber->priv->modifiers[CACHE_SUPER] = mask;
-
-          if (keysyms[j] == GDK_Meta_L || keysyms[j] == GDK_Meta_R)
-            grabber->priv->modifiers[CACHE_META] = mask;
-
-          if (keysyms[j] == GDK_Hyper_L || keysyms[j] == GDK_Hyper_R)
-            grabber->priv->modifiers[CACHE_HYPER] = mask;
-
-          if (keysyms[j] == GDK_Scroll_Lock)
-            grabber->priv->modifiers[CACHE_SCROLL_LOCK] = mask;
+          default:
+            effectiveGroup %= nKeyGroups;
+            break;
+          case XkbClampIntoRange:
+            effectiveGroup = nKeyGroups-1;
+            break;
+          case XkbRedirectIntoRange:
+            effectiveGroup = XkbOutOfRangeGroupNumber (groupInfo);
+            if (effectiveGroup >= nKeyGroups)
+              effectiveGroup = 0;
+            break;
+        }
+    }
 
-          if (keysyms[j] == GDK_Num_Lock)
-            grabber->priv->modifiers[CACHE_NUM_LOCK] = mask;
+  type = XkbKeyKeyType (xkb, key, effectiveGroup);
 
-          if (keysyms[j] == GDK_Caps_Lock)
-            grabber->priv->modifiers[CACHE_CAPS_LOCK] = mask;
+  for (k = 0; k < type->map_count; k++)
+    {
+      if (type->map[k].active && type->map[k].level == level)
+        {
+          if (type->preserve)
+            return (type->map[k].mods.mask & ~type->preserve[k].mask);
+          else
+            return type->map[k].mods.mask;
         }
     }
 
-  XFreeModifiermap (modmap);
-  XFree (keymap);
-
-  gdk_flush ();
-  gdk_error_trap_pop ();
+  return MODIFIERS_NONE;
 }
 
 
 
 static void
-xfce_shortcuts_grabber_parse_shortcut (XfceShortcutsGrabber *grabber,
-                                       const gchar          *shortcut,
-                                       guint                *keycode,
-                                       guint                *modifiers)
+xfce_shortcuts_grabber_grab (XfceShortcutsGrabber *grabber,
+                             XfceKey              *key,
+                             gboolean              grab)
 {
-  guint keyval;
+  GdkKeymapKey *keys;
+  XkbDescPtr    xmap;
+  GdkDisplay   *display;
+  GdkKeymap    *keymap;
+  gchar        *shortcut_name;
+  guint         modifiers;
+  guint         k;
+  gint          i, j;
+  gint          n_keys;
+  gint          screens;
 
   g_return_if_fail (XFCE_IS_SHORTCUTS_GRABBER (grabber));
+  g_return_if_fail (key != NULL);
 
-  gtk_accelerator_parse (shortcut, &keyval, modifiers);
-
-  *keycode = XKeysymToKeycode (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), keyval);
-
-  if ((*modifiers & GDK_SUPER_MASK) == GDK_SUPER_MASK)
-    {
-      *modifiers |= grabber->priv->modifiers[CACHE_SUPER];
-      *modifiers ^= GDK_SUPER_MASK;
-    }
-
-  if ((*modifiers & GDK_HYPER_MASK) == GDK_HYPER_MASK)
-    {
-      *modifiers |= grabber->priv->modifiers[CACHE_HYPER];
-      *modifiers ^= GDK_HYPER_MASK;
-    }
-
-  if ((*modifiers & GDK_META_MASK) == GDK_META_MASK)
-    {
-      *modifiers |= grabber->priv->modifiers[CACHE_META];
-      *modifiers ^= GDK_META_MASK;
-    }
-
-  *modifiers &= MODIFIER_MASK;
-  *modifiers &= ~xfce_shortcuts_grabber_get_ignore_mask (grabber);
-}
-
+  display = gdk_display_get_default ();
+  screens = gdk_display_get_n_screens (display);
+  keymap = gdk_keymap_get_default ();
 
+  /* Map virtual modifiers to non-virtual modifiers */
+  modifiers = key->modifiers;
+  gdk_keymap_map_virtual_modifiers (keymap, &modifiers);
 
-gchar *
-xfce_shortcuts_grabber_shortcut_name (XfceShortcutsGrabber *grabber,
-                                      guint                 keycode,
-                                      guint                 modifiers)
-{
-  Display *display;
-  KeySym   keysym;
+  /* Debugging information */
+  shortcut_name = gtk_accelerator_name (key->keyval, modifiers);
 
-  g_return_val_if_fail (XFCE_IS_SHORTCUTS_GRABBER (grabber), NULL);
+  if (grab)
+    TRACE ("Grabbing %s", shortcut_name);
+  else
+    TRACE ("Ungrabbing %s", shortcut_name);
 
-  display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
-  keysym = XKeycodeToKeysym (display, keycode, 0);
+  TRACE ("Keyval: %d", key->keyval);
+  TRACE ("Modifiers: 0x%x", key->modifiers);
 
-  modifiers &= MODIFIER_MASK;
-  modifiers &= ~xfce_shortcuts_grabber_get_ignore_mask (grabber);
+  g_free (shortcut_name);
 
-  if ((modifiers & grabber->priv->modifiers[CACHE_SUPER]) != 0)
+  if (modifiers == key->modifiers &&
+      (GDK_SUPER_MASK | GDK_HYPER_MASK | GDK_META_MASK) & modifiers)
     {
-      modifiers |= GDK_SUPER_MASK;
-      modifiers ^= grabber->priv->modifiers[CACHE_SUPER];
+      TRACE ("Failed to map virtual modifiers");
+      return;
     }
 
-  if ((modifiers & grabber->priv->modifiers[CACHE_HYPER]) != 0)
-    {
-      modifiers |= GDK_HYPER_MASK;
-      modifiers ^= grabber->priv->modifiers[CACHE_HYPER];
-    }
+  xmap = XkbGetMap (GDK_DISPLAY_XDISPLAY (display),
+                    XkbAllClientInfoMask,
+                    XkbUseCoreKbd);
 
-#if 0
-  if ((modifiers & grabber->priv->modifiers[CACHE_META]) != 0)
+  /* Get all keys generating keyval */
+  if (!gdk_keymap_get_entries_for_keyval (keymap,key->keyval,
+                                          &keys, &n_keys))
     {
-      modifiers |= GDK_META_MASK;
-      modifiers ^= grabber->priv->modifiers[CACHE_META];
+      XkbFreeClientMap (xmap, 0, TRUE);
+      TRACE ("Got no keys for keyval");
+      return;
     }
-#endif
-
-  return gtk_accelerator_name (keysym, modifiers);
-}
-
 
+  if (n_keys == 0)
+    {
+      XkbFreeClientMap (xmap, 0, TRUE);
+      g_free (keys);
 
-static void
-xfce_shortcuts_grabber_grab (XfceShortcutsGrabber *grabber,
-                             XfceKey              *key,
-                             gboolean              grab)
-{
-  GdkDisplay *display;
-  GdkScreen  *screen;
-  Window      window;
-  guint       bits[32];
-  guint       current_mask;
-  guint       n_bits;
-  guint       screens;
-  guint       modifiers;
-  guint       ignored_modifiers = 0;
-  gint        i;
-  guint       j;
-  guint       k;
+      TRACE ("Got 0 keys for keyval");
+      return;
+    }
 
-  g_return_if_fail (XFCE_IS_SHORTCUTS_GRABBER (grabber));
-  g_return_if_fail (key != NULL);
+  for (i = 0; i < n_keys; i ++)
+    {
+      /* Grab all hardware keys generating keyval */
 
-  display = gdk_display_get_default ();
-  screens = gdk_display_get_n_screens (display);
+      GdkModifierType add_modifiers;
 
-  ignored_modifiers = xfce_shortcuts_grabber_get_ignore_mask (grabber);
+      TRACE ("Keycode: %d", keys[i].keycode);
 
-  modifiers = key->modifiers & MODIFIER_MASK & ~ignored_modifiers;
+      add_modifiers = FinallyGetModifiersForKeycode (xmap,
+                                                     keys[i].keycode,
+                                                     keys[i].group,
+                                                     keys[i].level);
 
-  /* Store indices of all the set bits of the ignore mask in an array */
-  for (i = 0, n_bits = 0; i < 32; ++i, ignored_modifiers >>= 1)
-    if ((ignored_modifiers & 0x1) == 0x1)
-      bits[n_bits++] = i;
+      if (add_modifiers == MODIFIERS_ERROR)
+        {
+          TRACE ("Error when getting modifiers for keycode");
+          continue;
+        }
 
-  for (i = 0; i < (1 << n_bits); ++i)
-    {
-      /* Map bits in the counter to those in the mask and thereby retrieve all ignored bit
-       * mask combinations */
-      for (current_mask = 0, j = 0; j < n_bits; ++j)
-        if ((i & (1 << j)) != 0)
-          current_mask |= (1 << bits[j]);
-
-      /* Grab key on all screens */
-      for (k = 0; k < screens; ++k)
+      for (j = 0; j < screens; j++)
         {
-          /* Get current screen and X root window */
-          screen = gdk_display_get_screen (display, k);
-          window = GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (screen));
+          /* Do the grab on all screens */
+          GdkScreen *screen;
+          Window     root_window;
+
+          /* Ignorable modifiers */
+          guint mod_masks [] = {
+            0,
+            GDK_MOD2_MASK,
+            GDK_LOCK_MASK,
+            GDK_MOD5_MASK,
+            GDK_MOD2_MASK | GDK_LOCK_MASK,
+            GDK_MOD2_MASK | GDK_MOD5_MASK,
+            GDK_LOCK_MASK | GDK_MOD5_MASK,
+            GDK_MOD2_MASK | GDK_LOCK_MASK | GDK_MOD5_MASK,
+          };
+
+          /* Retrieve the root window of the screen */
+          screen = gdk_display_get_screen (display, j);
+          root_window = GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (screen));
 
           gdk_error_trap_push ();
 
-          if (grab)
+          for (k = 0; k < G_N_ELEMENTS (mod_masks); k++)
             {
-              XGrabKey (GDK_DISPLAY_XDISPLAY (display), key->keycode, current_mask | modifiers,
-                        window, FALSE, GrabModeAsync, GrabModeAsync);
+              /* Take ignorable modifiers into account when grabbing */
+              if (grab)
+                XGrabKey (GDK_DISPLAY_XDISPLAY (display),
+                          keys[i].keycode,
+                          add_modifiers | modifiers | mod_masks [k],
+                          root_window,
+                          False,
+                          GrabModeAsync,
+                          GrabModeAsync);
+              else
+                XUngrabKey (GDK_DISPLAY_XDISPLAY (display),
+                            keys[i].keycode,
+                            add_modifiers | modifiers | mod_masks [k],
+                            root_window);
             }
-          else
-            XUngrabKey (GDK_DISPLAY_XDISPLAY (display), key->keycode, current_mask | modifiers,
-                        window);
 
           gdk_flush ();
-          gdk_error_trap_pop ();
+
+          if (gdk_error_trap_pop ())
+            {
+              if (grab)
+                TRACE ("Failed to grab");
+              else
+                TRACE ("Failed to ungrab");
+            }
         }
     }
-}
 
-
-
-static guint
-xfce_shortcuts_grabber_get_ignore_mask (XfceShortcutsGrabber *grabber)
-{
-  guint mask = 0;
-
-  g_return_val_if_fail (XFCE_IS_SHORTCUTS_GRABBER (grabber), 0);
-
-  mask |= 0x200 | GDK_LOCK_MASK | GDK_HYPER_MASK | GDK_SUPER_MASK | GDK_META_MASK;
-  mask |= grabber->priv->modifiers[CACHE_CAPS_LOCK];
-  mask |= grabber->priv->modifiers[CACHE_NUM_LOCK];
-  mask |= grabber->priv->modifiers[CACHE_SCROLL_LOCK];
-
-  return mask;
+  g_free (keys);
+  XkbFreeClientMap (xmap, 0, TRUE);
 }
 
 
@@ -547,7 +428,8 @@ xfce_shortcuts_grabber_get_ignore_mask (XfceShortcutsGrabber *grabber)
 struct EventKeyFindContext
 {
   XfceShortcutsGrabber *grabber;
-  XKeyEvent            *xevent;
+  GdkModifierType       modifiers;
+  guint                 keyval;
   const gchar          *result;
 };
 
@@ -558,29 +440,38 @@ find_event_key (const gchar                *shortcut,
                 XfceKey                    *key,
                 struct EventKeyFindContext *context)
 {
-  gchar   *name;
-  gboolean result = FALSE;
+  GdkModifierType ignored;
 
-  g_return_val_if_fail (context != NULL, TRUE);
-  g_return_val_if_fail (context->xevent != NULL, TRUE);
+  g_return_val_if_fail (context != NULL, FALSE);
 
-  gdk_error_trap_push ();
+  TRACE ("Comparing to %s", shortcut);
 
-  name = xfce_shortcuts_grabber_shortcut_name (context->grabber, context->xevent->keycode,
-                                               context->xevent->state);
+  ignored = 0;
 
-  if (G_UNLIKELY (g_str_equal (shortcut, name)))
+  /* Accept MOD1 + META as MOD1 */
+  if (key->modifiers & context->modifiers & GDK_MOD1_MASK)
     {
-      context->result = shortcut;
-      result = TRUE;
+      TRACE ("Ignoring Meta Mask");
+      ignored |= GDK_META_MASK;
+    }
+
+  /* Accept SUPER + HYPER as SUPER */
+  if (key->modifiers & context->modifiers & GDK_SUPER_MASK)
+    {
+      TRACE ("Ignoring Hyper Mask");
+      ignored |= GDK_HYPER_MASK;
     }
 
-  g_free (name);
+  if ((key->modifiers & ~ignored) == (context->modifiers & ~ignored)
+      && key->keyval == context->keyval)
+    {
+      context->result = shortcut;
 
-  gdk_flush ();
-  gdk_error_trap_pop ();
+      TRACE ("Positive match for %s", context->result);
+      return TRUE;
+    }
 
-  return result;
+  return FALSE;
 }
 
 
@@ -590,9 +481,13 @@ xfce_shortcuts_grabber_event_filter (GdkXEvent            *gdk_xevent,
                                      GdkEvent             *event,
                                      XfceShortcutsGrabber *grabber)
 {
-  struct EventKeyFindContext context;
-  XEvent                    *xevent;
-  gint                       timestamp;
+  struct EventKeyFindContext  context;
+  GdkKeymap                  *keymap;
+  GdkModifierType             consumed, modifiers;
+  XEvent                     *xevent;
+  guint                       keyval, mod_mask;
+  gchar                      *raw_shortcut_name;
+  gint                        timestamp;
 
   g_return_val_if_fail (XFCE_IS_SHORTCUTS_GRABBER (grabber), GDK_FILTER_CONTINUE);
 
@@ -602,14 +497,40 @@ xfce_shortcuts_grabber_event_filter (GdkXEvent            *gdk_xevent,
     return GDK_FILTER_CONTINUE;
 
   context.grabber = grabber;
-  context.xevent = (XKeyEvent *) xevent;
   context.result = NULL;
-  timestamp = context.xevent->time;
+  timestamp = xevent->xkey.time;
+
+  /* Get the keyboard state */
+  gdk_error_trap_push ();
+  keymap = gdk_keymap_get_default ();
+  mod_mask = gtk_accelerator_get_default_mod_mask ();
+  modifiers = xevent->xkey.state;
+
+  gdk_keymap_translate_keyboard_state (keymap, xevent->xkey.keycode,
+                                       modifiers,
+                                       XkbGroupForCoreState (xevent->xkey.state),
+                                       &keyval, NULL, NULL, &consumed);
+
+  /* Get the modifiers */
+  modifiers &= ~consumed;
+  gdk_keymap_add_virtual_modifiers (keymap, &modifiers);
+  modifiers &= mod_mask;
+
+  context.keyval = keyval;
+  context.modifiers = modifiers;
+
+  raw_shortcut_name = gtk_accelerator_name (keyval, modifiers);
+  TRACE ("Looking for %s", raw_shortcut_name);
+  g_free (raw_shortcut_name);
 
   g_hash_table_foreach (grabber->priv->keys, (GHFunc) find_event_key, &context);
 
   if (G_LIKELY (context.result != NULL))
-    g_signal_emit_by_name (grabber, "shortcut-activated", context.result, timestamp);
+    g_signal_emit_by_name (grabber, "shortcut-activated",
+                           context.result, timestamp);
+
+  gdk_flush ();
+  gdk_error_trap_pop ();
 
   return GDK_FILTER_CONTINUE;
 }
@@ -635,13 +556,15 @@ xfce_shortcuts_grabber_add (XfceShortcutsGrabber *grabber,
 
   key = g_new0 (XfceKey, 1);
 
-  xfce_shortcuts_grabber_parse_shortcut (grabber, shortcut, &key->keycode, &key->modifiers);
+  gtk_accelerator_parse (shortcut, &key->keyval, &key->modifiers);
 
-  if (G_LIKELY (key->keycode != 0))
+  if (G_LIKELY (key->keyval != 0))
     {
       xfce_shortcuts_grabber_grab (grabber, key, TRUE);
       g_hash_table_insert (grabber->priv->keys, g_strdup (shortcut), key);
     }
+  else
+    g_free (key);
 }
 
 



More information about the Xfce4-commits mailing list