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

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