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