summaryrefslogtreecommitdiff
path: root/libcaribou
diff options
context:
space:
mode:
authorEitan Isaacson <eitan@monotonous.org>2011-04-26 15:28:40 -0700
committerEitan Isaacson <eitan@monotonous.org>2011-05-02 10:18:49 -0700
commitf72b4505ac6a46e03b106ea0b294e4fb2b67f535 (patch)
tree834bc5a3534b08112867f6ec50b03b47b139cc0b /libcaribou
parentb319f06ecb7ba4d9bdb4e998cfdacf639edaa1aa (diff)
downloadcaribou-f72b4505ac6a46e03b106ea0b294e4fb2b67f535.tar.gz
libcaribou: Ported XKB helper to Vala.
Diffstat (limited to 'libcaribou')
-rw-r--r--libcaribou/Makefile.am111
-rw-r--r--libcaribou/caribou-enum-types.c.tmpl0
-rw-r--r--libcaribou/caribou-enum-types.h.tmpl0
-rw-r--r--libcaribou/caribou-marshal.list2
-rw-r--r--libcaribou/caribou-virtual-keyboard.c392
-rw-r--r--libcaribou/caribou-virtual-keyboard.h59
-rw-r--r--libcaribou/caribou.h19
-rw-r--r--libcaribou/external-libs.vapi234
-rw-r--r--libcaribou/libxklavier.vapi182
-rw-r--r--libcaribou/xadapter.vala213
10 files changed, 668 insertions, 544 deletions
diff --git a/libcaribou/Makefile.am b/libcaribou/Makefile.am
index c7f7a0a..ca2b6b7 100644
--- a/libcaribou/Makefile.am
+++ b/libcaribou/Makefile.am
@@ -1,93 +1,60 @@
-INCLUDES = \
- -DG_LOG_DOMAIN=\"libcaribou\" \
- -I$(top_srcdir) \
- $(LIBCARIBOU_CFLAGS)
-
-
-MARSHAL_GENERATED = caribou-marshal.c caribou-marshal.h
-MKENUMS_GENERATED = caribou-enum-types.c caribou-enum-types.h
-
-caribou-marshal.h: caribou-marshal.list
- $(AM_V_GEN) ( $(GLIB_GENMARSHAL) --prefix=caribou_marshal $(srcdir)/caribou-marshal.list --header > caribou-marshal.tmp \
- && mv caribou-marshal.tmp caribou-marshal.h ) \
- || ( rm -f caribou-marshal.tmp && exit 1 )
-
-caribou-marshal.c: caribou-marshal.h
- $(AM_V_GEN) ( (echo '#include "caribou-marshal.h"'; $(GLIB_GENMARSHAL) --prefix=caribou_marshal $(srcdir)/caribou-marshal.list --body) > caribou-marshal.tmp \
- && mv caribou-marshal.tmp caribou-marshal.c ) \
- || ( rm -f caribou-marshal.tmp && exit 1 )
-
-caribou-enum-types.h: $(caribou_headers)
- $(AM_V_GEN) ( cd $(srcdir) && $(GLIB_MKENUMS) --template caribou-enum-types.h.tmpl \
- $(caribou_headers) ) > caribou-enum-types.h.tmp \
- && mv caribou-enum-types.h.tmp caribou-enum-types.h \
- || rm -f caribou-enum-type.h.tmp
+lib_LTLIBRARIES = libcaribou.la
-caribou-enum-types.c: $(libcaribouinclude_HEADERS)
- $(AM_V_GEN) ( cd $(srcdir) && $(GLIB_MKENUMS) --template caribou-enum-types.c.tmpl \
- $(caribou_headers) ) > caribou-enum-types.c.tmp \
- && mv caribou-enum-types.c.tmp caribou-enum-types.c \
- || rm -f caribou-enum-type.c.tmp
+INCLUDES = \
+ -DG_LOG_DOMAIN=\"caribou\" \
+ -I$(top_srcdir) \
+ $(LIBCARIBOU_CFLAGS)
-BUILT_SOURCES = $(MARSHAL_GENERATED) $(MKENUMS_GENERATED)
+libcaribou_la_VALAFLAGS = \
+ -H caribou.h --vapi caribou-1.0.vapi \
+ -h caribou-internals.h \
+ --vapidir=. \
+ --pkg x11 --pkg libxklavier --pkg external-libs --pkg gdk-3.0 --pkg gdk-x11-3.0 \
+ --internal-vapi caribou-internals-1.0.vapi \
+ --library caribou-1.0 --gir Caribou-1.0.gir \
+ $(VALAFLAGS)
-CLEANFILES = $(MARSHAL_GENERATED) $(MKENUMS_GENERATED)
+libcaribou_la_CPPFLAGS = \
+ $(INCLUDES)
libcaribouincludedir = $(includedir)/libcaribou
-caribou_headers = \
- caribou.h \
- caribou-virtual-keyboard.h
-
-libcaribouinclude_HEADERS = \
- $(caribou_headers) \
- caribou-enum-types.h
+caribouinclude_headers = \
+ caribou.h
-lib_LTLIBRARIES = libcaribou.la
+libcaribouinclude_HEADERS = \
+ $(caribou_headers)
libcaribou_la_LIBADD = \
$(LIBCARIBOU_LIBS)
-libcaribou_la_SOURCES = \
- $(BUILT_SOURCES) \
- caribou-virtual-keyboard.c
+libcaribou_la_SOURCES = \
+ xadapter.vala
+
+EXTRA_DIST = \
+ external-libs.vapi \
+ libxklavier.vapi
#
# Introspection support
#
-include $(INTROSPECTION_MAKEFILE)
-INTROSPECTION_GIRS =
-INTROSPECTION_SCANNER_ARGS = --add-include-path=.
-INTROSPECTION_COMPILER_ARGS = --includedir=.
if HAVE_INTROSPECTION
-
-gi_caribou_files = \
- $(filter-out caribou.h caribou-enum-types.% caribou-marshal.h,\
- $(caribou_headers) $(filter-out %.h, $(libcaribou_la_SOURCES)))
-# gi_built_caribou_files = caribou-enum-types.h
-
-Caribou-1.0.gir: libcaribou.la
-Caribou_1_0_gir_INCLUDES = Gdk-3.0
-Caribou_1_0_gir_CFLAGS = $(INCLUDES)
-Caribou_1_0_gir_LIBS = libcaribou.la
-Caribou_1_0_gir_EXPORT_PACKAGES = libcaribou
-Caribou_1_0_gir_SCANNERFLAGS = --c-include "libcaribou/caribou.h"
-Caribou_1_0_gir_FILES = \
- $(addprefix $(srcdir)/, $(gi_caribou_files)) \
- $(foreach f,$(gi_built_caribou_files), \
- $(if $(shell test -f $(addprefix $(srcdir)/,$(f)) && echo yes), \
- $(addprefix $(srcdir)/,$(f)), \
- $(f)))
-
-INTROSPECTION_GIRS += Caribou-1.0.gir
-
girdir = $(datadir)/gir-1.0
-gir_DATA = $(INTROSPECTION_GIRS)
+gir_DATA = Caribou-1.0.gir
+
+typelibdir = $(libdir)/girepository-1.0
+typelib_DATA = Caribou-1.0.typelib
-typelibsdir = $(libdir)/girepository-1.0
-typelibs_DATA = $(INTROSPECTION_GIRS:.gir=.typelib)
+Caribou-1.0.typelib: Caribou-1.0.gir
+ @INTROSPECTION_COMPILER@ --shared-library=libcaribou -o $@ $^
+endif
-CLEANFILES += $(gir_DATA) $(typelibs_DATA)
+Caribou-1.0.gir caribou-internals-1.0.vapi caribou-1.0.vapi: libcaribou.la
-endif \ No newline at end of file
+CLEANFILES = \
+ caribou-1.0.vapi \
+ caribou-internals-1.0.vapi \
+ Caribou-1.0.typelib \
+ Caribou-1.0.gir \
+ *.[ch] \ No newline at end of file
diff --git a/libcaribou/caribou-enum-types.c.tmpl b/libcaribou/caribou-enum-types.c.tmpl
deleted file mode 100644
index e69de29..0000000
--- a/libcaribou/caribou-enum-types.c.tmpl
+++ /dev/null
diff --git a/libcaribou/caribou-enum-types.h.tmpl b/libcaribou/caribou-enum-types.h.tmpl
deleted file mode 100644
index e69de29..0000000
--- a/libcaribou/caribou-enum-types.h.tmpl
+++ /dev/null
diff --git a/libcaribou/caribou-marshal.list b/libcaribou/caribou-marshal.list
deleted file mode 100644
index 6c138ac..0000000
--- a/libcaribou/caribou-marshal.list
+++ /dev/null
@@ -1,2 +0,0 @@
-NONE:UINT
-NONE:UINT,STRING,STRING
diff --git a/libcaribou/caribou-virtual-keyboard.c b/libcaribou/caribou-virtual-keyboard.c
deleted file mode 100644
index 565f1eb..0000000
--- a/libcaribou/caribou-virtual-keyboard.c
+++ /dev/null
@@ -1,392 +0,0 @@
-/*
- * Copyright (C) 2011, Eitan Isaacson <eitan@monotonous.org>
- */
-
-#include "caribou-virtual-keyboard.h"
-#include "caribou-marshal.h"
-#include <X11/Xlib.h>
-#include <X11/extensions/XTest.h>
-#include <gdk/gdk.h>
-#include <gdk/gdkx.h>
-#include <X11/XKBlib.h>
-#include <libxklavier/xklavier.h>
-
-#define XDISPLAY GDK_DISPLAY_XDISPLAY(gdk_display_get_default ())
-
-struct _CaribouVirtualKeyboardPrivate {
- XkbDescPtr xkbdesc;
- XklEngine *xkl_engine;
- KeyCode reserved_keycode;
- KeySym reserved_keysym;
- gchar modifiers;
- gchar group;
-};
-
-G_DEFINE_TYPE (CaribouVirtualKeyboard, caribou_virtual_keyboard, G_TYPE_OBJECT)
-
-enum {
- KB_MODIFIERS_CHANGED,
- KB_GROUP_CHANGED,
- LAST_SIGNAL
-};
-
-static guint signals[LAST_SIGNAL] = { 0 };
-
-static void
-dispose (GObject *object)
-{
- CaribouVirtualKeyboard *self = CARIBOU_VIRTUAL_KEYBOARD (object);
-
- XkbFreeKeyboard (self->priv->xkbdesc, XkbGBN_AllComponentsMask, True);
-
- 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)
-{
- CaribouVirtualKeyboard *self = CARIBOU_VIRTUAL_KEYBOARD (data);
- XkbEvent *xevent = gdk_xevent;
-
- if (xevent->any.xkb_type == XkbStateNotify) {
- XkbStateNotifyEvent *sevent = &xevent->state;
- if (sevent->changed & XkbGroupStateMask) {
- XklConfigRec *config_rec;
- self->priv->group = sevent->group;
- config_rec = xkl_config_rec_new ();
- xkl_config_rec_get_from_server (config_rec, self->priv->xkl_engine);
- g_signal_emit (self, signals[KB_GROUP_CHANGED], 0,
- sevent->group,
- config_rec->layouts[sevent->group],
- config_rec->variants[sevent->group]);
- g_object_unref (config_rec);
- } else if (sevent->changed & XkbModifierStateMask) {
- self->priv->modifiers = sevent->mods;
- g_signal_emit (self, signals[KB_MODIFIERS_CHANGED], 0, sevent->mods);
- }
- }
-
- return GDK_FILTER_CONTINUE;
-}
-
-static void
-caribou_virtual_keyboard_init (CaribouVirtualKeyboard *self)
-{
- XkbStateRec sr;
-
- self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self), CARIBOU_TYPE_VIRTUAL_KEYBOARD,
- CaribouVirtualKeyboardPrivate);
-
- self->priv->xkbdesc = XkbGetKeyboard(XDISPLAY, XkbGBN_AllComponentsMask,
- XkbUseCoreKbd);
-
- self->priv->xkl_engine = xkl_engine_get_instance (XDISPLAY);
-
- XkbGetState(XDISPLAY, XkbUseCoreKbd, &sr);
-
- self->priv->modifiers = sr.mods;
- self->priv->group = sr.group;
-
- XkbSelectEvents (XDISPLAY,
- XkbUseCoreKbd, XkbStateNotifyMask | XkbAccessXNotifyMask,
- XkbStateNotifyMask | XkbAccessXNotifyMask | XkbMapNotifyMask);
-
- 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
-caribou_virtual_keyboard_class_init (CaribouVirtualKeyboardClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- g_type_class_add_private (klass, sizeof (CaribouVirtualKeyboardPrivate));
-
- /* virtual method override */
- object_class->dispose = dispose;
-
- /* signals */
-
- /**
- * CaribouVirtualKeyboard::modifiers-changed:
- * @virtual_keyboard: the object that received the signal
- * @modifiers: the modifiers that are currently active
- *
- * Emitted when the keyboard modifiers change.
- */
- signals[KB_MODIFIERS_CHANGED] =
- g_signal_new ("modifiers-changed",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_FIRST,
- 0,
- NULL, NULL,
- caribou_marshal_NONE__UINT,
- G_TYPE_NONE, 1, G_TYPE_UINT);
-
- /**
- * CaribouVirtualKeyboard::group-changed:
- * @virtual_keyboard: the object that received the signal
- * @group: the currently active group
- *
- * Emitted when the keyboard group changes.
- */
- signals[KB_GROUP_CHANGED] =
- g_signal_new ("group-changed",
- G_OBJECT_CLASS_TYPE (object_class),
- G_SIGNAL_RUN_FIRST,
- 0,
- NULL, NULL,
- caribou_marshal_NONE__UINT_STRING_STRING,
- G_TYPE_NONE, 3, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING);
-}
-
-/**
- * caribou_virtual_keyboard_new:
- *
- * Create a new #CaribouVirtualKeyboard.
- *
- * Returns: A new #CaribouVirtualKeyboard.
- */
-CaribouVirtualKeyboard *
-caribou_virtual_keyboard_new ()
-{
- return g_object_new (CARIBOU_TYPE_VIRTUAL_KEYBOARD, NULL);
-}
-
-static KeyCode
-keycode_for_keyval (CaribouVirtualKeyboard *self,
- guint keyval,
- guint *modmask)
-{
- GdkKeymap *km = gdk_keymap_get_default ();
- GdkKeymapKey *kmk;
- gint len;
- KeyCode keycode = 0;
-
- g_return_val_if_fail (modmask != NULL, 0);
-
- if (gdk_keymap_get_entries_for_keyval (km, keyval, &kmk, &len)) {
- 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;
-}
-
-/**
- * caribou_virtual_keyboard_mod_latch:
- * @mask: the modifier mask
- *
- * Simulate a keyboard modifier key press
- */
-void
-caribou_virtual_keyboard_mod_latch (CaribouVirtualKeyboard *self,
- int mask)
-{
- XkbLatchModifiers(XDISPLAY, XkbUseCoreKbd, mask, mask);
-
- gdk_display_sync (gdk_display_get_default ());
-}
-
-/**
- * caribou_virtual_keyboard_mod_unlatch:
- * @mask: the modifier mask
- *
- * Simulate a keyboard modifier key release
- */
-void
-caribou_virtual_keyboard_mod_unlatch (CaribouVirtualKeyboard *self,
- int mask)
-{
- XkbLatchModifiers(XDISPLAY, XkbUseCoreKbd, mask, 0);
- gdk_display_sync (gdk_display_get_default ());
-}
-
-/**
- * caribou_virtual_keyboard_keyval_press:
- * @keyval: the keyval to simulate
- *
- * Simulate a keyboard key press with a given keyval.
- */
-void
-caribou_virtual_keyboard_keyval_press (CaribouVirtualKeyboard *self,
- guint keyval)
-{
- guint mask;
- KeyCode keycode = keycode_for_keyval (self, keyval, &mask);
-
- if (mask != 0)
- caribou_virtual_keyboard_mod_latch (self, mask);
-
- XTestFakeKeyEvent(XDISPLAY, keycode, TRUE, CurrentTime);
- gdk_display_sync (gdk_display_get_default ());
-}
-
-/**
- * caribou_virtual_keyboard_keyval_release:
- * @keyval: the keyval to simulate
- *
- * Simulate a keyboard key press with a given keyval.
- */
-void
-caribou_virtual_keyboard_keyval_release (CaribouVirtualKeyboard *self,
- guint keyval)
-{
- guint mask;
- KeyCode keycode = keycode_for_keyval (self, keyval, &mask);
-
- XTestFakeKeyEvent(XDISPLAY, keycode, FALSE, CurrentTime);
-
- if (mask != 0)
- caribou_virtual_keyboard_mod_unlatch (self, mask);
-
- gdk_display_sync (gdk_display_get_default ());
-}
-/**
- * caribou_virtual_keyboard_get_current_group:
- * @group_name: (out) (transfer full): Location to store name of current group,
- * or NULL.
- * @variant_name: (out) (transfer full): Location to store name of current group's
- * variant or NULL.
- *
- * Retrieve the keyboard's currently active group.
- *
- * Returns: Current group index.
- */
-guint
-caribou_virtual_keyboard_get_current_group (CaribouVirtualKeyboard *self,
- gchar **group_name,
- gchar **variant_name)
-{
- CaribouVirtualKeyboardPrivate *priv = self->priv;
-
- if (group_name != NULL || variant_name != NULL) {
- XklConfigRec *config_rec = xkl_config_rec_new ();
- xkl_config_rec_get_from_server (config_rec, priv->xkl_engine);
-
- if (group_name != NULL)
- *group_name = g_strdup (config_rec->layouts[priv->group]);
-
- if (variant_name != NULL)
- *variant_name = g_strdup (config_rec->variants[priv->group]);
-
- g_object_unref (config_rec);
- }
-
- return priv->group;
-}
-
-/**
- * caribou_virtual_keyboard_get_groups:
- * @group_names: (out) (transfer full) (array zero-terminated=1): Location to store
- * names of available groups or NULL.
- * @variant_names: (out) (transfer full) (array zero-terminated=1): Location to store
- * variants of available groups or NULL.
- *
- * Retrieve the keyboard's available groups.
- */
-void
-caribou_virtual_keyboard_get_groups (CaribouVirtualKeyboard *self,
- gchar ***group_names,
- gchar ***variant_names)
-{
- CaribouVirtualKeyboardPrivate *priv = self->priv;
-
- if (group_names != NULL || variant_names != NULL) {
- XklConfigRec *config_rec = xkl_config_rec_new ();
- xkl_config_rec_get_from_server (config_rec, priv->xkl_engine);
-
- if (group_names != NULL)
- *group_names = g_strdupv (config_rec->layouts);
-
- if (variant_names != NULL)
- *variant_names = g_strdupv (config_rec->variants);
-
- g_object_unref (config_rec);
- }
-}
diff --git a/libcaribou/caribou-virtual-keyboard.h b/libcaribou/caribou-virtual-keyboard.h
deleted file mode 100644
index 0fa3715..0000000
--- a/libcaribou/caribou-virtual-keyboard.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2011, Eitan Isaacson <eitan@monotonous.org>
- */
-
-#ifndef CARIBOU_VIRTUAL_KEYBOARD_H
-#define CARIBOU_VIRTUAL_KEYBOARD_H
-
-#include <glib-object.h>
-
-G_BEGIN_DECLS
-
-#define CARIBOU_TYPE_VIRTUAL_KEYBOARD (caribou_virtual_keyboard_get_type ())
-#define CARIBOU_VIRTUAL_KEYBOARD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CARIBOU_TYPE_VIRTUAL_KEYBOARD, CaribouVirtualKeyboard))
-#define CARIBOU_VIRTUAL_KEYBOARD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CARIBOU_TYPE_VIRTUAL_KEYBOARD, CaribouVirtualKeyboardClass))
-#define CARIBOU_IS_VIRTUAL_KEYBOARD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CARIBOU_TYPE_VIRTUAL_KEYBOARD))
-#define CARIBOU_IS_VIRTUAL_KEYBOARD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), CARIBOU_TYPE_VIRTUAL_KEYBOARD))
-#define CARIBOU_VIRTUAL_KEYBOARD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CARIBOU_TYPE_VIRTUAL_KEYBOARD, CaribouVirtualKeyboardClass))
-
-typedef struct _CaribouVirtualKeyboard CaribouVirtualKeyboard;
-typedef struct _CaribouVirtualKeyboardClass CaribouVirtualKeyboardClass;
-typedef struct _CaribouVirtualKeyboardPrivate CaribouVirtualKeyboardPrivate;
-
-struct _CaribouVirtualKeyboard {
- GObject parent;
-
- CaribouVirtualKeyboardPrivate *priv;
-};
-
-struct _CaribouVirtualKeyboardClass {
- GObjectClass parent_class;
-
-};
-
-GType caribou_virtual_keyboard_get_type (void);
-
-CaribouVirtualKeyboard *caribou_virtual_keyboard_new ();
-
-void caribou_virtual_keyboard_keyval_press (CaribouVirtualKeyboard *self,
- guint keyval);
-
-void caribou_virtual_keyboard_keyval_release (CaribouVirtualKeyboard *self,
- guint keyval);
-
-void caribou_virtual_keyboard_mod_latch (CaribouVirtualKeyboard *self,
- int mask);
-
-void caribou_virtual_keyboard_mod_unlatch (CaribouVirtualKeyboard *self,
- int mask);
-
-guint caribou_virtual_keyboard_get_current_group (CaribouVirtualKeyboard *self,
- gchar **group_name,
- gchar **variant_name);
-
-void caribou_virtual_keyboard_get_groups (CaribouVirtualKeyboard *self,
- gchar ***group_names,
- gchar ***variant_names);
-G_END_DECLS
-
-#endif /* CARIBOU_VIRTUAL_KEYBOARD_H */
diff --git a/libcaribou/caribou.h b/libcaribou/caribou.h
deleted file mode 100644
index 66b4c9f..0000000
--- a/libcaribou/caribou.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Copyright (C) 2011, Eitan Isaacson <eitan@monotonous.org>
- */
-
-#ifndef CARIBOU_H
-#define CARIBOU_H 1
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <libcaribou/caribou-virtual-keyboard.h>
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* CARIBOU_H */
diff --git a/libcaribou/external-libs.vapi b/libcaribou/external-libs.vapi
new file mode 100644
index 0000000..6a87d33
--- /dev/null
+++ b/libcaribou/external-libs.vapi
@@ -0,0 +1,234 @@
+using X;
+
+[CCode (cprefix = "", lower_case_cprefix = "",
+ cheader_filename = "X11/extensions/XTest.h")]
+namespace XTest {
+ [CCode (cname = "XTestFakeKeyEvent")]
+ public int fake_key_event (Display dpy, uchar keycode, bool key_press,
+ ulong delay);
+}
+
+[CCode (cprefix = "", lower_case_cprefix = "", cheader_filename = "X11/Xlib.h")]
+namespace X {
+ [CCode (cname = "XKeycodeToKeysym")]
+ public int keycode_to_keysym (Display dpy, uchar keycode, int index);
+
+}
+
+[CCode (cprefix = "", lower_case_cprefix = "", cheader_filename = "X11/XKBlib.h")]
+namespace Xkb {
+
+ [CCode (cname = "XkbGetKeyboard")]
+ public Desc get_keyboard (X.Display dpy, uint which, uint device_spec);
+
+ [CCode (cname = "XkbSetMap")]
+ public void set_map (X.Display dpy, uint which, Desc xkb);
+
+ [CCode (cname = "XkbFreeKeyboard")]
+ public void free_keyboard (Desc xkb, uint which, bool free_all);
+
+ [CCode (cname = "XkbGetState")]
+ public void get_state (X.Display dpy, uint device_spec, out State state);
+
+ [CCode (cname = "XkbSelectEvents")]
+ public void select_events (X.Display dpy, uint device_spec, ulong bits_to_change,
+ ulong values_for_bits);
+
+ [CCode (cname = "XkbLatchModifiers")]
+ public void latch_modifiers (X.Display dpy, uint device_spec, uint affect,
+ uint values);
+
+ [Compact]
+ [CCode (cname = "XkbAnyEvent", free_function = "")]
+ public struct AnyEvent {
+ int xkb_type;
+ }
+
+ [Compact]
+ [CCode (cname = "XkbStateNotifyEvent", free_function = "")]
+ public struct StateNotifyEvent {
+ uint changed;
+ int group;
+ uint mods;
+ }
+
+ [Compact]
+ [CCode (cname = "XkbEvent", free_function = "")]
+ public struct Event {
+ int type;
+ AnyEvent any;
+ StateNotifyEvent state;
+ }
+
+ [Compact]
+ [CCode (cname = "XkbStateRec", free_function = "")]
+ public struct State {
+ uchar group;
+ uchar locked_group;
+ ushort base_group;
+ ushort latched_group;
+ uchar mods;
+ uchar base_mods;
+ uchar latched_mods;
+ uchar locked_mods;
+ uchar compat_state;
+ uchar grab_mods;
+ uchar compat_grab_mods;
+ uchar lookup_mods;
+ uchar compat_lookup_mods;
+ ushort ptr_buttons;
+ }
+
+ [Compact]
+ [CCode (cname = "XkbDescRec", free_function = "")]
+ public class Desc {
+ public X.Display dpy;
+ public ushort flags;
+ public ushort device_spec;
+ public char min_key_code;
+ public char max_key_code;
+ public Controls ctrls;
+ public ServerMap server;
+ public ClientMap map;
+ public Indicator indicators;
+ public Names names;
+ public CompatMap compat;
+ public Geometry geom;
+ }
+
+ [Compact]
+ [CCode (cname = "XkbControlsRec", free_function = "")]
+ public class Controls {
+ }
+
+ [Compact]
+ [CCode (cname = "XkbServerMapRec", free_function = "")]
+ public class ServerMap {
+ }
+
+ [Compact]
+ [CCode (cname = "XkbKeyTypeRec", free_function = "")]
+ public struct KeyType {
+ }
+
+ [CCode (cname = "XkbSymMapRec", free_function = "")]
+ public struct SymMap {
+ uchar kt_index[4];
+ uchar group_info;
+ uchar width;
+ ushort offset;
+ }
+
+ [Compact]
+ [CCode (cname = "XkbClientMapRec", free_function = "")]
+ public class ClientMap {
+ public uchar size_types;
+ public uchar num_types;
+ public KeyType[] types;
+
+ public ushort size_syms;
+ public ushort num_syms;
+ public uint[] syms;
+ public SymMap[] key_sym_map;
+
+ public uchar[] modmap;
+ }
+
+ [Compact]
+ [CCode (cname = "XkbIndicatorRec", free_function = "")]
+ public class Indicator {
+ }
+
+ [Compact]
+ [CCode (cname = "XkbNamesRec", free_function = "")]
+ public class Names {
+ }
+
+ [Compact]
+ [CCode (cname = "XkbCompatMapRec", free_function = "")]
+ public class CompatMap {
+ }
+
+ [Compact]
+ [CCode (cname = "XkbGeometryRec", free_function = "")]
+ public class Geometry {
+ }
+
+ [CCode (cname = "XkbUseCoreKbd")]
+ public int UseCoreKbd;
+ [CCode (cname = "XkbUseCorePtr")]
+ public int UseCorePtr;
+ [CCode (cname = "XkbDfltXIClass")]
+ public int DfltXIClass;
+ [CCode (cname = "XkbDfltXIId")]
+ public int DfltXIId;
+ [CCode (cname = "XkbAllXIClasses")]
+ public int AllXIClasses;
+ [CCode (cname = "XkbAllXIIds")]
+ public int AllXIIds;
+ [CCode (cname = "XkbXINone")]
+ public int XINone;
+
+ [CCode (cname = "XkbGBN_TypesMask")]
+ public int GBN_TypesMask;
+ [CCode (cname = "XkbGBN_CompatMapMask")]
+ public int GBN_CompatMapMask;
+ [CCode (cname = "XkbGBN_ClientSymbolsMask")]
+ public int GBN_ClientSymbolsMask;
+ [CCode (cname = "XkbGBN_ServerSymbolsMask")]
+ public int GBN_ServerSymbolsMask;
+ [CCode (cname = "XkbGBN_SymbolsMask")]
+ public int GBN_SymbolsMask;
+ [CCode (cname = "XkbGBN_IndicatorMapMask")]
+ public int GBN_IndicatorMapMask;
+ [CCode (cname = "XkbGBN_KeyNamesMask")]
+ public int GBN_KeyNamesMask;
+ [CCode (cname = "XkbGBN_GeometryMask")]
+ public int GBN_GeometryMask;
+ [CCode (cname = "XkbGBN_OtherNamesMask")]
+ public int GBN_OtherNamesMask;
+ [CCode (cname = "XkbGBN_AllComponentsMask")]
+ public int GBN_AllComponentsMask;
+
+ [CCode (cname = "XkbOneLevelIndex")]
+ public int OneLevelIndex;
+
+ [CCode (cname = "XkbNewKeyboardNotifyMask")]
+ public int NewKeyboardNotifyMask;
+ [CCode (cname = "XkbMapNotifyMask")]
+ public int MapNotifyMask;
+ [CCode (cname = "XkbStateNotifyMask")]
+ public int StateNotifyMask;
+ [CCode (cname = "XkbControlsNotifyMask")]
+ public int ControlsNotifyMask;
+ [CCode (cname = "XkbIndicatorStateNotifyMask")]
+ public int IndicatorStateNotifyMask;
+ [CCode (cname = "XkbIndicatorMapNotifyMask")]
+ public int IndicatorMapNotifyMask;
+ [CCode (cname = "XkbNamesNotifyMask")]
+ public int NamesNotifyMask;
+ [CCode (cname = "XkbCompatMapNotifyMask")]
+ public int CompatMapNotifyMask;
+ [CCode (cname = "XkbBellNotifyMask")]
+ public int BellNotifyMask;
+ [CCode (cname = "XkbActionMessageMask")]
+ public int ActionMessageMask;
+ [CCode (cname = "XkbAccessXNotifyMask")]
+ public int AccessXNotifyMask;
+ [CCode (cname = "XkbExtensionDeviceNotifyMask")]
+ public int ExtensionDeviceNotifyMask;
+ [CCode (cname = "XkbAllEventsMask")]
+ public int AllEventsMask;
+
+ [CCode (cname = "XkbStateNotify")]
+ public int StateNotify;
+
+ [CCode (cname = "XkbGroupStateMask")]
+ public int GroupStateMask;
+
+ [CCode (cname = "XkbModifierStateMask")]
+ public int ModifierStateMask;
+
+ [CCode (cname = "XkbAllMapComponentsMask")]
+ public int AllMapComponentsMask;
+} \ No newline at end of file
diff --git a/libcaribou/libxklavier.vapi b/libcaribou/libxklavier.vapi
new file mode 100644
index 0000000..7d31572
--- /dev/null
+++ b/libcaribou/libxklavier.vapi
@@ -0,0 +1,182 @@
+/* libxklavier.vapi generated by vapigen, do not modify. */
+
+[CCode (cprefix = "Xkl", lower_case_cprefix = "xkl_")]
+namespace Xkl {
+ [CCode (cheader_filename = "libxklavier/xklavier.h")]
+ public class ConfigItem : GLib.Object {
+ [CCode (array_length = false)]
+ public weak char[] description;
+ [CCode (array_length = false)]
+ public weak char[] name;
+ [CCode (array_length = false)]
+ public weak char[] short_description;
+ [CCode (has_construct_function = false)]
+ public ConfigItem ();
+ }
+ [CCode (cheader_filename = "libxklavier/xklavier.h")]
+ public class ConfigRec : GLib.Object {
+ public string[] layouts;
+ public weak string model;
+ public string[] options;
+ public string[] variants;
+ [CCode (has_construct_function = false)]
+ public ConfigRec ();
+ public bool activate (Xkl.Engine engine);
+ public bool equals (Xkl.ConfigRec data2);
+ public bool get_from_backup (Xkl.Engine engine);
+ public bool get_from_root_window_property (X.Atom rules_atom_name, string rules_file_out, Xkl.Engine engine);
+ public bool get_from_server (Xkl.Engine engine);
+ public void reset ();
+ public bool set_to_root_window_property (X.Atom rules_atom_name, string rules_file, Xkl.Engine engine);
+ public static bool write_to_file (Xkl.Engine engine, string file_name, Xkl.ConfigRec data, bool binary);
+ }
+ [CCode (cheader_filename = "libxklavier/xklavier.h")]
+ public class ConfigRegistry : GLib.Object {
+ [CCode (has_construct_function = false)]
+ protected ConfigRegistry ();
+ public bool find_layout (Xkl.ConfigItem item);
+ public bool find_model (Xkl.ConfigItem item);
+ public bool find_option (string option_group_name, Xkl.ConfigItem item);
+ public bool find_option_group (Xkl.ConfigItem item);
+ public bool find_variant (string layout_name, Xkl.ConfigItem item);
+ public void foreach_country (Xkl.ConfigItemProcessFunc func, void* data);
+ public void foreach_country_variant (string country_code, Xkl.TwoConfigItemsProcessFunc func, void* data);
+ public void foreach_language (Xkl.ConfigItemProcessFunc func, void* data);
+ public void foreach_language_variant (string language_code, Xkl.TwoConfigItemsProcessFunc func, void* data);
+ public void foreach_layout (Xkl.ConfigItemProcessFunc func, void* data);
+ public void foreach_layout_variant (string layout_name, Xkl.ConfigItemProcessFunc func, void* data);
+ public void foreach_model (Xkl.ConfigItemProcessFunc func, void* data);
+ public void foreach_option (string option_group_name, Xkl.ConfigItemProcessFunc func, void* data);
+ public void foreach_option_group (Xkl.ConfigItemProcessFunc func, void* data);
+ public static unowned Xkl.ConfigRegistry get_instance (Xkl.Engine engine);
+ public bool load (bool if_extras_needed);
+ public void search_by_pattern (string pattern, Xkl.TwoConfigItemsProcessFunc func, void* data);
+ [NoAccessorMethod]
+ public Xkl.Engine engine { owned get; construct; }
+ }
+ [CCode (cheader_filename = "libxklavier/xklavier.h")]
+ public class Engine : GLib.Object {
+ [CCode (has_construct_function = false)]
+ protected Engine ();
+ public static void INT__LONG_LONG (GLib.Closure closure, GLib.Value return_value, uint n_param_values, GLib.Value param_values, void* invocation_hint, void* marshal_data);
+ public static void VOID__FLAGS_INT_BOOLEAN (GLib.Closure closure, GLib.Value return_value, uint n_param_values, GLib.Value param_values, void* invocation_hint, void* marshal_data);
+ public void allow_one_switch_to_secondary_group ();
+ public bool backup_names_prop ();
+ [NoWrapper]
+ public virtual void config_notify ();
+ public void delete_state (X.Window win);
+ public int filter_events (X.Event evt);
+ public unowned string get_backend_name ();
+ public unowned Xkl.State get_current_state ();
+ public X.Window get_current_window ();
+ public int get_current_window_group ();
+ public int get_default_group ();
+ public uint get_features ();
+ public unowned string get_groups_names ();
+ public bool get_indicators_handling ();
+ public unowned string get_indicators_names ();
+ public static unowned Xkl.Engine get_instance (X.Display display);
+ public uint get_max_num_groups ();
+ public int get_next_group ();
+ public uint get_num_groups ();
+ public int get_prev_group ();
+ public uint get_secondary_groups_mask ();
+ public bool get_state (X.Window win, Xkl.State state_out);
+ public unowned string get_window_title (X.Window win);
+ public bool grab_key (int keycode, uint modifiers);
+ public bool is_group_per_toplevel_window ();
+ public bool is_window_from_same_toplevel_window (X.Window win1, X.Window win2);
+ public bool is_window_transparent (X.Window win);
+ public void lock_group (int group);
+ public int pause_listen ();
+ public int resume_listen ();
+ public void save_state (X.Window win, Xkl.State state);
+ public void set_default_group (int group);
+ public void set_group_per_toplevel_window (bool is_global);
+ public void set_indicators_handling (bool whether_handle);
+ public void set_secondary_groups_mask (uint mask);
+ public void set_window_transparent (X.Window win, bool transparent);
+ public int start_listen (uint flags);
+ [NoWrapper]
+ public virtual void state_notify (Xkl.EngineStateChange change_type, int group, bool restore);
+ public int stop_listen (uint flags);
+ public bool ungrab_key (int keycode, uint modifiers);
+ [NoAccessorMethod]
+ public string backendName { owned get; }
+ public uint default_group { get; }
+ [NoAccessorMethod]
+ public void* display { get; construct; }
+ public Xkl.EngineFeatures features { get; }
+ public bool indicators_handling { get; }
+ public uint max_num_groups { get; }
+ public uint num_groups { get; }
+ public uint secondary_groups_mask { get; }
+ public virtual signal void X_config_changed ();
+ public virtual signal void X_new_device ();
+ public virtual signal void X_state_changed (int p0, int p1, bool p2);
+ public virtual signal int new_toplevel_window (long p0, long p1);
+ }
+ [Compact]
+ [CCode (cheader_filename = "libxklavier/xklavier.h")]
+ public class State {
+ public int32 group;
+ public uint32 indicators;
+ }
+ [CCode (cprefix = "XKLF_", cheader_filename = "libxklavier/xklavier.h")]
+ [Flags]
+ public enum EngineFeatures {
+ CAN_TOGGLE_INDICATORS,
+ CAN_OUTPUT_CONFIG_AS_ASCII,
+ CAN_OUTPUT_CONFIG_AS_BINARY,
+ MULTIPLE_LAYOUTS_SUPPORTED,
+ REQUIRES_MANUAL_LAYOUT_MANAGEMENT,
+ DEVICE_DISCOVERY
+ }
+ [CCode (cprefix = "XKLL_", cheader_filename = "libxklavier/xklavier.h")]
+ public enum EngineListenModes {
+ MANAGE_WINDOW_STATES,
+ TRACK_KEYBOARD_STATE,
+ MANAGE_LAYOUTS
+ }
+ [CCode (cprefix = "", cheader_filename = "libxklavier/xklavier.h")]
+ public enum EngineStateChange {
+ GROUP_CHANGED,
+ INDICATORS_CHANGED
+ }
+ [CCode (cheader_filename = "libxklavier/xklavier.h")]
+ public delegate void ConfigItemProcessFunc (Xkl.ConfigRegistry config, Xkl.ConfigItem item);
+ [CCode (cheader_filename = "libxklavier/xklavier.h", has_target = false)]
+ public delegate void LogAppender (char[] file, char[] function, int level, char[] format, void* args);
+ [CCode (cheader_filename = "libxklavier/xklavier.h")]
+ public delegate void TwoConfigItemsProcessFunc (Xkl.ConfigRegistry config, Xkl.ConfigItem item, Xkl.ConfigItem subitem);
+ [CCode (cheader_filename = "libxklavier/xklavier.h")]
+ public const int MAX_CI_DESC_LENGTH;
+ [CCode (cheader_filename = "libxklavier/xklavier.h")]
+ public const int MAX_CI_NAME_LENGTH;
+ [CCode (cheader_filename = "libxklavier/xklavier.h")]
+ public const int MAX_CI_SHORT_DESC_LENGTH;
+ [CCode (cheader_filename = "libxklavier/xklavier.h")]
+ public const string XCI_PROP_ALLOW_MULTIPLE_SELECTION;
+ [CCode (cheader_filename = "libxklavier/xklavier.h")]
+ public const string XCI_PROP_COUNTRY_LIST;
+ [CCode (cheader_filename = "libxklavier/xklavier.h")]
+ public const string XCI_PROP_EXTRA_ITEM;
+ [CCode (cheader_filename = "libxklavier/xklavier.h")]
+ public const string XCI_PROP_LANGUAGE_LIST;
+ [CCode (cheader_filename = "libxklavier/xklavier.h")]
+ public const string XCI_PROP_VENDOR;
+ [CCode (cheader_filename = "libxklavier/xklavier.h")]
+ public static void default_log_appender (char[] file, char[] function, int level, char[] format, void* args);
+ [CCode (cheader_filename = "libxklavier/xklavier.h")]
+ public static unowned string get_country_name (string code);
+ [CCode (cheader_filename = "libxklavier/xklavier.h")]
+ public static unowned string get_language_name (string code);
+ [CCode (cheader_filename = "libxklavier/xklavier.h")]
+ public static unowned string get_last_error ();
+ [CCode (cheader_filename = "libxklavier/xklavier.h")]
+ public static bool restore_names_prop (Xkl.Engine engine);
+ [CCode (cheader_filename = "libxklavier/xklavier.h")]
+ public static void set_debug_level (int level);
+ [CCode (cheader_filename = "libxklavier/xklavier.h")]
+ public static void set_log_appender (Xkl.LogAppender fun);
+}
diff --git a/libcaribou/xadapter.vala b/libcaribou/xadapter.vala
new file mode 100644
index 0000000..d240f08
--- /dev/null
+++ b/libcaribou/xadapter.vala
@@ -0,0 +1,213 @@
+using Xkl;
+using Gdk;
+using Xkb;
+using XTest;
+using X;
+
+namespace Caribou {
+ public class XAdapter : Object {
+
+ /* Signals */
+ public signal void modifiers_changed (uint modifiers);
+ public signal void group_changed (uint gid, string group, string variant);
+
+ /* Private properties */
+ private static XAdapter instance;
+ X.Display xdisplay;
+ Xkb.Desc xkbdesc;
+ Xkl.Engine xkl_engine;
+ uint reserved_keysym;
+ uchar reserved_keycode;
+ uchar modifiers;
+ uchar group;
+
+ construct {
+ Xkb.State state;
+
+ this.xdisplay = new X.Display ();
+ this.xkbdesc = Xkb.get_keyboard (this.xdisplay,
+ Xkb.GBN_AllComponentsMask,
+ Xkb.UseCoreKbd);
+ this.xkl_engine = Xkl.Engine.get_instance (this.xdisplay);
+
+ Xkb.get_state (this.xdisplay, Xkb.UseCoreKbd, out state);
+
+ this.group = state.group;
+ this.modifiers = state.mods;
+
+ this.reserved_keycode = 0;
+
+ Xkb.select_events (
+ this.xdisplay, Xkb.UseCoreKbd,
+ Xkb.StateNotifyMask | Xkb.AccessXNotifyMask,
+ Xkb.StateNotifyMask | Xkb.AccessXNotifyMask);
+
+ ((Gdk.Window) null).add_filter (x_event_filter); // Did I blow your mind?
+ }
+
+ ~XAdapter () {
+ Xkb.free_keyboard(this.xkbdesc, Xkb.GBN_AllComponentsMask, true);
+ }
+
+ public static XAdapter get_default() {
+ if (instance == null)
+ instance = new XAdapter ();
+ return instance;
+ }
+
+ private Gdk.FilterReturn x_event_filter (Gdk.XEvent xevent, Gdk.Event event) {
+ void* pointer = &xevent;
+ Xkb.Event *xev = (Xkb.Event *) pointer;
+
+ if (xev.any.xkb_type == Xkb.StateNotify) {
+ Xkb.StateNotifyEvent *sevent = &xev.state;
+ if ((sevent.changed & Xkb.GroupStateMask) != 0) {
+ Xkl.ConfigRec config_rec = new Xkl.ConfigRec ();
+ config_rec.get_from_server (this.xkl_engine);
+ group_changed (sevent.group, config_rec.layouts[sevent.group],
+ config_rec.variants[sevent.group]);
+ this.group = (uchar) sevent.group;
+ } else if ((sevent.changed & Xkb.ModifierStateMask) != 0) {
+ this.modifiers = (uchar) sevent.mods;
+ }
+ }
+
+ return Gdk.FilterReturn.CONTINUE;
+ }
+
+ private uchar get_reserved_keycode () {
+ uchar i;
+ unowned Xkb.Desc xkbdesc = this.xkbdesc;
+
+ for (i = xkbdesc.max_key_code; i >= xkbdesc.min_key_code; --i) {
+ if (xkbdesc.map.key_sym_map[i].kt_index[0] == Xkb.OneLevelIndex) {
+ if (X.keycode_to_keysym (this.xdisplay, i, 0) != 0) {
+ Gdk.error_trap_push ();
+ this.xdisplay.grab_key (i, 0,
+ Gdk.x11_get_default_root_xwindow (), true,
+ X.GrabMode.Sync, X.GrabMode.Sync);
+ this.xdisplay.flush ();
+ this.xdisplay.ungrab_key (
+ i, 0, Gdk.x11_get_default_root_xwindow ());
+ if (Gdk.error_trap_pop () == 0)
+ return i;
+ }
+ }
+ }
+
+ return (uchar) this.xdisplay.keysym_to_keycode (0x0023); // XK_numbersign
+ }
+
+ private void replace_keycode (uint keysym) {
+ if (this.reserved_keycode == 0) {
+ this.reserved_keycode = get_reserved_keycode ();
+ this.reserved_keysym = X.keycode_to_keysym (this.xdisplay,
+ this.reserved_keycode, 0);
+ }
+
+ this.xdisplay.flush ();
+ uint offset = this.xkbdesc.map.key_sym_map[this.reserved_keycode].offset;
+
+ this.xkbdesc.map.syms[offset] = keysym;
+
+ Xkb.set_map (this.xdisplay, Xkb.AllMapComponentsMask, this.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.
+ **/
+
+ this.xdisplay.flush ();
+
+ if (keysym != this.reserved_keysym)
+ GLib.Timeout.add (500, reset_reserved);
+ }
+
+ private bool reset_reserved () {
+ replace_keycode (this.reserved_keysym);
+ return false;
+ }
+
+ private uchar keycode_for_keyval (uint keyval, out uint modmask) {
+ Gdk.Keymap kmap= Gdk.Keymap.get_default ();
+ Gdk.KeymapKey[] kmk;
+ uchar keycode = 0;
+
+ if (kmap.get_entries_for_keyval (keyval, out kmk)) {
+ Gdk.KeymapKey best_match = kmk[0];
+ foreach (KeymapKey km in kmk)
+ if (km.group == this.group)
+ best_match = km;
+
+ keycode = (uchar) best_match.keycode;
+ modmask = (best_match.level == 1) ? Gdk.ModifierType.SHIFT_MASK : 0;
+ } else {
+ replace_keycode (keyval);
+ keycode = this.reserved_keycode;
+ }
+
+ return keycode;
+ }
+
+ public void keyval_press (uint keyval) {
+ uint mask;
+ uchar keycode = keycode_for_keyval (keyval, out mask);
+
+ if (mask != 0)
+ mod_latch (mask);
+
+ XTest.fake_key_event (this.xdisplay, keycode, true, X.CURRENT_TIME);
+ this.xdisplay.flush ();
+ }
+
+ public void keyval_release (uint keyval) {
+ uchar keycode = keycode_for_keyval (keyval, null);
+
+ XTest.fake_key_event (this.xdisplay, keycode, false, X.CURRENT_TIME);
+ this.xdisplay.flush ();
+ }
+
+ public void mod_latch (uint mask) {
+ Xkb.latch_modifiers (this.xdisplay, Xkb.UseCoreKbd, mask, mask);
+ this.xdisplay.flush ();
+ }
+
+ public void mod_unlatch (uint mask) {
+ Xkb.latch_modifiers (this.xdisplay, Xkb.UseCoreKbd, mask, 0);
+ this.xdisplay.flush ();
+ }
+
+ public uint get_current_group (out string group_name,
+ out string variant_name) {
+ Xkl.ConfigRec config_rec = new Xkl.ConfigRec ();
+ config_rec.get_from_server (this.xkl_engine);
+ group_name = config_rec.layouts[this.group];
+ variant_name = config_rec.variants[this.group];
+
+ return this.group;
+ }
+
+ public void get_groups (out string[] group_names,
+ out string[] variant_names) {
+ int i;
+ Xkl.ConfigRec config_rec = new Xkl.ConfigRec ();
+ config_rec.get_from_server (this.xkl_engine);
+
+ for (i=0; i<4; i++)
+ if (config_rec.layouts[i] == null)
+ break;
+
+ group_names = new string[i];
+ variant_names = new string[i];
+
+ for (; i>=0; i--) {
+ group_names[i] = config_rec.layouts[i];
+ variant_names[i] = config_rec.variants[i];
+ }
+ }
+
+ public void me () {
+ stdout.printf("%p\n", this.xkl_engine);
+ }
+ }
+}