#endif /* HAVE_XINPUT */
static void
-translate_key_event (ClutterBackend *backend,
- ClutterEvent *event,
- XEvent *xevent)
+translate_key_event (ClutterBackendX11 *backend_x11,
+ ClutterEvent *event,
+ XEvent *xevent)
{
ClutterEventX11 *event_x11;
char buffer[256 + 1];
0);
event_x11->key_group =
- _clutter_keymap_x11_get_key_group (event->key.modifier_state);
+ _clutter_keymap_x11_get_key_group (backend_x11->keymap,
+ event->key.modifier_state);
/* unicode_value is the printable representation */
n = XLookupString (&xevent->xkey, buffer, sizeof (buffer) - 1, NULL, NULL);
clutter_device_manager_get_core_device (manager,
CLUTTER_KEYBOARD_DEVICE);
- translate_key_event (backend, event, xevent);
+ translate_key_event (backend_x11, event, xevent);
set_user_time (backend_x11, &xwindow, xevent->xkey.time);
break;
* the next event and check if it's a KeyPress for the same key
* and timestamp - and then ignore it if it matches the
* KeyRelease
+ *
+ * if we have XKB, and autorepeat is enabled, then this becomes
+ * a no-op
*/
- if (XPending (xevent->xkey.display))
+ if (!backend_x11->have_xkb_autorepeat && XPending (xevent->xkey.display))
{
XEvent next_event;
clutter_device_manager_get_core_device (manager,
CLUTTER_KEYBOARD_DEVICE);
- translate_key_event (backend, event, xevent);
+ translate_key_event (backend_x11, event, xevent);
break;
default:
? CLUTTER_KEY_PRESS
: CLUTTER_KEY_RELEASE;
- translate_key_event (backend, event, &xevent_converted);
+ translate_key_event (backend_x11, event, &xevent_converted);
if (xevent->type == key_press)
set_user_time (backend_x11, &xwindow, xkev->time);
#endif
#include "clutter-keymap-x11.h"
+#include "clutter-backend-x11.h"
#include "clutter-debug.h"
#include "clutter-private.h"
GObject parent_instance;
ClutterBackend *backend;
+
+ gint min_keycode;
+ gint max_keycode;
+
+ ClutterModifierType modmap[8];
+
+ ClutterModifierType num_lock_mask;
+
+#ifdef HAVE_XKB
+ XkbDescPtr xkb_desc;
+#endif
};
struct _ClutterKeymapX11Class
G_DEFINE_TYPE (ClutterKeymapX11, clutter_keymap_x11, G_TYPE_OBJECT);
+#ifdef HAVE_XKB
+
+/* code adapted from gdk/x11/gdkkeys-x11.c - update_modmap */
+static void
+update_modmap (Display *display,
+ ClutterKeymapX11 *keymap_x11)
+{
+ static struct {
+ const gchar *name;
+ Atom atom;
+ ClutterModifierType mask;
+ } vmods[] = {
+ { "Meta", 0, CLUTTER_META_MASK },
+ { "Super", 0, CLUTTER_SUPER_MASK },
+ { "Hyper", 0, CLUTTER_HYPER_MASK },
+ { NULL, 0, 0 }
+ };
+
+ int i, j, k;
+
+ if (vmods[0].atom == 0)
+ for (i = 0; vmods[i].name; i++)
+ vmods[i].atom = XInternAtom (display, vmods[i].name, FALSE);
+
+ for (i = 0; i < 8; i++)
+ keymap_x11->modmap[i] = 1 << i;
+
+ for (i = 0; i < XkbNumVirtualMods; i++)
+ {
+ for (j = 0; vmods[j].atom; j++)
+ {
+ if (keymap_x11->xkb_desc->names->vmods[i] == vmods[j].atom)
+ {
+ for (k = 0; k < 8; k++)
+ {
+ if (keymap_x11->xkb_desc->server->vmods[i] & (1 << k))
+ keymap_x11->modmap[k] |= vmods[j].mask;
+ }
+ }
+ }
+ }
+}
+
+static XkbDescPtr
+get_xkb (ClutterKeymapX11 *keymap_x11)
+{
+ ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (keymap_x11->backend);
+
+ if (keymap_x11->max_keycode == 0)
+ XDisplayKeycodes (backend_x11->xdpy,
+ &keymap_x11->min_keycode,
+ &keymap_x11->max_keycode);
+
+ if (keymap_x11->xkb_desc == NULL)
+ {
+ int flags = XkbKeySymsMask
+ | XkbKeyTypesMask
+ | XkbModifierMapMask
+ | XkbVirtualModsMask;
+
+ keymap_x11->xkb_desc = XkbGetMap (backend_x11->xdpy, flags, XkbUseCoreKbd);
+ if (G_UNLIKELY (keymap_x11->xkb_desc == NULL))
+ {
+ g_error ("Failed to get the keymap from XKB");
+ return NULL;
+ }
+
+ flags = XkbGroupNamesMask | XkbVirtualModNamesMask;
+ XkbGetNames (backend_x11->xdpy, flags, keymap_x11->xkb_desc);
+
+ update_modmap (backend_x11->xdpy, keymap_x11);
+ }
+
+ if (keymap_x11->num_lock_mask == 0)
+ keymap_x11->num_lock_mask = XkbKeysymToModifiers (backend_x11->xdpy,
+ XK_Num_Lock);
+
+ return keymap_x11->xkb_desc;
+}
+#endif /* HAVE_XKB */
+
+static void
+clutter_keymap_x11_constructed (GObject *gobject)
+{
+ ClutterKeymapX11 *keymap_x11 = CLUTTER_KEYMAP_X11 (gobject);
+ ClutterBackendX11 *backend_x11;
+
+ g_assert (keymap_x11->backend != NULL);
+ backend_x11 = CLUTTER_BACKEND_X11 (keymap_x11->backend);
+
+#if HAVE_XKB
+ {
+ gint xkb_major = XkbMajorVersion;
+ gint xkb_minor = XkbMinorVersion;
+
+ if (XkbLibraryVersion (&xkb_major, &xkb_minor))
+ {
+ xkb_major = XkbMajorVersion;
+ xkb_minor = XkbMinorVersion;
+
+ if (XkbQueryExtension (backend_x11->xdpy,
+ NULL, &backend_x11->xkb_event_base, NULL,
+ &xkb_major, &xkb_minor))
+ {
+ Bool detectable_autorepeat_supported;
+
+ backend_x11->use_xkb = TRUE;
+
+#if 0
+ /* XXX - enable when we handle keymap-related events */
+ XkbSelectEvents (backend_x11->xdpy,
+ XkbUseCoreKbd,
+ XkbNewKeyboardNotifyMask | XkbMapNotifyMask | XkbStateNotifyMask,
+ XkbNewKeyboardNotifyMask | XkbMapNotifyMask | XkbStateNotifyMask);
+
+ XkbSelectEventDetails (backend_x11->xdpy,
+ XkbUseCoreKbd, XkbStateNotify,
+ XkbAllStateComponentsMask,
+ XkbGroupLockMask|XkbModifierLockMask);
+#endif
+
+ /* enable XKB autorepeat */
+ XkbSetDetectableAutoRepeat (backend_x11->xdpy,
+ True,
+ &detectable_autorepeat_supported);
+
+ backend_x11->have_xkb_autorepeat = detectable_autorepeat_supported;
+
+ CLUTTER_NOTE (BACKEND, "Detectable autorepeat: %s",
+ backend_x11->have_xkb_autorepeat ? "supported"
+ : "not supported");
+ }
+ }
+ }
+#endif /* HAVE_XKB */
+}
+
static void
clutter_keymap_x11_set_property (GObject *gobject,
guint prop_id,
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GParamSpec *pspec;
+ gobject_class->constructed = clutter_keymap_x11_constructed;
gobject_class->set_property = clutter_keymap_x11_set_property;
gobject_class->finalize = clutter_keymap_x11_finalize;
}
gint
-_clutter_keymap_x11_get_key_group (ClutterModifierType state)
+_clutter_keymap_x11_get_key_group (ClutterKeymapX11 *keymap,
+ ClutterModifierType state)
{
#ifdef HAVE_XKB
+ (void) get_xkb (keymap);
+
return XkbGroupForCoreState (state);
#else
return 0;