[gnome-settings-daemon] common: Use XInput2 to capture and match keys
- From: Bastien Nocera <hadess src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-settings-daemon] common: Use XInput2 to capture and match keys
- Date: Wed, 2 Nov 2011 20:12:06 +0000 (UTC)
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]