|
|
41c151 |
From 8dfcfa0607754caab5032532ccc9d97b4393708e Mon Sep 17 00:00:00 2001
|
|
|
41c151 |
From: Carlos Garnacho <carlosg@gnome.org>
|
|
|
41c151 |
Date: Fri, 29 Jun 2018 14:31:23 +0200
|
|
|
41c151 |
Subject: [PATCH] clutter/x11: Implement keycode lookup from keysyms on virtual
|
|
|
41c151 |
key devices
|
|
|
41c151 |
|
|
|
41c151 |
Unfortunately XKeysymToKeycode() falls short in that it coalesces keysyms
|
|
|
41c151 |
into keycodes pertaining to the first level (i.e. lowercase). Add a
|
|
|
41c151 |
ClutterKeymapX11 method (much alike its GdkKeymap counterpart) to look up
|
|
|
41c151 |
all matches for the given keysym.
|
|
|
41c151 |
|
|
|
41c151 |
Two other helper methods have been added so the virtual device can fetch
|
|
|
41c151 |
the current keyboard group, and latch modifiers for key emission. Combining
|
|
|
41c151 |
all this, the virtual device is now able to handle keycodes in further
|
|
|
41c151 |
levels.
|
|
|
41c151 |
|
|
|
41c151 |
Closes: https://gitlab.gnome.org/GNOME/gnome-shell/issues/135
|
|
|
41c151 |
|
|
|
41c151 |
(cherry picked from commit 85284acb000ddc70afcf716b6c198b4b5bf5741e)
|
|
|
41c151 |
---
|
|
|
41c151 |
clutter/clutter/x11/clutter-keymap-x11.c | 178 +++++++++++++++++-
|
|
|
41c151 |
clutter/clutter/x11/clutter-keymap-x11.h | 8 +
|
|
|
41c151 |
.../x11/clutter-virtual-input-device-x11.c | 22 ++-
|
|
|
41c151 |
3 files changed, 204 insertions(+), 4 deletions(-)
|
|
|
41c151 |
|
|
|
41c151 |
diff --git a/clutter/clutter/x11/clutter-keymap-x11.c b/clutter/clutter/x11/clutter-keymap-x11.c
|
|
|
41c151 |
index 914e31434..c34e676a4 100644
|
|
|
41c151 |
--- a/clutter/clutter/x11/clutter-keymap-x11.c
|
|
|
41c151 |
+++ b/clutter/clutter/x11/clutter-keymap-x11.c
|
|
|
41c151 |
@@ -38,6 +38,14 @@
|
|
|
41c151 |
|
|
|
41c151 |
typedef struct _ClutterKeymapX11Class ClutterKeymapX11Class;
|
|
|
41c151 |
typedef struct _DirectionCacheEntry DirectionCacheEntry;
|
|
|
41c151 |
+typedef struct _ClutterKeymapKey ClutterKeymapKey;
|
|
|
41c151 |
+
|
|
|
41c151 |
+struct _ClutterKeymapKey
|
|
|
41c151 |
+{
|
|
|
41c151 |
+ guint keycode;
|
|
|
41c151 |
+ guint group;
|
|
|
41c151 |
+ guint level;
|
|
|
41c151 |
+};
|
|
|
41c151 |
|
|
|
41c151 |
struct _DirectionCacheEntry
|
|
|
41c151 |
{
|
|
|
41c151 |
@@ -59,6 +67,7 @@ struct _ClutterKeymapX11
|
|
|
41c151 |
|
|
|
41c151 |
ClutterModifierType num_lock_mask;
|
|
|
41c151 |
ClutterModifierType scroll_lock_mask;
|
|
|
41c151 |
+ ClutterModifierType level3_shift_mask;
|
|
|
41c151 |
|
|
|
41c151 |
PangoDirection current_direction;
|
|
|
41c151 |
|
|
|
41c151 |
@@ -69,6 +78,7 @@ struct _ClutterKeymapX11
|
|
|
41c151 |
Atom current_group_atom;
|
|
|
41c151 |
guint current_cache_serial;
|
|
|
41c151 |
DirectionCacheEntry group_direction_cache[4];
|
|
|
41c151 |
+ int current_group;
|
|
|
41c151 |
#endif
|
|
|
41c151 |
|
|
|
41c151 |
guint caps_lock_state : 1;
|
|
|
41c151 |
@@ -198,6 +208,9 @@ get_xkb (ClutterKeymapX11 *keymap_x11)
|
|
|
41c151 |
if (keymap_x11->scroll_lock_mask == 0)
|
|
|
41c151 |
keymap_x11->scroll_lock_mask = XkbKeysymToModifiers (backend_x11->xdpy,
|
|
|
41c151 |
XK_Scroll_Lock);
|
|
|
41c151 |
+ if (keymap_x11->level3_shift_mask == 0)
|
|
|
41c151 |
+ keymap_x11->level3_shift_mask = XkbKeysymToModifiers (backend_x11->xdpy,
|
|
|
41c151 |
+ XK_ISO_Level3_Shift);
|
|
|
41c151 |
|
|
|
41c151 |
return keymap_x11->xkb_desc;
|
|
|
41c151 |
}
|
|
|
41c151 |
@@ -469,6 +482,7 @@ static void
|
|
|
41c151 |
clutter_keymap_x11_init (ClutterKeymapX11 *keymap)
|
|
|
41c151 |
{
|
|
|
41c151 |
keymap->current_direction = PANGO_DIRECTION_NEUTRAL;
|
|
|
41c151 |
+ keymap->current_group = -1;
|
|
|
41c151 |
}
|
|
|
41c151 |
|
|
|
41c151 |
static ClutterTranslateReturn
|
|
|
41c151 |
@@ -498,7 +512,8 @@ clutter_keymap_x11_translate_event (ClutterEventTranslator *translator,
|
|
|
41c151 |
{
|
|
|
41c151 |
case XkbStateNotify:
|
|
|
41c151 |
CLUTTER_NOTE (EVENT, "Updating keyboard state");
|
|
|
41c151 |
- update_direction (keymap_x11, XkbStateGroup (&xkb_event->state));
|
|
|
41c151 |
+ keymap_x11->current_group = XkbStateGroup (&xkb_event->state);
|
|
|
41c151 |
+ update_direction (keymap_x11, keymap_x11->current_group);
|
|
|
41c151 |
update_locked_mods (keymap_x11, xkb_event->state.locked_mods);
|
|
|
41c151 |
retval = CLUTTER_TRANSLATE_REMOVE;
|
|
|
41c151 |
break;
|
|
|
41c151 |
@@ -665,3 +680,164 @@ _clutter_keymap_x11_get_direction (ClutterKeymapX11 *keymap)
|
|
|
41c151 |
#endif
|
|
|
41c151 |
return PANGO_DIRECTION_NEUTRAL;
|
|
|
41c151 |
}
|
|
|
41c151 |
+
|
|
|
41c151 |
+static gboolean
|
|
|
41c151 |
+clutter_keymap_x11_get_entries_for_keyval (ClutterKeymapX11 *keymap_x11,
|
|
|
41c151 |
+ guint keyval,
|
|
|
41c151 |
+ ClutterKeymapKey **keys,
|
|
|
41c151 |
+ gint *n_keys)
|
|
|
41c151 |
+{
|
|
|
41c151 |
+#ifdef HAVE_XKB
|
|
|
41c151 |
+ if (CLUTTER_BACKEND_X11 (keymap_x11->backend)->use_xkb)
|
|
|
41c151 |
+ {
|
|
|
41c151 |
+ XkbDescRec *xkb = get_xkb (keymap_x11);
|
|
|
41c151 |
+ GArray *retval;
|
|
|
41c151 |
+ gint keycode;
|
|
|
41c151 |
+
|
|
|
41c151 |
+ keycode = keymap_x11->min_keycode;
|
|
|
41c151 |
+ retval = g_array_new (FALSE, FALSE, sizeof (ClutterKeymapKey));
|
|
|
41c151 |
+
|
|
|
41c151 |
+ while (keycode <= keymap_x11->max_keycode)
|
|
|
41c151 |
+ {
|
|
|
41c151 |
+ gint max_shift_levels = XkbKeyGroupsWidth (xkb, keycode);
|
|
|
41c151 |
+ gint group = 0;
|
|
|
41c151 |
+ gint level = 0;
|
|
|
41c151 |
+ gint total_syms = XkbKeyNumSyms (xkb, keycode);
|
|
|
41c151 |
+ gint i = 0;
|
|
|
41c151 |
+ KeySym *entry;
|
|
|
41c151 |
+
|
|
|
41c151 |
+ /* entry is an array with all syms for group 0, all
|
|
|
41c151 |
+ * syms for group 1, etc. and for each group the
|
|
|
41c151 |
+ * shift level syms are in order
|
|
|
41c151 |
+ */
|
|
|
41c151 |
+ entry = XkbKeySymsPtr (xkb, keycode);
|
|
|
41c151 |
+
|
|
|
41c151 |
+ while (i < total_syms)
|
|
|
41c151 |
+ {
|
|
|
41c151 |
+ g_assert (i == (group * max_shift_levels + level));
|
|
|
41c151 |
+
|
|
|
41c151 |
+ if (entry[i] == keyval)
|
|
|
41c151 |
+ {
|
|
|
41c151 |
+ ClutterKeymapKey key;
|
|
|
41c151 |
+
|
|
|
41c151 |
+ key.keycode = keycode;
|
|
|
41c151 |
+ key.group = group;
|
|
|
41c151 |
+ key.level = level;
|
|
|
41c151 |
+
|
|
|
41c151 |
+ g_array_append_val (retval, key);
|
|
|
41c151 |
+
|
|
|
41c151 |
+ g_assert (XkbKeySymEntry (xkb, keycode, level, group) ==
|
|
|
41c151 |
+ keyval);
|
|
|
41c151 |
+ }
|
|
|
41c151 |
+
|
|
|
41c151 |
+ ++level;
|
|
|
41c151 |
+
|
|
|
41c151 |
+ if (level == max_shift_levels)
|
|
|
41c151 |
+ {
|
|
|
41c151 |
+ level = 0;
|
|
|
41c151 |
+ ++group;
|
|
|
41c151 |
+ }
|
|
|
41c151 |
+
|
|
|
41c151 |
+ ++i;
|
|
|
41c151 |
+ }
|
|
|
41c151 |
+
|
|
|
41c151 |
+ ++keycode;
|
|
|
41c151 |
+ }
|
|
|
41c151 |
+
|
|
|
41c151 |
+ if (retval->len > 0)
|
|
|
41c151 |
+ {
|
|
|
41c151 |
+ *keys = (ClutterKeymapKey*) retval->data;
|
|
|
41c151 |
+ *n_keys = retval->len;
|
|
|
41c151 |
+ }
|
|
|
41c151 |
+ else
|
|
|
41c151 |
+ {
|
|
|
41c151 |
+ *keys = NULL;
|
|
|
41c151 |
+ *n_keys = 0;
|
|
|
41c151 |
+ }
|
|
|
41c151 |
+
|
|
|
41c151 |
+ g_array_free (retval, retval->len > 0 ? FALSE : TRUE);
|
|
|
41c151 |
+
|
|
|
41c151 |
+ return *n_keys > 0;
|
|
|
41c151 |
+ }
|
|
|
41c151 |
+ else
|
|
|
41c151 |
+#endif
|
|
|
41c151 |
+ {
|
|
|
41c151 |
+ return FALSE;
|
|
|
41c151 |
+ }
|
|
|
41c151 |
+}
|
|
|
41c151 |
+
|
|
|
41c151 |
+void
|
|
|
41c151 |
+clutter_keymap_x11_latch_modifiers (ClutterKeymapX11 *keymap_x11,
|
|
|
41c151 |
+ uint32_t level,
|
|
|
41c151 |
+ gboolean enable)
|
|
|
41c151 |
+{
|
|
|
41c151 |
+#ifdef HAVE_XKB
|
|
|
41c151 |
+ ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (keymap_x11->backend);
|
|
|
41c151 |
+ uint32_t modifiers[] = {
|
|
|
41c151 |
+ 0,
|
|
|
41c151 |
+ ShiftMask,
|
|
|
41c151 |
+ keymap_x11->level3_shift_mask,
|
|
|
41c151 |
+ keymap_x11->level3_shift_mask | ShiftMask,
|
|
|
41c151 |
+ };
|
|
|
41c151 |
+ uint32_t value = 0;
|
|
|
41c151 |
+
|
|
|
41c151 |
+ if (!backend_x11->use_xkb)
|
|
|
41c151 |
+ return;
|
|
|
41c151 |
+
|
|
|
41c151 |
+ level = CLAMP (level, 0, G_N_ELEMENTS (modifiers) - 1);
|
|
|
41c151 |
+
|
|
|
41c151 |
+ if (enable)
|
|
|
41c151 |
+ value = modifiers[level];
|
|
|
41c151 |
+ else
|
|
|
41c151 |
+ value = 0;
|
|
|
41c151 |
+
|
|
|
41c151 |
+ XkbLatchModifiers (clutter_x11_get_default_display (),
|
|
|
41c151 |
+ XkbUseCoreKbd, modifiers[level],
|
|
|
41c151 |
+ value);
|
|
|
41c151 |
+#endif
|
|
|
41c151 |
+}
|
|
|
41c151 |
+
|
|
|
41c151 |
+static uint32_t
|
|
|
41c151 |
+clutter_keymap_x11_get_current_group (ClutterKeymapX11 *keymap_x11)
|
|
|
41c151 |
+{
|
|
|
41c151 |
+ ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (keymap_x11->backend);
|
|
|
41c151 |
+ XkbStateRec state_rec;
|
|
|
41c151 |
+
|
|
|
41c151 |
+ if (keymap_x11->current_group >= 0)
|
|
|
41c151 |
+ return keymap_x11->current_group;
|
|
|
41c151 |
+
|
|
|
41c151 |
+ XkbGetState (backend_x11->xdpy, XkbUseCoreKbd, &state_rec);
|
|
|
41c151 |
+ return XkbStateGroup (&state_rec);
|
|
|
41c151 |
+}
|
|
|
41c151 |
+
|
|
|
41c151 |
+gboolean
|
|
|
41c151 |
+clutter_keymap_x11_keycode_for_keyval (ClutterKeymapX11 *keymap_x11,
|
|
|
41c151 |
+ guint keyval,
|
|
|
41c151 |
+ guint *keycode_out,
|
|
|
41c151 |
+ guint *level_out)
|
|
|
41c151 |
+{
|
|
|
41c151 |
+ ClutterKeymapKey *keys;
|
|
|
41c151 |
+ gint i, n_keys, group;
|
|
|
41c151 |
+ gboolean found = FALSE;
|
|
|
41c151 |
+
|
|
|
41c151 |
+ g_return_val_if_fail (keycode_out != NULL, FALSE);
|
|
|
41c151 |
+ g_return_val_if_fail (level_out != NULL, FALSE);
|
|
|
41c151 |
+
|
|
|
41c151 |
+ group = clutter_keymap_x11_get_current_group (keymap_x11);
|
|
|
41c151 |
+
|
|
|
41c151 |
+ if (!clutter_keymap_x11_get_entries_for_keyval (keymap_x11, keyval, &keys, &n_keys))
|
|
|
41c151 |
+ return FALSE;
|
|
|
41c151 |
+
|
|
|
41c151 |
+ for (i = 0; i < n_keys && !found; i++)
|
|
|
41c151 |
+ {
|
|
|
41c151 |
+ if (keys[i].group == group)
|
|
|
41c151 |
+ {
|
|
|
41c151 |
+ *keycode_out = keys[i].keycode;
|
|
|
41c151 |
+ *level_out = keys[i].level;
|
|
|
41c151 |
+ found = TRUE;
|
|
|
41c151 |
+ }
|
|
|
41c151 |
+ }
|
|
|
41c151 |
+
|
|
|
41c151 |
+ g_free (keys);
|
|
|
41c151 |
+ return found;
|
|
|
41c151 |
+}
|
|
|
41c151 |
diff --git a/clutter/clutter/x11/clutter-keymap-x11.h b/clutter/clutter/x11/clutter-keymap-x11.h
|
|
|
41c151 |
index ad673a2a7..4b5b403c8 100644
|
|
|
41c151 |
--- a/clutter/clutter/x11/clutter-keymap-x11.h
|
|
|
41c151 |
+++ b/clutter/clutter/x11/clutter-keymap-x11.h
|
|
|
41c151 |
@@ -51,6 +51,14 @@ gboolean _clutter_keymap_x11_get_is_modifier (ClutterKeymapX11 *keymap,
|
|
|
41c151 |
|
|
|
41c151 |
PangoDirection _clutter_keymap_x11_get_direction (ClutterKeymapX11 *keymap);
|
|
|
41c151 |
|
|
|
41c151 |
+gboolean clutter_keymap_x11_keycode_for_keyval (ClutterKeymapX11 *keymap_x11,
|
|
|
41c151 |
+ guint keyval,
|
|
|
41c151 |
+ guint *keycode_out,
|
|
|
41c151 |
+ guint *level_out);
|
|
|
41c151 |
+void clutter_keymap_x11_latch_modifiers (ClutterKeymapX11 *keymap_x11,
|
|
|
41c151 |
+ uint32_t level,
|
|
|
41c151 |
+ gboolean enable);
|
|
|
41c151 |
+
|
|
|
41c151 |
G_END_DECLS
|
|
|
41c151 |
|
|
|
41c151 |
#endif /* __CLUTTER_KEYMAP_X11_H__ */
|
|
|
41c151 |
diff --git a/clutter/clutter/x11/clutter-virtual-input-device-x11.c b/clutter/clutter/x11/clutter-virtual-input-device-x11.c
|
|
|
41c151 |
index 416c944b3..b86ded0d0 100644
|
|
|
41c151 |
--- a/clutter/clutter/x11/clutter-virtual-input-device-x11.c
|
|
|
41c151 |
+++ b/clutter/clutter/x11/clutter-virtual-input-device-x11.c
|
|
|
41c151 |
@@ -32,6 +32,8 @@
|
|
|
41c151 |
|
|
|
41c151 |
#include "clutter-virtual-input-device.h"
|
|
|
41c151 |
#include "x11/clutter-virtual-input-device-x11.h"
|
|
|
41c151 |
+#include "x11/clutter-backend-x11.h"
|
|
|
41c151 |
+#include "x11/clutter-keymap-x11.h"
|
|
|
41c151 |
|
|
|
41c151 |
struct _ClutterVirtualInputDeviceX11
|
|
|
41c151 |
{
|
|
|
41c151 |
@@ -135,11 +137,25 @@ clutter_virtual_input_device_x11_notify_keyval (ClutterVirtualInputDevice *virtu
|
|
|
41c151 |
uint32_t keyval,
|
|
|
41c151 |
ClutterKeyState key_state)
|
|
|
41c151 |
{
|
|
|
41c151 |
- KeyCode keycode;
|
|
|
41c151 |
+ ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (clutter_get_default_backend ());
|
|
|
41c151 |
+ ClutterKeymapX11 *keymap = backend_x11->keymap;
|
|
|
41c151 |
+ uint32_t keycode, level;
|
|
|
41c151 |
+
|
|
|
41c151 |
+ if (!clutter_keymap_x11_keycode_for_keyval (keymap, keyval, &keycode, &level))
|
|
|
41c151 |
+ {
|
|
|
41c151 |
+ g_warning ("No keycode found for keyval %x in current group", keyval);
|
|
|
41c151 |
+ return;
|
|
|
41c151 |
+ }
|
|
|
41c151 |
+
|
|
|
41c151 |
+ if (key_state == CLUTTER_KEY_STATE_PRESSED)
|
|
|
41c151 |
+ clutter_keymap_x11_latch_modifiers (keymap, level, TRUE);
|
|
|
41c151 |
|
|
|
41c151 |
- keycode = XKeysymToKeycode (clutter_x11_get_default_display (), keyval);
|
|
|
41c151 |
XTestFakeKeyEvent (clutter_x11_get_default_display (),
|
|
|
41c151 |
- keycode, key_state == CLUTTER_KEY_STATE_PRESSED, 0);
|
|
|
41c151 |
+ (KeyCode) keycode,
|
|
|
41c151 |
+ key_state == CLUTTER_KEY_STATE_PRESSED, 0);
|
|
|
41c151 |
+
|
|
|
41c151 |
+ if (key_state == CLUTTER_KEY_STATE_RELEASED)
|
|
|
41c151 |
+ clutter_keymap_x11_latch_modifiers (keymap, level, FALSE);
|
|
|
41c151 |
}
|
|
|
41c151 |
|
|
|
41c151 |
static void
|
|
|
41c151 |
--
|
|
|
41c151 |
2.19.0.rc0
|
|
|
41c151 |
|