aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AUTHORS0
-rw-r--r--ChangeLog0
-rw-r--r--Makefile.am9
-rw-r--r--NEWS0
-rw-r--r--README0
-rwxr-xr-xautogen.sh3
-rw-r--r--configure.ac130
-rw-r--r--doc/Doxyfile.in183
-rw-r--r--doc/Makefile.am14
-rw-r--r--fakekey/Makefile.am5
-rw-r--r--fakekey/fakekey.h131
-rw-r--r--libfakekey.pc.in10
-rw-r--r--src/Makefile.am10
-rw-r--r--src/libfakekey.c409
-rw-r--r--tests/Makefile.am5
-rw-r--r--tests/fakekey-test.c38
16 files changed, 947 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/AUTHORS
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ChangeLog
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..44de5fe
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,9 @@
+SUBDIRS=fakekey src tests doc
+
+EXTRA_DIST = fakekey.pc.in
+
+pkgconfigdir=$(libdir)/pkgconfig
+pkgconfig_DATA = libfakekey.pc
+
+
+
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/NEWS
diff --git a/README b/README
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/README
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..b1376df
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,3 @@
+#! /bin/sh
+autoreconf -v --install || exit 1
+./configure --enable-maintainer-mode "$@"
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..b07a732
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,130 @@
+>AC_PREREQ(2.53)
+AC_INIT([libfakekey], 0.1, [mallum@openedhand.com])
+AC_CONFIG_SRCDIR([src/libfakekey.c])
+
+AM_INIT_AUTOMAKE()
+AM_CONFIG_HEADER([config.h])
+AC_CONFIG_AUX_DIR(.)
+
+# Checks for programs.
+AC_PROG_CC
+AC_PROG_LIBTOOL
+AC_HEADER_STDC
+
+dnl ------ libtool versioning -----------------------------------------------
+
+LT_CURRENT=0
+LT_REVISION=1
+AC_SUBST(LT_CURRENT)
+AC_SUBST(LT_REVISION)
+LT_AGE=0
+
+LT_VERSION_INFO="$LT_CURRENT:$LT_REVISION:$LT_AGE"
+AC_SUBST(LT_VERSION_INFO)
+
+LT_CURRENT_MINUS_AGE=`expr $LT_CURRENT - $LT_AGE`
+AC_SUBST(LT_CURRENT_MINUS_AGE)
+
+dnl ------ Check for X Stuff ------------------------------------------------
+
+PKG_CHECK_MODULES(X11, x11, [have_libx11pc="yes"], [have_libx11pc="no"])
+
+if test $have_libx11pc = yes; then
+ PKG_CHECK_MODULES(XLIBS, x11 xtst)
+
+ FAKEKEY_LIBS="$XLIBS_LIBS"
+ FAKEKEY_CFLAGS="$XLIBS_CFLAGS"
+
+else
+
+AC_PATH_XTRA
+
+ALL_X_LIBS="$X_LIBS -lX11"
+
+AC_CHECK_LIB(Xtst, XTestQueryExtension, XTEST_LIBS=-lXtst have_xtest="yes" , have_xtest="no", $ALL_X_LIBS)
+
+if test "x$have_xtest" = "xno"; then
+ AC_MSG_ERROR([Cannot find XTest extension library])
+ exit 1
+fi
+
+FAKEKEY_CFLAGS="$XLIBS_CLAGS"
+FAKEKEY_LIBS="$ALL_X_LIBS $XTEST_LIBS"
+
+fi
+
+dnl ------ Debug -----------------------------------------------------------
+
+AC_ARG_ENABLE(debug,
+ [ --enable-debug enable debug ( verbose ) build],
+ enable_debug=$enableval, enable_debug=no )
+
+if test x$enable_debug != xno; then
+ FAKEKEY_CFLAGS="$FAKEKEY_CFLAGS -DDEBUG"
+fi
+
+dnl ------ Doxygen docs ----------------------------------------------------
+
+AC_ARG_ENABLE(doxygen-docs,
+ [ --enable-doxygen-docs build DOXYGEN API documentation (requires Doxygen)],
+ enable_doxygen_docs=$enableval,enable_doxygen_docs=no)
+
+if test x$enable_doxygen_docs = xyes ; then
+
+ AC_PATH_PROG(DOXYGEN, doxygen, no)
+
+ AC_MSG_CHECKING([whether to build Doxygen documentation])
+
+ if test x$DOXYGEN = xno ; then
+ have_doxygen=no
+ else
+ have_doxygen=yes
+ fi
+
+ if test x$have_doxygen = xno; then
+ AC_MSG_ERROR([Building Doxygen docs explicitly required, but Doxygen not found])
+ fi
+
+ AC_MSG_RESULT(yes)
+
+fi
+
+AM_CONDITIONAL(HAVE_DOXYGEN, test x$enable_doxygen_docs = xyes)
+
+
+dnl ------ GCC flags --------------------------------------------------------
+
+if test "x$GCC" = "xyes"; then
+ GCC_WARNINGS="-g -Wall -fno-strict-aliasing"
+ FAKEKEY_CFLAGS="$GCC_WARNINGS $FAKEKEY_CFLAGS"
+fi
+
+dnl -------------------------------------------------------------------------
+
+AC_SUBST(FAKEKEY_CFLAGS)
+AC_SUBST(FAKEKEY_LIBS)
+
+
+AC_OUTPUT([
+Makefile
+libfakekey.pc
+fakekey/Makefile
+src/Makefile
+doc/Doxyfile
+doc/Makefile
+tests/Makefile
+
+])
+
+dnl ==========================================================================
+echo "
+ LibFakeKey $VERSION
+ ======================
+
+ prefix: ${prefix}
+ source code location: ${srcdir}
+
+ Building with Debug: ${enable_debug}
+ Building with API Documentation: ${enable_doxygen_docs}
+
+"
diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in
new file mode 100644
index 0000000..3b0adec
--- /dev/null
+++ b/doc/Doxyfile.in
@@ -0,0 +1,183 @@
+# Doxyfile 0.1
+
+#---------------------------------------------------------------------------
+# General configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME = libfakekey
+PROJECT_NUMBER = @VERSION@
+OUTPUT_DIRECTORY = @top_srcdir@/doc
+OUTPUT_LANGUAGE = English
+EXTRACT_ALL = NO
+EXTRACT_PRIVATE = NO
+EXTRACT_STATIC = NO
+HIDE_UNDOC_MEMBERS = YES
+HIDE_UNDOC_CLASSES = YES
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ALWAYS_DETAILED_SEC = NO
+FULL_PATH_NAMES = NO
+STRIP_FROM_PATH =
+INTERNAL_DOCS = NO
+STRIP_CODE_COMMENTS = YES
+CASE_SENSE_NAMES = YES
+SHORT_NAMES = NO
+HIDE_SCOPE_NAMES = NO
+VERBATIM_HEADERS = YES
+SHOW_INCLUDE_FILES = YES
+JAVADOC_AUTOBRIEF = YES
+INHERIT_DOCS = YES
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = YES
+DISTRIBUTE_GROUP_DOC = NO
+TAB_SIZE = 8
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+ALIASES =
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+OPTIMIZE_OUTPUT_FOR_C = YES
+SHOW_USED_FILES = YES
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = YES
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_FORMAT =
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT = @top_srcdir@/fakekey
+FILE_PATTERNS = *.h
+RECURSIVE = YES
+#EXCLUDE = test
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+
+EXCLUDE_PATTERNS = Makefile.* ChangeLog CHANGES CHANGES.* README \
+ README.* *.png AUTHORS DESIGN DESIGN.* *.desktop \
+ DESKTOP* COMMENTS HOWTO magic NOTES TODO THANKS
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS =
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH =
+INPUT_FILTER =
+FILTER_SOURCE_FILES = NO
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER = YES
+INLINE_SOURCES = NO
+REFERENCED_BY_RELATION = YES
+REFERENCES_RELATION = YES
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX = NO
+COLS_IN_ALPHA_INDEX = 5
+IGNORE_PREFIX =
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML = YES
+HTML_OUTPUT =
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_ALIGN_MEMBERS = YES
+GENERATE_HTMLHELP = NO
+GENERATE_CHI = NO
+BINARY_TOC = NO
+TOC_EXPAND = NO
+DISABLE_INDEX = NO
+ENUM_VALUES_PER_LINE = 4
+GENERATE_TREEVIEW = NO
+TREEVIEW_WIDTH = 250
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX = NO
+LATEX_OUTPUT =
+COMPACT_LATEX = NO
+PAPER_TYPE = a4wide
+EXTRA_PACKAGES =
+LATEX_HEADER =
+PDF_HYPERLINKS = NO
+USE_PDFLATEX = NO
+LATEX_BATCHMODE = NO
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF = NO
+RTF_OUTPUT =
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN = YES
+MAN_OUTPUT = man
+MAN_EXTENSION = .mb
+MAN_LINKS = YES
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML = NO
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = YES
+EXPAND_ONLY_PREDEF = YES
+SEARCH_INCLUDES = YES
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED =
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+#---------------------------------------------------------------------------
+# Configuration::addtions related to external references
+#---------------------------------------------------------------------------
+TAGFILES =
+GENERATE_TAGFILE =
+ALLEXTERNALS = NO
+PERL_PATH =
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS = YES
+HAVE_DOT = NO
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+TEMPLATE_RELATIONS = YES
+HIDE_UNDOC_RELATIONS = YES
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+GRAPHICAL_HIERARCHY = YES
+DOT_PATH =
+DOTFILE_DIRS =
+MAX_DOT_GRAPH_WIDTH = 640
+MAX_DOT_GRAPH_HEIGHT = 1024
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
+#---------------------------------------------------------------------------
+# Configuration::addtions related to the search engine
+#---------------------------------------------------------------------------
+SEARCHENGINE = NO
+CGI_NAME =
+CGI_URL =
+DOC_URL =
+DOC_ABSPATH =
+BIN_ABSPATH =
+EXT_DOC_PATHS =
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644
index 0000000..8b643e4
--- /dev/null
+++ b/doc/Makefile.am
@@ -0,0 +1,14 @@
+EXTRA_DIST = Doxyfile.in
+
+all: stamp-doxygen
+
+stamp-doxygen:
+if HAVE_DOXYGEN
+ doxygen Doxyfile
+ touch stamp-doxygen
+endif
+
+clean: clean-local
+clean-local:
+ -rm -Rf html
+ -rm -f stamp-doxygen \ No newline at end of file
diff --git a/fakekey/Makefile.am b/fakekey/Makefile.am
new file mode 100644
index 0000000..e1a772a
--- /dev/null
+++ b/fakekey/Makefile.am
@@ -0,0 +1,5 @@
+fakekeyincludedir=$(includedir)/fakekey
+
+fakekey_headers=fakekey.h
+
+fakekeyinclude_HEADERS = $(fakekey_headers)
diff --git a/fakekey/fakekey.h b/fakekey/fakekey.h
new file mode 100644
index 0000000..da83223
--- /dev/null
+++ b/fakekey/fakekey.h
@@ -0,0 +1,131 @@
+#ifndef _HAVE_LIBFAKEKEY_H
+#define _HAVE_LIBFAKEKEY_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/Xlibint.h>
+#include <X11/Xutil.h>
+#include <X11/cursorfont.h>
+#include <X11/keysymdef.h>
+#include <X11/keysym.h>
+#include <X11/extensions/XTest.h>
+#include <X11/Xos.h>
+#include <X11/Xproto.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @defgroup FakeKey FakeKey -
+ * @brief yada yada yada
+ *
+ *
+ * Always remember to release held keys
+ * @{
+ */
+
+
+/**
+ * @typedef FakeKey
+ *
+ * Opaque structure used for all operations.
+ */
+typedef struct FakeKey FakeKey;
+
+/**
+ * @typedef FakeKeyModifier
+ *
+ * enumerated types for #mb_pixbuf_img_transform
+ */
+typedef enum
+{
+ FAKEKEYMOD_SHIFT = (1<<1),
+ FAKEKEYMOD_CONTROL = (1<<2),
+ FAKEKEYMOD_ALT = (1<<3),
+ FAKEKEYMOD_META = (1<<4)
+
+} FakeKeyModifier;
+
+/**
+ * Initiates FakeKey.
+ *
+ * @param xdpy X Display connection.
+ *
+ * @return new #FakeKey reference on success, NULL on fail.
+ */
+FakeKey*
+fakekey_init(Display *xdpy);
+
+
+/**
+ * Sends a Keypress to the server for the supplied UTF8 character.
+ *
+ * @param fk #FakeKey refernce from #fakekey_init
+ * @param utf8_char_in Pointer to a single UTF8 Character data.
+ * @param len_bytes Lenth in bytes of character, or -1 in ends with 0
+ * @param modifiers OR'd list of #FakeKeyModifier modifiers keys
+ * to press with the key.
+ *
+ *
+ * @return
+ */
+int
+fakekey_press(FakeKey *fk,
+ unsigned char *utf8_char_in,
+ int len_bytes,
+ int modifiers);
+
+/**
+ * Repreats a press of the currently held key ( from #fakekey_press )
+ *
+ * @param fk #FakeKey refernce from #fakekey_init
+ */
+void
+fakekey_repeat(FakeKey *fk);
+
+
+/**
+ * Releases the currently held key ( from #fakekey_press )
+ *
+ * @param fk #FakeKey refernce from #fakekey_init
+ */
+void
+fakekey_release(FakeKey *fk);
+
+/**
+ * Resyncs the internal list of keysyms with the server.
+ * Should be called if a MappingNotify event is recieved.
+ *
+ * @param fk #FakeKey refernce from #fakekey_init
+ *
+ * @return
+ */
+int
+fakekey_reload_keysyms(FakeKey *fk);
+
+/**
+ *
+ *
+ * @param fk #FakeKey refernce from #fakekey_init
+ * @param keycode X Keycode to send
+ * @param is_press Is this a press ( or release )
+ * @param modifiers
+ *
+ * @return
+ */
+int
+fakekey_send_keyevent(FakeKey *fk,
+ KeyCode keycode,
+ Bool is_press,
+ int modifiers);
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _HAVE_LIBFAKEKEY_H */
diff --git a/libfakekey.pc.in b/libfakekey.pc.in
new file mode 100644
index 0000000..ae778d1
--- /dev/null
+++ b/libfakekey.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libfakekey
+Description: X Virtual Keyboard Library
+Version: @VERSION@
+Libs: -L${libdir} @FAKEKEY_LIBS@
+Cflags: -I${includedir}
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..443befa
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,10 @@
+source_c = libfakekey.c
+
+AM_CFLAGS = @FAKEKEY_CFLAGS@
+
+libfakekey_la_SOURCES = $(source_c)
+
+lib_LTLIBRARIES = libfakekey.la
+
+libfakekey_la_LDFLAGS = -version-info @LT_VERSION_INFO@
+libfakekey_la_LIBADD = $(FAKEKEY_LIBS)
diff --git a/src/libfakekey.c b/src/libfakekey.c
new file mode 100644
index 0000000..307b4fb
--- /dev/null
+++ b/src/libfakekey.c
@@ -0,0 +1,409 @@
+/*
+ * libFakeKey
+ *
+ * A simple library for converting utf8 chars into 'fake' keypresses.
+ *
+ * Uses ideas from Fontconfig, libvirtkeys.c, keysym2ucs.c and dasher.
+ *
+ * Authored By Matthew Allum <amllum@openedhand.com>
+ *
+ * Copyright (C) 2004 OpenedHand
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#include <fakekey/fakekey.h>
+
+#if (DEBUG)
+#define FK_DBG(x, a...) \
+ fprintf(stderr, __FILE__ ":%d,%s() " x "\n", __LINE__, __func__, ##a)
+#else
+#define FK_DBG(x, a...) do {} while (0)
+#endif
+
+#define N_MODIFIER_INDEXES (Mod5MapIndex + 1)
+
+typedef unsigned int FkChar32;
+
+struct FakeKey
+{
+ Display *xdpy;
+ int min_keycode, max_keycode;
+ int n_keysyms_per_keycode;
+ KeySym *keysyms;
+ int held_keycode;
+ int held_state_flags;
+ KeyCode modifier_table[N_MODIFIER_INDEXES];
+ int shift_mod_index, alt_mod_index, meta_mod_index;
+};
+
+
+/* utf8_to_ucs4() Borrowed from fontconfig
+ *
+ * Converts the next Unicode char from src into dst and returns the
+ * number of bytes containing the char. src nust be at least len bytes
+ * long.
+ */
+static int
+utf8_to_ucs4 (const unsigned char *src_orig,
+ FkChar32 *dst,
+ int len)
+{
+ const unsigned char *src = src_orig;
+ unsigned char s;
+ int extra;
+ FkChar32 result;
+
+ if (len == 0)
+ return 0;
+
+ s = *src++;
+ len--;
+
+ if (!(s & 0x80))
+ {
+ result = s;
+ extra = 0;
+ }
+ else if (!(s & 0x40))
+ {
+ return -1;
+ }
+ else if (!(s & 0x20))
+ {
+ result = s & 0x1f;
+ extra = 1;
+ }
+ else if (!(s & 0x10))
+ {
+ result = s & 0xf;
+ extra = 2;
+ }
+ else if (!(s & 0x08))
+ {
+ result = s & 0x07;
+ extra = 3;
+ }
+ else if (!(s & 0x04))
+ {
+ result = s & 0x03;
+ extra = 4;
+ }
+ else if ( ! (s & 0x02))
+ {
+ result = s & 0x01;
+ extra = 5;
+ }
+ else
+ {
+ return -1;
+ }
+ if (extra > len)
+ return -1;
+
+ while (extra--)
+ {
+ result <<= 6;
+ s = *src++;
+
+ if ((s & 0xc0) != 0x80)
+ return -1;
+
+ result |= s & 0x3f;
+ }
+ *dst = result;
+ return src - src_orig;
+}
+
+FakeKey*
+fakekey_init(Display *xdpy)
+{
+ FakeKey *fk = NULL;
+ int event, error, major, minor;
+ XModifierKeymap *modifiers;
+ int mod_index;
+ int mod_key;
+ KeyCode *kp;
+
+ if (xdpy == NULL) return NULL;
+
+ if (!XTestQueryExtension(xdpy, &event, &error, &major, &minor))
+ {
+ return NULL;
+ }
+
+ fk = malloc(sizeof(FakeKey));
+ memset(fk,0,sizeof(FakeKey));
+
+ fk->xdpy = xdpy;
+
+ /* Find keycode limits */
+
+ XDisplayKeycodes(fk->xdpy, &fk->min_keycode, &fk->max_keycode);
+
+ /* Get the mapping */
+
+ /* TODO: Below needs to be kept in sync with anything else
+ * that may change the keyboard mapping.
+ *
+ * case MappingNotify:
+ * XRefreshKeyboardMapping(&ev.xmapping);
+ *
+ */
+
+ fk->keysyms = XGetKeyboardMapping(fk->xdpy,
+ fk->min_keycode,
+ fk->max_keycode - fk->min_keycode + 1,
+ &fk->n_keysyms_per_keycode);
+
+
+ modifiers = XGetModifierMapping(fk->xdpy);
+
+ kp = modifiers->modifiermap;
+
+ for (mod_index = 0; mod_index < 8; mod_index++)
+ {
+ fk->modifier_table[mod_index] = 0;
+
+ for (mod_key = 0; mod_key < modifiers->max_keypermod; mod_key++)
+ {
+ int keycode = kp[mod_index * modifiers->max_keypermod + mod_key];
+
+ if (keycode != 0)
+ {
+ fk->modifier_table[mod_index] = keycode;
+ break;
+ }
+ }
+ }
+
+ for (mod_index = Mod1MapIndex; mod_index <= Mod5MapIndex; mod_index++)
+ {
+ if (fk->modifier_table[mod_index])
+ {
+ KeySym ks = XKeycodeToKeysym(fk->xdpy,
+ fk->modifier_table[mod_index], 0);
+
+ /*
+ * Note: ControlMapIndex is already defined by xlib
+ * ShiftMapIndex
+ */
+
+ printf("checking ks\n");
+
+ switch (ks)
+ {
+ case XK_Meta_R:
+ case XK_Meta_L:
+ fk->meta_mod_index = mod_index;
+ break;
+
+ case XK_Alt_R:
+ case XK_Alt_L:
+ fk->alt_mod_index = mod_index;
+ break;
+
+ case XK_Shift_R:
+ case XK_Shift_L:
+ printf("got shift\n");
+ fk->shift_mod_index = mod_index;
+ break;
+ }
+ }
+ }
+
+ if (modifiers)
+ XFreeModifiermap(modifiers);
+
+ printf("index is %i %i\n",
+ fk->meta_mod_index, fk->modifier_table[ShiftMapIndex]);
+
+ return fk;
+}
+
+int
+fakekey_reload_keysyms(FakeKey *fk)
+{
+ if (fk->keysyms)
+ XFree(fk->keysyms);
+
+ fk->keysyms = XGetKeyboardMapping(fk->xdpy,
+ fk->min_keycode,
+ fk->max_keycode - fk->min_keycode + 1,
+ &fk->n_keysyms_per_keycode);
+ return 1;
+}
+
+int
+fakekey_send_keyevent(FakeKey *fk,
+ KeyCode keycode,
+ Bool is_press,
+ int flags)
+{
+ if (flags)
+ {
+ if (flags & FAKEKEYMOD_SHIFT)
+ XTestFakeKeyEvent(fk->xdpy, fk->modifier_table[ShiftMapIndex],
+ is_press, CurrentTime);
+
+ if (flags & FAKEKEYMOD_CONTROL)
+ XTestFakeKeyEvent(fk->xdpy, fk->modifier_table[ControlMapIndex],
+ is_press, CurrentTime);
+
+ if (flags & FAKEKEYMOD_ALT)
+ XTestFakeKeyEvent(fk->xdpy, fk->modifier_table[fk->alt_mod_index],
+ is_press, CurrentTime);
+
+ XSync(fk->xdpy, True);
+ }
+
+ XTestFakeKeyEvent(fk->xdpy, keycode, is_press, CurrentTime);
+
+ XSync(fk->xdpy, True);
+}
+
+int
+fakekey_press(FakeKey *fk,
+ unsigned char *utf8_char_in,
+ int len_bytes,
+ int flags)
+{
+ static int modifiedkey;
+ FkChar32 ucs4_out;
+ KeyCode code = 0;
+
+ if (fk->held_keycode) /* key is already held down */
+ return 0;
+
+ /* TODO: check for Return key here and other chars */
+
+ if (len_bytes < 0)
+ {
+ unsigned char *p = utf8_char_in;
+ while (*p != '\0') len_bytes++;
+ }
+
+ if (utf8_to_ucs4 (utf8_char_in, &ucs4_out, len_bytes) < 1)
+ {
+ printf("failed\n");
+ return 0;
+ }
+
+ /* first check for Latin-1 characters (1:1 mapping)
+ if ((keysym >= 0x0020 && keysym <= 0x007e) ||
+ (keysym >= 0x00a0 && keysym <= 0x00ff))
+ return keysym;
+ */
+
+ if (ucs4_out > 0x00ff) /* < 0xff assume Latin-1 1:1 mapping */
+ ucs4_out = ucs4_out | 0x01000000; /* This gives us the magic X keysym */
+
+ if ((code = XKeysymToKeycode(fk->xdpy, ucs4_out)) != 0)
+ {
+ printf("using fast code\n");
+
+ /* we already have a keycode for this keysym */
+ /* Does it need a shift key though ? */
+ if (XKeycodeToKeysym(fk->xdpy, code, 0) != ucs4_out)
+ {
+ printf("does not equal code\n");
+ /* TODO: Assumes 1st modifier is shifted ? */
+ if (XKeycodeToKeysym(fk->xdpy, code, 1) == ucs4_out)
+ flags |= FAKEKEYMOD_SHIFT; /* can get at it via shift */
+ else
+ code = 0; /* urg, some other modifier do it the heavy way */
+ }
+ }
+
+ if (!code)
+ {
+ int index;
+
+ printf("using slow remapping code\n");
+
+ /* Change one of the last 10 keysyms to our converted utf8,
+ * remapping the x keyboard on the fly.
+ *
+ * This make assumption the last 10 arn't already used.
+ * TODO: probably safer to check for this.
+ */
+
+ modifiedkey = (modifiedkey+1) % 10;
+
+ /* Point at the end of keysyms, modifier 0 */
+
+ index = (fk->max_keycode - fk->min_keycode - modifiedkey - 1) * fk->n_keysyms_per_keycode;
+
+ fk->keysyms[index] = ucs4_out;
+
+ XChangeKeyboardMapping(fk->xdpy,
+ fk->min_keycode,
+ fk->n_keysyms_per_keycode,
+ fk->keysyms,
+ (fk->max_keycode-fk->min_keycode));
+
+ XSync(fk->xdpy, True);
+
+ /* From dasher src;
+ * There's no way whatsoever that this could ever possibly
+ * be guaranteed to work (ever), but it does.
+ *
+ * code = fk->max_keycode - modifiedkey - 1;
+ *
+ * below instead is probably safer.
+ */
+
+ code = XKeysymToKeycode(fk->xdpy, ucs4_out);
+ }
+
+ if (code != 0)
+ {
+ fakekey_send_keyevent(fk, code, True, flags);
+
+ fk->held_state_flags = flags;
+ fk->held_keycode = code;
+
+ return 1;
+ }
+
+ fk->held_state_flags = 0;
+ fk->held_keycode = 0;
+
+ return 0;
+}
+
+void
+fakekey_repeat(FakeKey *fk)
+{
+ if (!fk->held_keycode)
+ return;
+
+ fakekey_send_keyevent(fk, fk->held_keycode, True, fk->held_state_flags);
+}
+
+void
+fakekey_release(FakeKey *fk)
+{
+ if (!fk->held_keycode)
+ return;
+
+ fakekey_send_keyevent(fk, fk->held_keycode, False, fk->held_state_flags);
+
+ fk->held_state_flags = 0;
+ fk->held_keycode = 0;
+}
+
diff --git a/tests/Makefile.am b/tests/Makefile.am
new file mode 100644
index 0000000..67ed38b
--- /dev/null
+++ b/tests/Makefile.am
@@ -0,0 +1,5 @@
+INCLUDES=-I${top_srcdir}/src -I${top_srcdir} $(FAKEKEY_CFLAGS)
+
+noinst_PROGRAMS=fakekey-test
+
+fakekey_test_LDADD=../src/libfakekey.la \ No newline at end of file
diff --git a/tests/fakekey-test.c b/tests/fakekey-test.c
new file mode 100644
index 0000000..9d807b6
--- /dev/null
+++ b/tests/fakekey-test.c
@@ -0,0 +1,38 @@
+#include "fakekey/fakekey.h"
+
+int
+main(int argc, char **argv)
+{
+ Display *dpy;
+ FakeKey *fk;
+ int i;
+ unsigned char str[] = "hello HELLO worldly world", *p = NULL;
+ unsigned char str2[] = "\303\270";
+
+ if ((dpy = XOpenDisplay(NULL)) == NULL)
+ {
+ fprintf(stderr,"Failed to open display\n");
+ exit(1);
+ }
+
+ fk = fakekey_init(dpy);
+
+ p = str;
+
+ /*
+ for (i=0; i<10; i++)
+ {
+ fakekey_press(fk, str2, 2, 0);
+ fakekey_release(fk);
+ }
+ */
+
+ while (*p != '\0')
+ {
+ fakekey_press(fk, p, 1, 0);
+ fakekey_release(fk);
+ p++;
+ }
+
+
+}