Blame SOURCES/0001-clutter-x11-Implement-keycode-lookup-from-keysyms-on.patch

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