Blob Blame History Raw
Index: plugins/media-keys/gsd-media-keys-manager.c
===================================================================
--- plugins/media-keys/gsd-media-keys-manager.c	(revision 327)
+++ plugins/media-keys/gsd-media-keys-manager.c	(working copy)
@@ -42,6 +42,12 @@
 #include <dbus/dbus-glib.h>
 #include <dbus/dbus-glib-lowlevel.h>
 
+#ifdef HAVE_X11_EXTENSIONS_XKB_H
+#include <X11/XKBlib.h>
+#include <X11/extensions/XKB.h>
+#include <gdk/gdkkeysyms.h>
+#endif
+
 #include "gnome-settings-profile.h"
 #include "gsd-marshal.h"
 #include "gsd-media-keys-manager.h"
@@ -941,6 +947,65 @@
         return NULL;
 }
 
+static gboolean
+have_xkb (Display *dpy)
+{
+	static int have_xkb = -1;
+
+	if (have_xkb == -1) {
+#ifdef HAVE_X11_EXTENSIONS_XKB_H
+		int opcode, error_base, major, minor, xkb_event_base;
+
+		gdk_error_trap_push ();
+		have_xkb = XkbQueryExtension (dpy,
+					      &opcode,
+					      &xkb_event_base,
+					      &error_base,
+					      &major,
+					      &minor)
+			&& XkbUseExtension (dpy, &major, &minor);
+		gdk_error_trap_pop ();
+#else
+		have_xkb = 0;
+#endif
+	}
+
+	return have_xkb;
+}
+
+static gboolean
+match_key (Key *key, XEvent *event)
+{
+	GdkKeymap *keymap;
+	guint keyval;
+	GdkModifierType consumed;
+	gint group;
+
+	if (key == NULL)
+		return FALSE;
+
+	keymap = gdk_keymap_get_default ();
+	if (have_xkb (event->xkey.display))
+		group = XkbGroupForCoreState (event->xkey.state);
+	else
+		group = (event->xkey.state & GDK_Mode_switch) ? 1 : 0;
+	/* Check if we find a keysym that matches our current state */
+	if (gdk_keymap_translate_keyboard_state (keymap, event->xkey.keycode,
+					     event->xkey.state, group,
+					     &keyval, NULL, NULL, &consumed)) {
+		guint lower, upper;
+
+		gdk_keyval_convert_case (keyval, &lower, &upper);
+		return ((lower == key->keysym || upper == key->keysym)
+			&& (key->state & ~consumed & USED_MODS) == key->state);
+	}
+
+	/* The key we passed doesn't have a keysym, so try with just the keycode */
+        return (key != NULL
+                && key->keycode == event->xkey.keycode
+                && key->state == (event->xkey.state & USED_MODS));
+}
+
 static GdkFilterReturn
 acme_filter_events (GdkXEvent           *xevent,
                     GdkEvent            *event,
@@ -962,12 +1027,7 @@
         state = xev->xkey.state;
 
         for (i = 0; i < HANDLED_KEYS; i++) {
-                if (keys[i].key == NULL) {
-                        continue;
-                }
-
-                if (keys[i].key->keycode == keycode
-                    && (state & USED_MODS) == keys[i].key->state) {
+		if (match_key (keys[i].key, xev)) {
                         switch (keys[i].key_type) {
                         case VOLUME_DOWN_KEY:
                         case VOLUME_UP_KEY: