summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--clutter/clutter/x11/clutter-keymap-x11.c167
-rw-r--r--clutter/clutter/x11/clutter-keymap-x11.h6
-rw-r--r--clutter/clutter/x11/clutter-virtual-input-device-x11.c19
3 files changed, 186 insertions, 6 deletions
diff --git a/clutter/clutter/x11/clutter-keymap-x11.c b/clutter/clutter/x11/clutter-keymap-x11.c
index 32cb5a279..f1bdf16a2 100644
--- a/clutter/clutter/x11/clutter-keymap-x11.c
+++ b/clutter/clutter/x11/clutter-keymap-x11.c
@@ -79,6 +79,9 @@ struct _ClutterKeymapX11
guint current_cache_serial;
DirectionCacheEntry group_direction_cache[4];
int current_group;
+
+ GHashTable *reserved_keycodes;
+ GQueue *available_keycodes;
#endif
guint caps_lock_state : 1;
@@ -441,16 +444,100 @@ clutter_keymap_x11_set_property (GObject *gobject,
}
}
+#ifdef HAVE_XKB
+static void
+clutter_keymap_x11_refresh_reserved_keycodes (ClutterKeymapX11 *keymap_x11)
+{
+ Display *dpy = clutter_x11_get_default_display ();
+ GHashTableIter iter;
+ gpointer key, value;
+
+ g_hash_table_iter_init (&iter, keymap_x11->reserved_keycodes);
+ while (g_hash_table_iter_next (&iter, &key, &value))
+ {
+ guint reserved_keycode = GPOINTER_TO_UINT (key);
+ guint reserved_keysym = GPOINTER_TO_UINT (value);
+ guint actual_keysym = XkbKeycodeToKeysym (dpy, reserved_keycode, 0, 0);
+
+ /* If an available keycode is no longer mapped to the stored keysym, then
+ * the keycode should not be considered available anymore and should be
+ * removed both from the list of available and reserved keycodes.
+ */
+ if (reserved_keysym != actual_keysym)
+ {
+ g_hash_table_iter_remove (&iter);
+ g_queue_remove (keymap_x11->available_keycodes, key);
+ }
+ }
+}
+
+static gboolean
+clutter_keymap_x11_replace_keycode (ClutterKeymapX11 *keymap_x11,
+ KeyCode keycode,
+ KeySym keysym)
+{
+ if (CLUTTER_BACKEND_X11 (keymap_x11->backend)->use_xkb)
+ {
+ Display *dpy = clutter_x11_get_default_display ();
+ XkbDescPtr xkb = get_xkb (keymap_x11);
+ XkbMapChangesRec changes;
+
+ XFlush (dpy);
+
+ xkb->device_spec = XkbUseCoreKbd;
+ memset (&changes, 0, sizeof(changes));
+
+ if (keysym != NoSymbol)
+ {
+ int types[XkbNumKbdGroups] = { XkbOneLevelIndex };
+ XkbChangeTypesOfKey (xkb, keycode, 1, XkbGroup1Mask, types, &changes);
+ XkbKeySymEntry (xkb, keycode, 0, 0) = keysym;
+ }
+ else
+ {
+ /* Reset to NoSymbol */
+ XkbChangeTypesOfKey (xkb, keycode, 0, XkbGroup1Mask, NULL, &changes);
+ }
+
+ changes.changed = XkbKeySymsMask | XkbKeyTypesMask;
+ changes.first_key_sym = keycode;
+ changes.num_key_syms = 1;
+ changes.first_type = 0;
+ changes.num_types = xkb->map->num_types;
+ XkbChangeMap (dpy, xkb, &changes);
+
+ XFlush (dpy);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+#endif
+
static void
clutter_keymap_x11_finalize (GObject *gobject)
{
ClutterKeymapX11 *keymap;
ClutterEventTranslator *translator;
+ GHashTableIter iter;
+ gpointer key, value;
keymap = CLUTTER_KEYMAP_X11 (gobject);
translator = CLUTTER_EVENT_TRANSLATOR (keymap);
#ifdef HAVE_XKB
+ clutter_keymap_x11_refresh_reserved_keycodes (keymap);
+ g_hash_table_iter_init (&iter, keymap->reserved_keycodes);
+ while (g_hash_table_iter_next (&iter, &key, &value))
+ {
+ guint keycode = GPOINTER_TO_UINT (key);
+ clutter_keymap_x11_replace_keycode (keymap, keycode, NoSymbol);
+ }
+
+ g_hash_table_destroy (keymap->reserved_keycodes);
+ g_queue_free (keymap->available_keycodes);
+
_clutter_backend_remove_event_translator (keymap->backend, translator);
if (keymap->xkb_desc != NULL)
@@ -460,6 +547,7 @@ clutter_keymap_x11_finalize (GObject *gobject)
G_OBJECT_CLASS (clutter_keymap_x11_parent_class)->finalize (gobject);
}
+
static void
clutter_keymap_x11_class_init (ClutterKeymapX11Class *klass)
{
@@ -483,6 +571,11 @@ clutter_keymap_x11_init (ClutterKeymapX11 *keymap)
{
keymap->current_direction = PANGO_DIRECTION_NEUTRAL;
keymap->current_group = -1;
+
+#ifdef HAVE_XKB
+ keymap->reserved_keycodes = g_hash_table_new (NULL, NULL);
+ keymap->available_keycodes = g_queue_new ();
+#endif
}
static ClutterTranslateReturn
@@ -766,6 +859,80 @@ clutter_keymap_x11_get_entries_for_keyval (ClutterKeymapX11 *keymap_x11,
}
}
+#ifdef HAVE_XKB
+static guint
+clutter_keymap_x11_get_available_keycode (ClutterKeymapX11 *keymap_x11)
+{
+ if (CLUTTER_BACKEND_X11 (keymap_x11->backend)->use_xkb)
+ {
+ clutter_keymap_x11_refresh_reserved_keycodes (keymap_x11);
+
+ if (g_hash_table_size (keymap_x11->reserved_keycodes) < 5)
+ {
+ Display *dpy = clutter_x11_get_default_display ();
+ XkbDescPtr xkb = get_xkb (keymap_x11);
+ guint i;
+
+ for (i = xkb->max_key_code; i >= xkb->min_key_code; --i)
+ {
+ if (XkbKeycodeToKeysym (dpy, i, 0, 0) == NoSymbol)
+ return i;
+ }
+ }
+
+ return GPOINTER_TO_UINT (g_queue_pop_head (keymap_x11->available_keycodes));
+ }
+
+ return 0;
+}
+#endif
+
+gboolean clutter_keymap_x11_reserve_keycode (ClutterKeymapX11 *keymap_x11,
+ guint keyval,
+ guint *keycode_out)
+{
+ g_return_val_if_fail (CLUTTER_IS_KEYMAP_X11 (keymap_x11), FALSE);
+ g_return_val_if_fail (keyval != 0, FALSE);
+ g_return_val_if_fail (keycode_out != NULL, FALSE);
+
+#ifdef HAVE_XKB
+ *keycode_out = clutter_keymap_x11_get_available_keycode (keymap_x11);
+
+ if (*keycode_out == NoSymbol)
+ {
+ g_warning ("Cannot reserve a keycode for keyval %d: no available keycode", keyval);
+ return FALSE;
+ }
+
+ if (!clutter_keymap_x11_replace_keycode (keymap_x11, *keycode_out, keyval))
+ {
+ g_warning ("Failed to remap keycode %d to keyval %d", *keycode_out, keyval);
+ return FALSE;
+ }
+
+ g_hash_table_insert (keymap_x11->reserved_keycodes, GUINT_TO_POINTER (*keycode_out), GUINT_TO_POINTER (keyval));
+ g_queue_remove (keymap_x11->available_keycodes, GUINT_TO_POINTER (*keycode_out));
+
+ return TRUE;
+#else
+ return FALSE;
+#endif
+}
+
+void clutter_keymap_x11_release_keycode_if_needed (ClutterKeymapX11 *keymap_x11,
+ guint keycode)
+{
+ g_return_if_fail (CLUTTER_IS_KEYMAP_X11 (keymap_x11));
+
+#ifdef HAVE_XKB
+ if (!g_hash_table_contains (keymap_x11->reserved_keycodes, GUINT_TO_POINTER (keycode)) ||
+ g_queue_index (keymap_x11->available_keycodes, GUINT_TO_POINTER (keycode)) != -1)
+ return;
+
+ g_queue_push_tail (keymap_x11->available_keycodes, GUINT_TO_POINTER (keycode));
+#endif
+}
+
void
clutter_keymap_x11_latch_modifiers (ClutterKeymapX11 *keymap_x11,
uint32_t level,
diff --git a/clutter/clutter/x11/clutter-keymap-x11.h b/clutter/clutter/x11/clutter-keymap-x11.h
index 4b5b403c8..4decb44ee 100644
--- a/clutter/clutter/x11/clutter-keymap-x11.h
+++ b/clutter/clutter/x11/clutter-keymap-x11.h
@@ -58,7 +58,11 @@ gboolean clutter_keymap_x11_keycode_for_keyval (ClutterKeymapX11 *keymap_x11,
void clutter_keymap_x11_latch_modifiers (ClutterKeymapX11 *keymap_x11,
uint32_t level,
gboolean enable);
-
+gboolean clutter_keymap_x11_reserve_keycode (ClutterKeymapX11 *keymap_x11,
+ guint keyval,
+ guint *keycode_out);
+void clutter_keymap_x11_release_keycode_if_needed (ClutterKeymapX11 *keymap_x11,
+ guint keycode);
G_END_DECLS
#endif /* __CLUTTER_KEYMAP_X11_H__ */
diff --git a/clutter/clutter/x11/clutter-virtual-input-device-x11.c b/clutter/clutter/x11/clutter-virtual-input-device-x11.c
index e16ba3fd0..cab26c38c 100644
--- a/clutter/clutter/x11/clutter-virtual-input-device-x11.c
+++ b/clutter/clutter/x11/clutter-virtual-input-device-x11.c
@@ -143,8 +143,13 @@ clutter_virtual_input_device_x11_notify_keyval (ClutterVirtualInputDevice *virtu
if (!clutter_keymap_x11_keycode_for_keyval (keymap, keyval, &keycode, &level))
{
- g_warning ("No keycode found for keyval %x in current group", keyval);
- return;
+ level = 0;
+
+ if (!clutter_keymap_x11_reserve_keycode (keymap, keyval, &keycode))
+ {
+ g_warning ("No keycode found for keyval %x in current group", keyval);
+ return;
+ }
}
if (!_clutter_keymap_x11_get_is_modifier (keymap, keycode) &&
@@ -155,9 +160,13 @@ clutter_virtual_input_device_x11_notify_keyval (ClutterVirtualInputDevice *virtu
(KeyCode) keycode,
key_state == CLUTTER_KEY_STATE_PRESSED, 0);
- if (!_clutter_keymap_x11_get_is_modifier (keymap, keycode) &&
- key_state == CLUTTER_KEY_STATE_RELEASED)
- clutter_keymap_x11_latch_modifiers (keymap, level, FALSE);
+
+ if (key_state == CLUTTER_KEY_STATE_RELEASED)
+ {
+ if (!_clutter_keymap_x11_get_is_modifier (keymap, keycode))
+ clutter_keymap_x11_latch_modifiers (keymap, level, FALSE);
+ clutter_keymap_x11_release_keycode_if_needed (keymap, keycode);
+ }
}
static void