diff options
author | Eitan Isaacson <eitan@monotonous.org> | 2011-04-26 15:28:40 -0700 |
---|---|---|
committer | Eitan Isaacson <eitan@monotonous.org> | 2011-05-02 10:18:49 -0700 |
commit | f72b4505ac6a46e03b106ea0b294e4fb2b67f535 (patch) | |
tree | 834bc5a3534b08112867f6ec50b03b47b139cc0b /libcaribou | |
parent | b319f06ecb7ba4d9bdb4e998cfdacf639edaa1aa (diff) | |
download | caribou-f72b4505ac6a46e03b106ea0b294e4fb2b67f535.tar.gz |
libcaribou: Ported XKB helper to Vala.
Diffstat (limited to 'libcaribou')
-rw-r--r-- | libcaribou/Makefile.am | 111 | ||||
-rw-r--r-- | libcaribou/caribou-enum-types.c.tmpl | 0 | ||||
-rw-r--r-- | libcaribou/caribou-enum-types.h.tmpl | 0 | ||||
-rw-r--r-- | libcaribou/caribou-marshal.list | 2 | ||||
-rw-r--r-- | libcaribou/caribou-virtual-keyboard.c | 392 | ||||
-rw-r--r-- | libcaribou/caribou-virtual-keyboard.h | 59 | ||||
-rw-r--r-- | libcaribou/caribou.h | 19 | ||||
-rw-r--r-- | libcaribou/external-libs.vapi | 234 | ||||
-rw-r--r-- | libcaribou/libxklavier.vapi | 182 | ||||
-rw-r--r-- | libcaribou/xadapter.vala | 213 |
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); + } + } +} |