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

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