[Xfce4-commits] <libxfce4ui:jeromeg/keyboard-shortcuts-rework> Rework grabbing/ungrabbing code.
Jérôme Guelfucci
noreply at xfce.org
Sun May 29 17:50:02 CEST 2011
Updating branch refs/heads/jeromeg/keyboard-shortcuts-rework
to 13251f7a7ab201dd20186d81ca11e21922d35628 (commit)
from 310a4d7d9d3834e7ee074359973f52cc1e186502 (commit)
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.
libxfce4kbd-private/xfce-shortcuts-grabber.c | 327 +++++++++++---------------
1 files changed, 133 insertions(+), 194 deletions(-)
diff --git a/libxfce4kbd-private/xfce-shortcuts-grabber.c b/libxfce4kbd-private/xfce-shortcuts-grabber.c
index 642ecc0..4013840 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,37 +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)
-
-
-
-/* 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;
@@ -84,15 +56,9 @@ static void xfce_shortcuts_grabber_keys_changed (GdkKeymap
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);
@@ -102,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;
};
@@ -154,8 +119,6 @@ xfce_shortcuts_grabber_init (XfceShortcutsGrabber *grabber)
* updates it.
*/
(void) gdk_keymap_have_bidi_layouts (gdk_keymap_get_default ());
-
- xfce_shortcuts_grabber_reload_modifiers (grabber);
}
@@ -203,7 +166,6 @@ xfce_shortcuts_grabber_keys_changed (GdkKeymap *keymap,
g_return_if_fail (XFCE_IS_SHORTCUTS_GRABBER (grabber));
xfce_shortcuts_grabber_ungrab_all (grabber);
- xfce_shortcuts_grabber_reload_modifiers (grabber);
xfce_shortcuts_grabber_grab_all (grabber);
}
@@ -249,109 +211,66 @@ 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 ());
-
- gdk_error_trap_push ();
-
- XDisplayKeycodes (display, &min_keycode, &max_keycode);
-
- keymap = XGetKeyboardMapping (display, min_keycode, max_keycode - min_keycode + 1,
- &keysyms_per_keycode);
+ XkbKeyTypeRec *type;
+ int nKeyGroups;
+ int effectiveGroup;
+ int k;
- if (G_UNLIKELY (keymap == NULL))
- return;
+ nKeyGroups = XkbKeyNumGroups (xkb, key);
- modmap = XGetModifierMapping (display);
+ if ((!XkbKeycodeInRange (xkb, key)) || (nKeyGroups == 0))
+ return MODIFIERS_ERROR;
- if (G_UNLIKELY (modmap == NULL))
- {
- XFree (keymap);
- return;
- }
+ /* Taken from GDK's MyEnhancedXkbTranslateKeyCode */
+ /* find the offset of the effective group */
+ effectiveGroup = group;
- for (i = 0; i < 8 * modmap->max_keypermod; ++i)
+ if (effectiveGroup >= nKeyGroups)
{
- keycode = modmap->modifiermap[i];
-
- if (keycode == 0 || keycode < min_keycode || keycode > max_keycode)
- continue;
+ unsigned groupInfo = XkbKeyGroupInfo (xkb,key);
- keysyms = keymap + (keycode - min_keycode) * keysyms_per_keycode;
- mask = 1 << (i / modmap->max_keypermod);
-
- 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;
-
- if (keysyms[j] == GDK_Num_Lock)
- grabber->priv->modifiers[CACHE_NUM_LOCK] = mask;
-
- if (keysyms[j] == GDK_Caps_Lock)
- grabber->priv->modifiers[CACHE_CAPS_LOCK] = mask;
+ default:
+ effectiveGroup %= nKeyGroups;
+ break;
+ case XkbClampIntoRange:
+ effectiveGroup = nKeyGroups-1;
+ break;
+ case XkbRedirectIntoRange:
+ effectiveGroup = XkbOutOfRangeGroupNumber (groupInfo);
+ if (effectiveGroup >= nKeyGroups)
+ effectiveGroup = 0;
+ break;
}
}
- XFreeModifiermap (modmap);
- XFree (keymap);
-
- gdk_flush ();
- gdk_error_trap_pop ();
-}
-
+ type = XkbKeyKeyType (xkb, key, effectiveGroup);
+ 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;
+ }
+ }
-static void
-xfce_shortcuts_grabber_parse_shortcut (XfceShortcutsGrabber *grabber,
- const gchar *shortcut,
- guint *keycode,
- guint *modifiers)
-{
- gchar *parsed_name;
- guint keyval;
-
- g_return_if_fail (XFCE_IS_SHORTCUTS_GRABBER (grabber));
-
- gtk_accelerator_parse (shortcut, &keyval, modifiers);
-
- /* Map virtual modifiers to non-virtual modifiers */
- gdk_keymap_map_virtual_modifiers (gdk_keymap_get_default (),
- modifiers);
-
- *keycode = XKeysymToKeycode (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), keyval);
-
- parsed_name = gtk_accelerator_name (keyval, *modifiers);
- TRACE ("Parsed %s", parsed_name);
- g_free (parsed_name);
+ return MODIFIERS_NONE;
}
@@ -361,81 +280,105 @@ 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;
+ GdkKeymapKey *keys;
+ XkbDescPtr xmap;
+ GdkDisplay *display;
+ GdkKeymap *keymap;
+ 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);
display = gdk_display_get_default ();
screens = gdk_display_get_n_screens (display);
+ keymap = gdk_keymap_get_default ();
- ignored_modifiers = xfce_shortcuts_grabber_get_ignore_mask (grabber);
+ /* Map virtual modifiers to non-virtual modifiers */
+ modifiers = key->modifiers;
+ gdk_keymap_map_virtual_modifiers (keymap, &modifiers);
- modifiers = key->modifiers & MODIFIER_MASK & ~ignored_modifiers;
+ if (modifiers == key->modifiers &&
+ (GDK_SUPER_MASK | GDK_HYPER_MASK | GDK_META_MASK) & modifiers)
+ {
+ TRACE ("Failed to map virtual modifiers");
+ return;
+ }
+
+ xmap = XkbGetMap (GDK_DISPLAY_XDISPLAY (display),
+ XkbAllClientInfoMask,
+ XkbUseCoreKbd);
- /* 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 (!gdk_keymap_get_entries_for_keyval (keymap,key->keyval,
+ &keys, &n_keys)
+ || n_keys == 0)
+ {
+ XkbFreeClientMap (xmap, 0, TRUE);
+ TRACE ("Got no keys for keyval");
+ return;
+ }
- for (i = 0; i < (1 << n_bits); ++i)
+ for (i = 0; i < n_keys; 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)
+ /* Grab all hardware keys generating keyval */
+ GdkModifierType add_modifiers;
+
+ add_modifiers = FinallyGetModifiersForKeycode (xmap,
+ keys[i].keycode,
+ keys[i].group,
+ keys[i].level);
+
+ if (add_modifiers == MODIFIERS_ERROR)
+ continue;
+
+ 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_MOD2_MASK | GDK_LOCK_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 ();
}
}
-}
-
-
-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);
}
@@ -456,7 +399,6 @@ find_event_key (const gchar *shortcut,
struct EventKeyFindContext *context)
{
GdkModifierType ignored;
- guint keycode;
g_return_val_if_fail (context != NULL, FALSE);
@@ -464,10 +406,6 @@ find_event_key (const gchar *shortcut,
ignored = 0;
- keycode =
- XKeysymToKeycode (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
- context->keyval);
-
/* Accept MOD1 + META as MOD1 */
if (key->modifiers & context->modifiers & GDK_MOD1_MASK)
{
@@ -478,13 +416,12 @@ find_event_key (const gchar *shortcut,
/* Accept SUPER + HYPER as SUPER */
if (key->modifiers & context->modifiers & GDK_SUPER_MASK)
{
- TRACE ("Ignoring Hyper and Mod4 Masks");
+ TRACE ("Ignoring Hyper Mask");
ignored |= GDK_HYPER_MASK;
- ignored |= GDK_MOD4_MASK;
}
if ((key->modifiers & ~ignored) == (context->modifiers & ~ignored)
- && key->keycode == keycode)
+ && key->keyval == context->keyval)
{
context->result = shortcut;
@@ -577,13 +514,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