[gnome-settings-daemon] common: Use XInput2 to capture and match keys



commit beafbd4b188d6cfd90c66d65e2a3b602fddf1963
Author: Bastien Nocera <hadess hadess net>
Date:   Mon Oct 31 16:14:36 2011 +0000

    common: Use XInput2 to capture and match keys

 plugins/common/gsd-keygrab.c |  159 ++++++++++++++++++++++++++++++++++--------
 plugins/common/gsd-keygrab.h |    9 ++-
 2 files changed, 136 insertions(+), 32 deletions(-)
---
diff --git a/plugins/common/gsd-keygrab.c b/plugins/common/gsd-keygrab.c
index 0ea4270..26abe9d 100644
--- a/plugins/common/gsd-keygrab.c
+++ b/plugins/common/gsd-keygrab.c
@@ -22,9 +22,11 @@
 
 #include "config.h"
 
+#include <string.h>
 #include <gdk/gdk.h>
 #include <gdk/gdkx.h>
 #include <X11/XKBlib.h>
+#include <X11/extensions/XInput2.h>
 #include <X11/extensions/XKB.h>
 #include <gdk/gdkkeysyms.h>
 
@@ -78,21 +80,38 @@ static void
 grab_key_real (guint      keycode,
                GdkWindow *root,
                gboolean   grab,
-               int        mask)
+               XIGrabModifiers *mods,
+               int        num_mods)
 {
+	XIEventMask evmask;
+	unsigned char mask[(XI_LASTEVENT + 7)/8];
+
+	memset (mask, 0, sizeof (mask));
+	XISetMask (mask, XI_KeyPress);
+	XISetMask (mask, XI_KeyRelease);
+
+	evmask.deviceid = XIAllMasterDevices;
+	evmask.mask_len = sizeof (mask);
+	evmask.mask = mask;
+
         if (grab) {
-                XGrabKey (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
-                          keycode,
-                          mask,
-                          GDK_WINDOW_XID (root),
-                          True,
-                          GrabModeAsync,
-                          GrabModeAsync);
+                XIGrabKeycode (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
+                               XIAllMasterDevices,
+                               keycode,
+                               GDK_WINDOW_XID (root),
+                               GrabModeAsync,
+                               GrabModeAsync,
+                               False,
+                               &evmask,
+                               num_mods,
+                               mods);
         } else {
-                XUngrabKey (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
-                            keycode,
-                            mask,
-                            GDK_WINDOW_XID (root));
+                XIUngrabKeycode (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
+                                 XIAllMasterDevices,
+                                 keycode,
+                                 GDK_WINDOW_XID (root),
+                                 num_mods,
+                                 mods);
         }
 }
 
