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

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