[caribou: 4/22] libcaribou: Make any keysym work with weird keyboard remapping hack.



commit fde58831fdef2a0d89a884822e0b065e54a62996
Author: Eitan Isaacson <eitan monotonous org>
Date:   Fri Apr 22 17:32:36 2011 -0700

    libcaribou: Make any keysym work with weird keyboard remapping hack.

 libcaribou/caribou-virtual-keyboard.c |   99 +++++++++++++++++++++++++++++++--
 1 files changed, 93 insertions(+), 6 deletions(-)
---
diff --git a/libcaribou/caribou-virtual-keyboard.c b/libcaribou/caribou-virtual-keyboard.c
index 0f32bf2..5b6d28c 100644
--- a/libcaribou/caribou-virtual-keyboard.c
+++ b/libcaribou/caribou-virtual-keyboard.c
@@ -16,6 +16,8 @@
 struct _CaribouVirtualKeyboardPrivate {
   XkbDescPtr  xkbdesc;
   XklEngine  *xkl_engine;
+  KeyCode reserved_keycode;
+  KeySym reserved_keysym;
   gchar modifiers;
   gchar group;
 };
@@ -40,6 +42,77 @@ dispose (GObject *object)
   G_OBJECT_CLASS (caribou_virtual_keyboard_parent_class)->dispose (object);
 }
 
+/* A hack stolen from AT-SPI registry */
+static guint64
+_get_reserved_keycode (CaribouVirtualKeyboard *self)
+{
+  guint64 i;
+  XkbDescPtr xkbdesc = self->priv->xkbdesc;
+
+  for (i = xkbdesc->max_key_code; i >= xkbdesc->min_key_code; --i)
+    {
+	  if (xkbdesc->map->key_sym_map[i].kt_index[0] == XkbOneLevelIndex)
+        {
+	      if (XKeycodeToKeysym (XDISPLAY, i, 0) != 0)
+            {
+              /* don't use this one if there's a grab client! */
+              gdk_error_trap_push ();
+              XGrabKey (XDISPLAY, i, 0,
+                        gdk_x11_get_default_root_xwindow (),
+                        TRUE,
+                        GrabModeSync, GrabModeSync);
+              XSync (XDISPLAY, TRUE);
+              XUngrabKey (XDISPLAY, i, 0,
+                          gdk_x11_get_default_root_xwindow ());
+              if (!gdk_error_trap_pop ())
+                return i;
+            }
+        }
+    }
+
+  return XKeysymToKeycode (XDISPLAY, XK_numbersign);
+}
+
+static void _replace_keycode (CaribouVirtualKeyboard *self, KeySym keysym);
+
+static gboolean
+_reset_reserved (gpointer user_data)
+{
+  CaribouVirtualKeyboard *self = CARIBOU_VIRTUAL_KEYBOARD (user_data);
+
+  _replace_keycode (self, self->priv->reserved_keysym);
+
+  return FALSE;
+}
+
+static void
+_replace_keycode (CaribouVirtualKeyboard *self, KeySym keysym)
+{
+  CaribouVirtualKeyboardPrivate *priv = self->priv;
+  gint offset;
+  g_return_if_fail (priv->xkbdesc != NULL && priv->xkbdesc->map != NULL);
+
+  XFlush (XDISPLAY);
+  XSync (XDISPLAY, False);
+
+  offset = priv->xkbdesc->map->key_sym_map[priv->reserved_keycode].offset;
+
+  priv->xkbdesc->map->syms[offset] = keysym;
+
+  XkbSetMap (XDISPLAY, XkbAllMapComponentsMask, priv->xkbdesc);
+  /**
+   *  FIXME: the use of XkbChangeMap, and the reuse of the priv->xkb_desc structure,
+   * would be far preferable.
+   * HOWEVER it does not seem to work using XFree 4.3.
+   **/
+  /*	    XkbChangeMap (XDISPLAY, priv->xkb_desc, priv->changes); */
+  XFlush (XDISPLAY);
+  XSync (XDISPLAY, False);
+
+  if (keysym != priv->reserved_keysym)
+    g_timeout_add (500, _reset_reserved, self);
+}
+
 static GdkFilterReturn
 _filter_x_evt (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
 {
@@ -91,6 +164,9 @@ caribou_virtual_keyboard_init (CaribouVirtualKeyboard *self)
 
   gdk_window_add_filter (NULL, (GdkFilterFunc) _filter_x_evt, self);
 
+  self->priv->reserved_keycode = _get_reserved_keycode (self);
+  self->priv->reserved_keysym = XKeycodeToKeysym (XDISPLAY,
+                                                  self->priv->reserved_keycode, 0);
 }
 
 static void
@@ -152,20 +228,31 @@ caribou_virtual_keyboard_new ()
 }
 
 static KeyCode
-keycode_for_keyval (guint                   keyval,
+keycode_for_keyval (CaribouVirtualKeyboard *self,
+                    guint                   keyval,
                     guint                  *modmask)
 {
   GdkKeymap *km = gdk_keymap_get_default ();
   GdkKeymapKey *kmk;
   gint len;
-  KeyCode keycode;
+  KeyCode keycode = 38; // Initializing to something legal
 
   g_return_val_if_fail (modmask != NULL, 0);
 
   if (gdk_keymap_get_entries_for_keyval (km, keyval, &kmk, &len)) {
-    keycode = kmk[0].keycode;
-    *modmask = (kmk[0].level == 1) ? GDK_SHIFT_MASK : 0;
+    gint i;
+    GdkKeymapKey best_match = kmk[0];
+
+    for (i=0; i<len; i++)
+      if (kmk[i].group == self->priv->group)
+        best_match = kmk[i];
+
+    keycode = best_match.keycode;
+    *modmask = (best_match.level == 1) ? GDK_SHIFT_MASK : 0;
     g_free (kmk);
+  } else {
+    _replace_keycode (self, keyval);
+    keycode = self->priv->reserved_keycode;
   }
 
   return keycode;
@@ -211,7 +298,7 @@ caribou_virtual_keyboard_keyval_press (CaribouVirtualKeyboard *self,
                                        guint                   keyval)
 {
   guint mask;
-  KeyCode keycode = keycode_for_keyval (keyval, &mask);
+  KeyCode keycode = keycode_for_keyval (self, keyval, &mask);
 
   if (mask != 0)
     caribou_virtual_keyboard_mod_latch (self, mask);
@@ -231,7 +318,7 @@ caribou_virtual_keyboard_keyval_release (CaribouVirtualKeyboard *self,
                                          guint                   keyval)
 {
   guint mask;
-  KeyCode keycode = keycode_for_keyval (keyval, &mask);
+  KeyCode keycode = keycode_for_keyval (self, keyval, &mask);
 
   XTestFakeKeyEvent(XDISPLAY, keycode, FALSE, CurrentTime);
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]