@@ -122,12 +141,14 @@ grab_key_unsafe (Key                 *key,
                  gboolean             grab,
                  GSList              *screens)
 {
-        int   indexes[N_BITS]; /* indexes of bits we need to flip */
-        int   i;
-        int   bit;
-        int   bits_set_cnt;
-        int   uppervalue;
-        guint mask, modifiers;
+        int     indexes[N_BITS]; /* indexes of bits we need to flip */
+        int     i;
+        int     bit;
+        int     bits_set_cnt;
+        int     uppervalue;
+        guint   mask, modifiers;
+        GArray *all_mods;
+        GSList *l;
 
         setup_modifiers ();
 
@@ -175,12 +196,13 @@ grab_key_unsafe (Key                 *key,
 
         bits_set_cnt = bit;
 
+	all_mods = g_array_new (FALSE, TRUE, sizeof(XIGrabModifiers));
         uppervalue = 1 << bits_set_cnt;
-        /* grab all possible modifier combinations for our mask */
+        /* store all possible modifier combinations for our mask into all_mods */
         for (i = 0; i < uppervalue; ++i) {
-                GSList *l;
                 int     j;
                 int     result = 0;
+                XIGrabModifiers *mod;
 
                 /* map bits in the counter to those in the mask */
                 for (j = 0; j < bits_set_cnt; ++j) {
@@ -189,18 +211,26 @@ grab_key_unsafe (Key                 *key,
                         }
                 }
 
-                for (l = screens; l; l = l->next) {
-                        GdkScreen *screen = l->data;
-                        guint *code;
+                /* Grow the array by one, to fit our new XIGrabModifiers item */
+                g_array_set_size (all_mods, all_mods->len + 1);
+                mod = &g_array_index (all_mods, XIGrabModifiers, all_mods->len - 1);
+                mod->modifiers = result | modifiers;
+        }
 
-                        for (code = key->keycodes; *code; ++code) {
-                                grab_key_real (*code,
-                                               gdk_screen_get_root_window (screen),
-                                               grab,
-                                               result | modifiers);
-                        }
+	/* Capture the actual keycodes with the modifier array */
+        for (l = screens; l; l = l->next) {
+                GdkScreen *screen = l->data;
+                guint *code;
+
+                for (code = key->keycodes; *code; ++code) {
+                        grab_key_real (*code,
+                                       gdk_screen_get_root_window (screen),
+                                       grab,
+                                       (XIGrabModifiers *) all_mods->data,
+                                       all_mods->len);
                 }
         }
+        g_array_free (all_mods, TRUE);
 }
 
 static gboolean
@@ -237,6 +267,77 @@ key_uses_keycode (const Key *key, guint keycode)
 	return FALSE;
 }
 
+/* Adapted from _gdk_x11_device_xi2_translate_state()
+ * in gtk+/gdk/x11/gdkdevice-xi2.c */
+static guint
+device_xi2_translate_state (XIModifierState *mods_state,
+			    XIGroupState    *group_state)
+{
+	guint state;
+	gint group;
+
+	state = (guint) mods_state->base | mods_state->latched | mods_state->locked;
+
+	group = group_state->base | group_state->latched | group_state->locked;
+	/* FIXME: do we need the XKB complications for this ? */
+	group = CLAMP(group, 0, 3);
+	state |= group << 13;
+
+	return state;
+}
+
+gboolean
+match_xi2_key (Key *key, XIDeviceEvent *event)
+{
+	guint keyval;
+	GdkModifierType consumed;
+	gint group;
+	guint keycode, state;
+
+	if (key == NULL)
+		return FALSE;
+
+	setup_modifiers ();
+
+	state = device_xi2_translate_state (&event->mods, &event->group);
+
+	if (have_xkb (event->display))
+		group = XkbGroupForCoreState (state);
+	else
+		group = (state & GDK_KEY_Mode_switch) ? 1 : 0;
+
+	keycode = event->detail;
+
+	/* Check if we find a keysym that matches our current state */
+	if (gdk_keymap_translate_keyboard_state (gdk_keymap_get_default (), keycode,
+						 state, group,
+						 &keyval, NULL, NULL, &consumed)) {
+		guint lower, upper;
+		guint mask;
+
+		/* The Key structure contains virtual modifiers, whereas
+		 * the XEvent will be using the real modifier, so translate those */
+		egg_keymap_resolve_virtual_modifiers (gdk_keymap_get_default (),
+						      key->state, &mask);
+
+		gdk_keyval_convert_case (keyval, &lower, &upper);
+
+		/* If we are checking against the lower version of the
+		 * keysym, we might need the Shift state for matching,
+		 * so remove it from the consumed modifiers */
+		if (lower == key->keysym)
+			consumed &= ~GDK_SHIFT_MASK;
+
+		return ((lower == key->keysym || upper == key->keysym)
+			&& (state & ~consumed & gsd_used_mods) == mask);
+	}
+
+	/* The key we passed doesn't have a keysym, so try with just the keycode */
+        return (key != NULL
+                && key->state == (state & gsd_used_mods)
+                && key_uses_keycode (key, keycode));
+}
+
 gboolean
 match_key (Key *key, XEvent *event)
 {
diff --git a/plugins/common/gsd-keygrab.h b/plugins/common/gsd-keygrab.h
index c5cdb7a..90957b3 100644
--- a/plugins/common/gsd-keygrab.h
+++ b/plugins/common/gsd-keygrab.h
@@ -24,6 +24,7 @@ G_BEGIN_DECLS
 
 #include <glib.h>
 #include <X11/keysym.h>
+#include <X11/extensions/XInput2.h>
 
 typedef struct {
         guint keysym;
@@ -33,11 +34,13 @@ typedef struct {
 
 
 void	        grab_key_unsafe	(Key     *key,
-		        	 gboolean grab,
+				 gboolean grab,
 			         GSList  *screens);
 
-gboolean        match_key       (Key     *key,
-                                 XEvent  *event);
+gboolean        match_xi2_key   (Key           *key,
+                                 XIDeviceEvent *event);
+gboolean        match_key       (Key           *key,
+				 XEvent        *event);
 
 gboolean        key_uses_keycode (const Key *key,
                                   guint keycode);



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