summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHuang Peng <shawn.p.huang@gmail.com>2008-05-12 15:18:48 +0800
committerHuang Peng <shawn.p.huang@gmail.com>2008-05-12 15:18:48 +0800
commitc25a24ae2e40a39db61fcd6f80d76469daa49a28 (patch)
tree8e9640375fcaf1778c264a5609bc94d499f240cc
downloadibus-c25a24ae2e40a39db61fcd6f80d76469daa49a28.tar.gz
ibus-c25a24ae2e40a39db61fcd6f80d76469daa49a28.tar.xz
ibus-c25a24ae2e40a39db61fcd6f80d76469daa49a28.zip
import ibus
-rw-r--r--AUTHORS1
-rw-r--r--COPYING340
-rw-r--r--ChangeLog0
-rw-r--r--Makefile.am42
-rw-r--r--NEWS0
-rw-r--r--README0
-rwxr-xr-xautogen.sh12
-rw-r--r--configure.ac116
-rw-r--r--doc/interfaces63
-rw-r--r--doc/specification19
-rw-r--r--gtk2/Makefile.am56
-rw-r--r--gtk2/gikim.c68
-rw-r--r--gtk2/gikimclient.c1049
-rw-r--r--gtk2/gikimclient.h98
-rw-r--r--gtk2/gikimcontext.c374
-rw-r--r--gtk2/gikimcontext.h51
-rw-r--r--ibus/Makefile6
-rw-r--r--ibus/__init__.py11
-rw-r--r--ibus/attribute.py58
-rwxr-xr-xibus/bus.py168
-rw-r--r--ibus/client.py107
-rw-r--r--ibus/clientmanager.py20
-rw-r--r--ibus/common.py20
-rw-r--r--ibus/connection.py32
-rwxr-xr-xibus/driver.py24
-rwxr-xr-xibus/eng_demo.py136
-rw-r--r--ibus/engine.py123
-rw-r--r--ibus/exception.py2
-rw-r--r--ibus/factorymanager.py76
-rwxr-xr-xibus/ibusdaemon.py56
-rw-r--r--ibus/interface.py124
-rw-r--r--ibus/keysyms.py1521
-rw-r--r--ibus/object.py14
-rwxr-xr-xibus/server.py62
-rw-r--r--m4/Makefile.am27
-rw-r--r--m4/as-version.m471
-rw-r--r--po/Makevars41
-rw-r--r--po/POTFILES.in0
38 files changed, 4988 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..a32ecc2
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+Huang Peng <shawn.p.huang@gmail.com>
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..623b625
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
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..acd6b64
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,42 @@
+# vim:set noet ts=4:
+#
+# ibus - The Input Bus
+#
+# Copyright (c) 2007-2008 Huang Peng <shawn.p.huang@gmail.com>
+#
+#
+# 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 program; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+# Boston, MA 02111-1307 USA
+#
+# $Id: $
+#
+SUBDIRS = \
+ gtk2 \
+ m4 \
+ po \
+ $(NULL)
+
+ACLOCAL_AMFLAGS = -I m4
+
+EXTRA_DIST = \
+ $(NULL)
+
+noinst_DIST = \
+ $(NULL)
+
+
+DISTCLEANFILES = \
+ po/stamp-it
+
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..72d295d
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+set -e
+set -x
+
+autopoint
+libtoolize --automake --copy
+aclocal -I m4
+autoheader
+gtkdocize --copy
+automake --add-missing --copy
+autoconf
+./configure $*
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..f8ccc91
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,116 @@
+# vim:set noet ts=4:
+#
+# ibus - The Input Bus
+#
+# Copyright (c) 2007-2008 Huang Peng <shawn.p.huang@gmail.com>
+#
+#
+# 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 program; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+# Boston, MA 02111-1307 USA
+#
+# $Id: $
+#
+AC_INIT([ibus],[0.0.1],[https://bugs.launchpad.net/ibus],[ibus])
+
+AM_INIT_AUTOMAKE([1.10])
+AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_MACRO_DIR([m4])
+AC_GNU_SOURCE
+
+# define PACKAGE_VERSION_* variables
+AS_VERSION
+AS_NANO
+AM_SANITY_CHECK
+AM_MAINTAINER_MODE
+AM_DISABLE_STATIC
+AC_PROG_CC
+AM_PROG_CC_C_O
+AC_PROG_CXX
+AC_ISC_POSIX
+AC_HEADER_STDC
+AM_PROG_LIBTOOL
+
+
+
+# check glib2
+AM_PATH_GLIB_2_0
+PKG_CHECK_MODULES(GLIB2, [
+ glib-2.0
+])
+PKG_CHECK_MODULES(GOBJECT2, [
+ gobject-2.0
+])
+PKG_CHECK_MODULES(PYGOBJECT2, [
+ pygobject-2.0
+])
+
+
+# check gtk & pygtk
+PKG_CHECK_MODULES(GTK2, [
+ gtk+-2.0
+])
+
+PKG_CHECK_MODULES(PYGTK2, [
+ pygtk-2.0
+])
+
+# check dbus-glib
+PKG_CHECK_MODULES(DBUS, [
+ dbus-glib-1
+])
+
+
+AC_PATH_PROG(PYGTK_CODEGEN, pygtk-codegen-2.0, no)
+
+# check python
+AM_PATH_PYTHON([2.5])
+PYTHON_CONFIG=`type -p python$PYTHON_VERSION-config`
+if test "$PYTHON_CONFIG" != ""; then
+ PYTHON_CFLAGS=`$PYTHON_CONFIG --includes`
+ PYTHON_LIBS=`$PYTHON_CONFIG --libs`
+else
+ PYTHON_CFLAGS=`$PYTHON $srcdir/python-config.py --includes`
+ PYTHON_LIBS=`$PYTHON $srcdir/python-config.py --libs`
+fi
+AC_SUBST(PYTHON_CFLAGS)
+AC_SUBST(PYTHON_LIBS)
+
+# Checks for gtk-doc
+GTK_DOC_CHECK([1.6])
+
+AC_CHECK_PROG(DB2HTML, db2html, true, false)
+AM_CONDITIONAL(HAVE_DOCBOOK, $DB2HTML)
+
+
+# define GETTEXT_* variables
+GETTEXT_PACKAGE=ibus
+AC_SUBST(GETTEXT_PACKAGE)
+AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE", [Package name for gettext])
+
+AM_GNU_GETTEXT([external])
+AM_GNU_GETTEXT_VERSION(0.16.1)
+
+# Args for make distcheck
+DISTCHECK_CONFIGURE_FLAGS="--enable-gtk-doc"
+AC_SUBST(DISTCHECK_CONFIGURE_FLAGS)
+
+# OUTPUT files
+AC_CONFIG_FILES([ po/Makefile.in
+Makefile
+gtk2/Makefile
+m4/Makefile
+])
+
+AC_OUTPUT
diff --git a/doc/interfaces b/doc/interfaces
new file mode 100644
index 0000000..444e775
--- /dev/null
+++ b/doc/interfaces
@@ -0,0 +1,63 @@
+
+Type Name: ObjectID
+Desc: It is a String to identify a dbus object. Like: "object_path@bus_name"
+
+Bus Name: org.freedesktop.IM
+Name: IDirectory
+Path: /org/freedesktop/IM/Directory
+ It is responeible for maintain all object in the virtual objects tree.
+Methods:
+ void register_object (String object_path)
+ void register_objects (String *object_path_array)
+ void deregister_object (String object_path)
+ void deregister_object (String object_path)
+ void deregisters_object (String *object_path_array)
+ ObjectID *list_objects (String dirname)
+ Return Object_ids in a folder specified by argument dirname
+
+Signals:
+ directory_changed (String dirname)
+
+Name: IManager
+Path: /org/freedesktop/IM/Manager
+ Manager is responsible for managering all engines & im clients.
+Methods:
+ void register_client (String client_name)
+ register the client (the caller) to the Manager, the client_name is a readable name of client. It do not specify it, manager will use caller's bus_name.
+ void deregister_client ()
+ deregister the client (the caller) in the Manager. The manager should release resources hold by the client.
+ void set_client_name ()
+ Set a associated name for the client (the caller). Like: gedit-pid
+ String *get_hotkeys ()
+ Retrun a String array. Each string in the array is a hotkey. When user press the hotkeys, client should send the hotket's index in this array to the manager.
+ void focus_in ()
+ Tell the manager the client (the caller) request focus in. The current focused client will be focus out.
+ void focus_out ()
+ Tell the manager the client (the caller) request focus out.
+ String get_focused_client ()
+
+Signals:
+ focus_changed (String client_name, String engine_path)
+
+Name: IFactory
+Name: IEngineFactory
+Name: IEngine
+Methods:
+ boolean filter_keypress (unsigned int state, unsigned int keyval, boolean is_press)
+ void focus_in ()
+ void focus_out ()
+ void reset ()
+??void set_set_client_window
+ (int window_id)
+ void set_cursor_position (int x, int y)
+ void set_use_preedit (boolean use_preedit)
+ void set_surrounding (String text, int cursor_index)
+Signal:
+ commit (String commit_string)
+ preedit_start ()
+ preedit_end ()
+ preedit_changed (String preedit_string, Attribute *attrs)
+ retrieve_surrounding ()
+ delete_surrounding (int offset, int n_chars)
+
+
diff --git a/doc/specification b/doc/specification
new file mode 100644
index 0000000..f83d0c0
--- /dev/null
+++ b/doc/specification
@@ -0,0 +1,19 @@
+IM Specification
+
+ Huang Peng <phuang@redhat.com>
+
+1. Introducation
+ About
+ Architecture
+
+
+Chapter 1 Introducation
+
+About
+
+This document contain the specification of IM which is a software that managers all input services in the system.
+
+Architecture
+
+IM manager provides a directory service. All IM services will register themself in this directory service. All clients can enumerate serivces in a specified directoy folder and get a nodification when a specified folder's contain be changed.
+
diff --git a/gtk2/Makefile.am b/gtk2/Makefile.am
new file mode 100644
index 0000000..8385284
--- /dev/null
+++ b/gtk2/Makefile.am
@@ -0,0 +1,56 @@
+# vim:set noet ts=4:
+#
+# gik - The G Input Toolkit
+#
+# Copyright (c) 2007-2008 Huang Peng <shawn.p.huang@gmail.com>
+#
+#
+# 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 program; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+# Boston, MA 02111-1307 USA
+#
+# $Id: $
+#
+INCLUDES = \
+ -I$(top_srcdir)/src
+
+im_gik_sources = \
+ gikim.c \
+ gikimclient.c \
+ gikimcontext.c \
+ $(NULL)
+
+im_gik_private_headers = \
+ gikimcontext.h \
+ gikimclient.h \
+ $(NULL)
+
+immoduledir = $(libdir)/gtk-2.0/immodules
+immodule_LTLIBRARIES = im-gik.la
+
+im_gik_la_SOURCES = $(im_gik_sources) $(im_gik_private_headers)
+im_gik_la_CFLAGS = \
+ @GTK2_CFLAGS@ \
+ @DBUS_CFLAGS@ \
+ -DG_LOG_DOMAIN=\"GIK\" \
+ $(NULL)
+
+im_gik_la_LDFLAGS = \
+ @GTK2_LIBS@ \
+ @DBUS_LIBS@ \
+ -avoid-version \
+ -module \
+ $(NULL)
+
+EXTRA_DIST =
diff --git a/gtk2/gikim.c b/gtk2/gikim.c
new file mode 100644
index 0000000..e394a78
--- /dev/null
+++ b/gtk2/gikim.c
@@ -0,0 +1,68 @@
+/* vim:set et ts=4: */
+/* GIK - The G Input Toolkit
+ * Copyright (C) 2008-2009 Huang Peng
+ *
+ * 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 <gtk/gtk.h>
+#include <gtk/gtkimmodule.h>
+#include <string.h>
+#include <stdio.h>
+#include "gikimclient.h"
+#include "gikimcontext.h"
+
+#define GIK_LOCALDIR ""
+
+static const GtkIMContextInfo gik_im_info = {
+ "gik",
+ "The G Input Toolkit",
+ "gik",
+ GIK_LOCALDIR,
+ ""
+};
+
+static const GtkIMContextInfo * info_list[] = {
+ &gik_im_info
+};
+
+void
+im_module_init (GTypeModule *type_module)
+{
+ gik_im_client_register_type(type_module);
+ gik_im_context_register_type(type_module);
+}
+
+void
+im_module_exit (void)
+{
+}
+
+GtkIMContext *
+im_module_create (const gchar *context_id)
+{
+ if (strcmp (context_id, "gik") == 0)
+ return gik_im_context_new ();
+ return NULL;
+}
+
+void
+im_module_list (const GtkIMContextInfo ***contexts,
+ int *n_contexts)
+{
+ *contexts = info_list;
+ *n_contexts = G_N_ELEMENTS (info_list);
+}
+
diff --git a/gtk2/gikimclient.c b/gtk2/gikimclient.c
new file mode 100644
index 0000000..f022242
--- /dev/null
+++ b/gtk2/gikimclient.c
@@ -0,0 +1,1049 @@
+/* vim:set et ts=4: */
+/* GIK - The G Input Toolkit
+ * Copyright (C) 2008-2009 Huang Peng
+ *
+ * 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 <gdk/gdkkeysyms.h>
+#include <gdk/gdkx.h>
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/un.h>
+#include <string.h>
+#include <stdarg.h>
+#include "gikimclient.h"
+
+#define IBUS_NAME "org.freedesktop.IBus"
+#define IBUS_IFACE "org.freedesktop.IBus"
+#define IBUS_PATH "/org/freedesktop/IBus"
+#define IBUS_ADDR "unix:abstract=/tmp/ibus"
+//#define IBUS_ADDR "tcp:host=localhost,port=7799"
+
+/* GikIMClientPriv */
+struct _GikIMClientPrivate {
+#if USE_DBUS_SESSION_BUS
+ DBusConnection *dbus;
+#endif
+ DBusConnection *ibus;
+ gboolean enable;
+
+ GtkIMContext *context;
+
+ /* preedit status */
+ gchar *preedit_string;
+ PangoAttrList *preedit_attrs;
+ gint preedit_cursor;
+};
+
+/* functions prototype */
+static void gik_im_client_class_init (GikIMClientClass *klass);
+static void gik_im_client_init (GikIMClient *client);
+static void gik_im_client_finalize (GObject *obj);
+
+static void gik_im_client_commit_string(GikIMClient *client,
+ const gchar *string);
+static void gik_im_client_preedit_changed
+ (GikIMClient *client,
+ const gchar *string,
+ PangoAttrList *attrs,
+ gint cursor_pos);
+
+static void gik_im_client_sync_hotkeys (GikIMClient *client);
+static gboolean _ibus_call_with_reply_and_block
+ (DBusConnection *connection,
+ const gchar *method,
+ int first_arg_type,
+ ...);
+static gboolean _ibus_call_with_reply (DBusConnection *connection,
+ const gchar *method,
+ DBusPendingCallNotifyFunction
+ function,
+ void *data,
+ DBusFreeFunction free_function,
+ int first_arg_type,
+ ...);
+static gboolean _dbus_call_with_reply_and_block
+ (DBusConnection *connection,
+ const gchar *dest,
+ const gchar *path,
+ const gchar *iface,
+ const char *method,
+ gint first_arg_type,
+ ...);
+
+/* callback functions */
+static DBusHandlerResult
+ _gik_im_client_message_filter_cb
+ (DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data);
+
+static void _dbus_name_owner_changed_cb (DBusGProxy *proxy,
+ const gchar *name,
+ const gchar *old_name,
+ const gchar *new_name,
+ GikIMClient *client);
+
+static GType gik_type_im_client = 0;
+static GtkObjectClass *parent_class = NULL;
+static GikIMClient *_client = NULL;
+static gboolean has_focus = FALSE;
+
+
+GType
+gik_im_client_get_type (void)
+{
+ g_assert (gik_type_im_client != 0);
+ return gik_type_im_client;
+}
+
+void
+gik_im_client_register_type (GTypeModule *type_module)
+{
+ static const GTypeInfo gik_im_client_info = {
+ sizeof (GikIMClientClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gik_im_client_class_init,
+ NULL, /* class finialize */
+ NULL, /* class data */
+ sizeof (GikIMClient),
+ 0,
+ (GInstanceInitFunc) gik_im_client_init,
+ };
+
+ if (! gik_type_im_client ) {
+ gik_type_im_client =
+ g_type_module_register_type (type_module,
+ GTK_TYPE_OBJECT,
+ "GikIMClient",
+ &gik_im_client_info,
+ (GTypeFlags)0);
+ }
+}
+
+
+GikIMClient *
+gik_im_client_get_client (void)
+{
+ if (_client == NULL) {
+ _client = GIK_IM_CLIENT(g_object_new (GIK_TYPE_IM_CLIENT, NULL));
+ g_object_ref_sink (_client);
+ }
+ else {
+ g_object_ref (_client);
+ }
+
+ return _client;
+}
+
+
+static void
+gik_im_client_class_init (GikIMClientClass *klass)
+{
+ GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass);
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ parent_class = (GtkObjectClass *) g_type_class_peek_parent (klass);
+
+ g_type_class_add_private (klass, sizeof (GikIMClientPrivate));
+
+ gobject_class->finalize = &gik_im_client_finalize;
+}
+
+#if 0
+static void
+_gik_im_client_reinit_imm (GikIMClient *client)
+{
+ GError *error;
+ GikIMClientPrivate *priv = client->priv;
+
+ if (priv->imm != NULL) {
+ g_object_unref (priv->imm);
+ }
+
+ /* get gik proxy */
+ error = NULL;
+ priv->imm = dbus_g_proxy_new_for_name_owner (priv->ibus,
+ GIK_DBUS_SERVICE,
+ GIK_DBUS_PATH,
+ GIK_DBUS_INTERFACE,
+ &error);
+
+ if (priv->imm == NULL) {
+ g_warning (error->message);
+ g_error_free (error);
+ return;
+ }
+
+ error = NULL;
+ if (!dbus_g_proxy_call (priv->imm, "register_client", &error,
+ G_TYPE_INVALID, G_TYPE_INVALID)) {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ g_object_unref (priv->imm);
+ priv->imm = NULL;
+ return;
+ }
+
+ gik_im_client_sync_hotkeys (client);
+ g_debug ("new imm %s", dbus_g_proxy_get_bus_name (priv->imm));
+}
+#endif
+
+static void
+_gik_im_client_ibus_open (GikIMClient *client)
+{
+ gchar *ibus_addr;
+ DBusError error;
+
+ GikIMClientPrivate *priv;
+ priv = G_TYPE_INSTANCE_GET_PRIVATE (client, GIK_TYPE_IM_CLIENT, GikIMClientPrivate);
+
+#if USE_DBUS_SESSION_BUS
+ dbus_connection_setup_with_g_main (priv->dbus, NULL);
+ if (!_dbus_call_with_reply_and_block (priv->dbus,
+ IBUS_NAME, IBUS_PATH, IBUS_IFACE,
+ "GetIBusAddress",
+ DBUS_TYPE_INVALID,
+ DBUS_TYPE_STRING, &ibus_addr,
+ DBUS_TYPE_INVALID
+ )) {
+ g_warning ("Can not get ibus address");
+ return;
+ }
+#endif
+
+ /*
+ * Init ibus and proxy object
+ */
+ dbus_error_init (&error);
+ priv->ibus = dbus_connection_open_private (IBUS_ADDR, &error);
+ if (priv->ibus == NULL) {
+ g_warning ("Error: %s", error.message);
+ dbus_error_free (&error);
+ return;
+ }
+
+ if (!dbus_connection_add_filter (priv->ibus,
+ _gik_im_client_message_filter_cb,
+ client, NULL)) {
+ g_warning ("Out of memory");
+ return;
+ }
+ dbus_connection_setup_with_g_main (priv->ibus, NULL);
+ const gchar *app_name = g_get_application_name ();
+ _ibus_call_with_reply_and_block (priv->ibus, "RegisterClient",
+ DBUS_TYPE_STRING, &app_name,
+ DBUS_TYPE_INVALID,
+ DBUS_TYPE_INVALID);
+
+}
+
+static void
+_gik_im_client_ibus_close (GikIMClient *client)
+{
+ DBusError error;
+
+ GikIMClientPrivate *priv;
+ priv = G_TYPE_INSTANCE_GET_PRIVATE (client, GIK_TYPE_IM_CLIENT, GikIMClientPrivate);
+
+ if (priv->ibus) {
+ dbus_connection_close (priv->ibus);
+ dbus_connection_unref (priv->ibus);
+ priv->ibus = None;
+ }
+}
+
+static void
+gik_im_client_init (GikIMClient *obj)
+{
+ DEBUG_FUNCTION_IN;
+
+ DBusError error;
+ GikIMClient *client = GIK_IM_CLIENT (obj);
+ GikIMClientPrivate *priv;
+
+ priv = G_TYPE_INSTANCE_GET_PRIVATE (client, GIK_TYPE_IM_CLIENT, GikIMClientPrivate);
+ client->priv = priv;
+
+ priv->context = NULL;
+
+ priv->preedit_string = NULL;
+ priv->preedit_attrs = NULL;
+ priv->preedit_cursor = 0;
+ priv->enable = FALSE;
+
+#if USE_DBUS_SESSION_BUS
+ /*
+ * Init dbus
+ */
+ dbus_error_init (&error);
+ priv->dbus = dbus_bus_get (DBUS_BUS_SESSION, &error);
+ if (priv->dbus == NULL) {
+ g_warning ("Error: %s", error.message);
+ dbus_error_free (&error);
+ return;
+ }
+#endif
+
+ _gik_im_client_ibus_open (client);
+
+#if USE_DBUS_SESSION_BUS
+ if (!dbus_connection_add_filter (priv->dbus,
+ _gik_im_client_message_filter_cb,
+ client, NULL)) {
+ g_warning ("Out of memory");
+ return;
+ }
+
+ gchar *rule =
+ "type='signal',"
+ "sender='" DBUS_SERVICE_DBUS "',"
+ "interface='" DBUS_INTERFACE_DBUS "',"
+ "member='NameOwnerChanged',"
+ "path='" DBUS_PATH_DBUS "',"
+ "arg0='" IBUS_NAME "'";
+
+ if (!_dbus_call_with_reply_and_block (priv->dbus,
+ DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS,
+ "AddMatch",
+ DBUS_TYPE_STRING, &rule,
+ DBUS_TYPE_INVALID,
+ DBUS_TYPE_INVALID
+ )) {
+ g_warning ("Can not get ibus address");
+ return;
+ }
+#endif
+#if 0
+ /* get dbus proxy */
+ priv->dbus = dbus_g_proxy_new_for_name (priv->ibus,
+ DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS);
+ g_assert (priv->dbus != NULL);
+
+ /* connect NameOwnerChanged signal */
+ dbus_g_proxy_add_signal (priv->dbus, "NameOwnerChanged",
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_INVALID);
+
+ dbus_g_proxy_connect_signal (priv->dbus, "NameOwnerChanged",
+ G_CALLBACK (_dbus_name_owner_changed_cb),
+ (gpointer)client, NULL);
+ dbus_bus_add_match ((DBusConnection *)dbus_g_connection_get_connection (priv->ibus),
+ "type='signal',"
+ "sender='" DBUS_SERVICE_DBUS
+ "',interface='" DBUS_INTERFACE_DBUS
+ "',path='" DBUS_PATH_DBUS
+ "',member='NameOwnerChanged',"
+ "arg0='" GIK_DBUS_SERVICE "'",
+ &dbus_error);
+
+ _gik_im_client_reinit_imm (client);
+#endif
+
+}
+
+
+static void
+gik_im_client_finalize (GObject *obj)
+{
+ DEBUG_FUNCTION_IN;
+
+ GikIMClient *client = GIK_IM_CLIENT (obj);
+ GikIMClientPrivate *priv = client->priv;
+
+ g_assert (client == _client);
+
+ if (priv->preedit_string) {
+ g_free (priv->preedit_string);
+ }
+
+ if (priv->preedit_attrs) {
+ pango_attr_list_unref (priv->preedit_attrs);
+ }
+#if USE_DBUS_SESSION_BUS
+ if (priv->dbus) {
+ dbus_connection_unref (priv->dbus);
+ }
+#endif
+ _gik_im_client_ibus_close (client);
+
+ G_OBJECT_CLASS(parent_class)->finalize (obj);
+
+ _client = NULL;
+}
+
+
+void
+gik_im_client_set_im_context (GikIMClient *client, GtkIMContext *context)
+{
+ GikIMClientPrivate *priv = client->priv;
+ priv->context = context;
+}
+
+GtkIMContext *
+gik_im_client_get_im_context (GikIMClient *client)
+{
+ GikIMClientPrivate *priv = client->priv;
+ return priv->context;
+}
+
+static void
+gik_im_client_commit_string (GikIMClient *client, const gchar *string)
+{
+ GikIMClientPrivate *priv = client->priv;
+
+ if (priv->context) {
+ g_signal_emit_by_name (priv->context, "commit", string);
+ }
+}
+
+static void
+gik_im_client_preedit_changed (GikIMClient *client, const gchar *string, PangoAttrList *attrs, gint cursor_pos)
+{
+ GikIMClientPrivate *priv = client->priv;
+ if (priv->preedit_string) {
+ g_free (priv->preedit_string);
+ }
+ priv->preedit_string = g_strdup (string);
+
+ if (priv->preedit_attrs) {
+ pango_attr_list_unref (priv->preedit_attrs);
+ }
+
+ priv->preedit_attrs = attrs;
+ if (attrs) {
+ pango_attr_list_ref (priv->preedit_attrs);
+ }
+
+ priv->preedit_cursor = cursor_pos;
+ if (priv->context) {
+ g_signal_emit_by_name (priv->context, "preedit-changed");
+ }
+}
+
+static void
+_gik_signal_commit_string_handler (DBusConnection *connection, DBusMessage *message, GikIMClient *client)
+{
+ /* Handle CommitString signal */
+ DBusError error = {0};
+ gchar *string = NULL;
+
+ if (!dbus_message_get_args (message, &error,
+ DBUS_TYPE_STRING, &string, DBUS_TYPE_INVALID)) {
+ g_warning ("%s", error.message);
+ dbus_error_free (&error);
+ }
+ else {
+ gik_im_client_commit_string (client, string);
+ }
+}
+
+static void
+_gik_signal_preedit_changed_handler (DBusConnection *connection, DBusMessage *message, GikIMClient *client)
+{
+ /* Handle PreeditChanged signal */
+ DBusError error = {0};
+ gchar *string = NULL;
+ gint cursor = 0;
+ DBusMessageIter iter, sub_iter;
+ gint type, sub_type;
+ PangoAttrList *attrs = NULL;
+
+ if (!dbus_message_iter_init (message, &iter)) {
+ g_warning ("The PreeditChanged signal does have args!");
+ return;
+ }
+
+ type = dbus_message_iter_get_arg_type (&iter);
+ if (type != DBUS_TYPE_STRING) {
+ g_warning ("The frist argument of PreeditChanged signal must be a String");
+ return;
+ }
+ dbus_message_iter_get_basic (&iter, &string);
+ dbus_message_iter_next (&iter);
+
+
+ type = dbus_message_iter_get_arg_type (&iter);
+ if (type != DBUS_TYPE_ARRAY) {
+ g_warning ("The secode argument of PreeditChanged signal must be a Struct Array");
+ return;
+ }
+ dbus_message_iter_recurse (&iter, &sub_iter);
+ if (dbus_message_iter_get_arg_type (&sub_iter) != DBUS_TYPE_ARRAY ||
+ dbus_message_iter_get_element_type (&sub_iter) != DBUS_TYPE_UINT32 ) {
+ g_warning ("The secode argument of PreeditChanged signal must be a Struct Array");
+ return;
+ }
+
+ attrs = pango_attr_list_new ();
+ while ((sub_type = dbus_message_iter_get_arg_type (&sub_iter) != DBUS_TYPE_INVALID)) {
+ PangoAttribute *attr;
+ DBusMessageIter sub_sub_iter;
+ guint *values = NULL;
+ gint length = 0;
+ dbus_message_iter_recurse (&sub_iter, &sub_sub_iter);
+ dbus_message_iter_get_fixed_array (&sub_sub_iter, &values, &length);
+
+ if (length <= 0) {
+ g_warning ("The element of the second argument of PreeditChanged should not be a empty array");
+ continue;
+ }
+
+ switch (values[0]) {
+ case 1: /* Decoration */
+ attr = pango_attr_underline_new (PANGO_UNDERLINE_SINGLE);
+ attr->start_index = values[2];
+ attr->end_index = values[3];
+ pango_attr_list_insert (attrs, attr);
+ break;
+
+ case 2: /* Foreground Color */
+ attr = pango_attr_foreground_new (
+ (values[1] & 0xff0000) >> 8,
+ (values[1] & 0x00ff00),
+ (values[1] & 0x0000ff) << 8
+ );
+ attr->start_index = values[2];
+ attr->end_index = values[3];
+ pango_attr_list_insert (attrs, attr);
+ break;
+ case 3: /* Background Color */
+ attr = pango_attr_background_new (
+ (values[1] & 0xff0000) >> 8,
+ (values[1] & 0x00ff00),
+ (values[1] & 0x0000ff) << 8
+ );
+ attr->start_index = values[2];
+ attr->end_index = values[3];
+ pango_attr_list_insert (attrs, attr);
+ break;
+ default:
+ g_warning ("Unkown type attribute type = %d", values[0]);
+
+ }
+
+ dbus_message_iter_next (&sub_iter);
+
+ }
+ dbus_message_iter_next (&iter);
+
+ type = dbus_message_iter_get_arg_type (&iter);
+ if (type != DBUS_TYPE_INT32) {
+ g_warning ("The third argument of PreeditChanged signal must be an Int32");
+ pango_attr_list_unref (attrs);
+ return;
+ }
+ dbus_message_iter_get_basic (&iter, &cursor);
+ dbus_message_iter_next (&iter);
+
+ gik_im_client_preedit_changed (client, string, attrs, cursor);
+ pango_attr_list_unref (attrs);
+
+}
+
+static void
+_gik_signal_name_owner_changed_handler (DBusConnection *connection, DBusMessage *message, GikIMClient *client)
+{
+ GikIMClientPrivate *priv = client->priv;
+
+ gchar *name = NULL;
+ gchar *old_name = NULL;
+ gchar *new_name = NULL;
+ DBusError error = {0};
+
+ if (!dbus_message_get_args (message, &error,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_STRING, &old_name,
+ DBUS_TYPE_STRING, &new_name,
+ DBUS_TYPE_INVALID)) {
+ g_warning ("%s", error.message);
+ dbus_error_free (&error);
+ }
+
+ g_return_if_fail (strcmp (name, IBUS_NAME) == 0);
+
+ if (strcmp (new_name, "") == 0) {
+ _gik_im_client_ibus_close (client);
+ priv->enable = FALSE;
+ }
+ else {
+ _gik_im_client_ibus_open (client);
+ priv->enable = TRUE;
+ }
+}
+
+static void
+_gik_signal_enabled_handler (DBusConnection *connection, DBusMessage *message, GikIMClient *client)
+{
+ DEBUG_FUNCTION_IN;
+ client->priv->enable = TRUE;
+}
+
+
+static void
+_gik_signal_disabled_handler (DBusConnection *connection, DBusMessage *message, GikIMClient *client)
+{
+ DEBUG_FUNCTION_IN;
+ client->priv->enable = FALSE;
+}
+static DBusHandlerResult
+_gik_im_client_message_filter_cb (DBusConnection *connection, DBusMessage *message, void *user_data)
+{
+ GikIMClient *client = (GikIMClient *) user_data;
+
+ static struct SIGNAL_HANDLER {
+ const gchar *iface;
+ const gchar *name;
+ void (* handler) (DBusConnection *, DBusMessage *, GikIMClient *);
+ } handlers[] = {
+ { DBUS_INTERFACE_DBUS, "NameOwnerChanged", _gik_signal_name_owner_changed_handler },
+ { IBUS_IFACE, "CommitString", _gik_signal_commit_string_handler },
+ { IBUS_IFACE, "PreeditChanged", _gik_signal_preedit_changed_handler },
+ { IBUS_IFACE, "Enabled", _gik_signal_enabled_handler },
+ { IBUS_IFACE, "Disabled", _gik_signal_disabled_handler },
+ {0},
+ };
+
+ gint i;
+ for (i = 0; handlers[i].iface != NULL; i++) {
+ if (dbus_message_is_signal (message, handlers[i].iface, handlers[i].name)) {
+ handlers[i].handler (connection, message, client);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+inline static gboolean
+_dbus_call_with_reply_and_block_valist (DBusConnection *connection,
+ const gchar *dest, const gchar *path, const gchar* iface, const char *method,
+ gint first_arg_type, va_list args)
+{
+ DBusMessage *message, *reply;
+ DBusError error = {0};
+ int type;
+
+ g_return_val_if_fail (connection != NULL, FALSE);
+
+ message = dbus_message_new_method_call (dest,
+ path, iface, method);
+ if (!message) {
+ g_warning ("Out of memory!");
+ return FALSE;
+ }
+
+ if (!dbus_message_append_args_valist (message, first_arg_type, args)) {
+ dbus_message_unref (message);
+ g_warning ("Can not create call message");
+ return FALSE;
+ }
+
+ reply = dbus_connection_send_with_reply_and_block (connection,
+ message, -1, &error);
+
+ dbus_message_unref (message);
+
+ if (!reply) {
+ g_warning ("%s", error.message);
+ dbus_error_free (&error);
+ return FALSE;
+ }
+
+ type = first_arg_type;
+ while (type != DBUS_TYPE_INVALID) {
+ if (type == DBUS_TYPE_ARRAY) {
+ va_arg (args, int);
+ va_arg (args, void *);
+ va_arg (args, int);
+ }
+ else {
+ va_arg (args, int);
+ }
+ type = va_arg (args, int);
+ }
+
+ type = va_arg (args, int);
+ if (!dbus_message_get_args_valist (reply, &error, type, args)) {
+ g_warning ("%s", error.message);
+ dbus_error_free (&error);
+ dbus_message_unref (reply);
+ return FALSE;
+ }
+ dbus_message_unref (reply);
+
+ return TRUE;
+
+}
+
+inline static gboolean
+_dbus_call_with_reply_and_block (DBusConnection *connection,
+ const gchar *dest, const gchar *path, const gchar* iface, const char *method,
+ gint first_arg_type, ...)
+{
+ va_list args;
+ gboolean retval;
+
+ va_start (args, first_arg_type);
+ retval = _dbus_call_with_reply_and_block_valist (connection,
+ dest, path, iface, method, first_arg_type, args);
+ va_end (args);
+
+ return TRUE;
+
+}
+
+static gboolean
+_ibus_call_with_reply_and_block (DBusConnection *connection, const gchar *method, int first_arg_type, ...)
+{
+ va_list args;
+ gboolean retval;
+
+ va_start (args, first_arg_type);
+ retval = _dbus_call_with_reply_and_block_valist (connection,
+ IBUS_NAME, IBUS_PATH, IBUS_IFACE, method, first_arg_type, args);
+ va_end (args);
+
+ return retval;
+
+}
+
+
+inline static gboolean
+_dbus_call_with_reply_valist (DBusConnection *connection,
+ const gchar *dest, const gchar *path, const gchar* iface, const char *method,
+ DBusPendingCallNotifyFunction notify_function,
+ void *user_data, DBusFreeFunction free_function,
+ gint first_arg_type, va_list args)
+{
+ DBusMessage *message = NULL;
+ DBusPendingCall *pendingcall = NULL;
+ DBusError error = {0};
+ int type;
+
+ if (connection == NULL) {
+ g_warning ("connection != NULL failed");
+ goto error;
+
+ }
+
+ message = dbus_message_new_method_call (dest,
+ path, iface, method);
+ if (!message) {
+ g_warning ("Out of memory!");
+ goto error;
+ }
+
+ if (!dbus_message_append_args_valist (message, first_arg_type, args)) {
+ g_warning ("Can not create call message");
+ goto error;
+ }
+
+ if (!dbus_connection_send_with_reply (connection,
+ message, &pendingcall, -1)) {
+ g_warning ("Out of memory!");
+ goto error;
+ }
+
+ if (!dbus_pending_call_set_notify (pendingcall, notify_function,
+ user_data, free_function)) {
+ g_warning ("Out of memory!");
+ goto error;
+ }
+
+ dbus_message_unref (message);
+ return TRUE;
+
+error:
+ if (message)
+ dbus_message_unref (message);
+ if (pendingcall)
+ dbus_pending_call_cance (pendingcall);
+ if (user_data && free_function)
+ free_function (user_data);
+ return False;
+}
+
+inline static gboolean
+_dbus_call_with_reply (DBusConnection *connection,
+ const gchar *dest, const gchar *path, const gchar* iface, const char *method,
+ DBusPendingCallNotifyFunction notify_function,
+ void *user_data, DBusFreeFunction free_function,
+ gint first_arg_type, ...)
+{
+ va_list args;
+ gboolean retval;
+
+ va_start (args, first_arg_type);
+ retval = _dbus_call_with_reply_valist (connection,
+ dest, path, iface, method,
+ notify_function,
+ user_data, free_function,
+ first_arg_type, args);
+ va_end (args);
+
+ return TRUE;
+
+}
+
+
+
+static gboolean
+_ibus_call_with_reply (DBusConnection *connection, const gchar *method,
+ DBusPendingCallNotifyFunction notify_function,
+ void *user_data, DBusFreeFunction free_function,
+ int first_arg_type, ...)
+{
+ va_list args;
+ gboolean retval;
+
+ va_start (args, first_arg_type);
+ retval = _dbus_call_with_reply_valist (connection,
+ IBUS_NAME, IBUS_PATH, IBUS_IFACE,
+ method, notify_function,
+ user_data, free_function,
+ first_arg_type, args);
+ va_end (args);
+
+ return retval;
+}
+
+
+static void
+_gik_filter_keypress_reply_cb (DBusPendingCall *pending, void *user_data)
+{
+ DBusMessage *reply;
+ DBusError error = {0};
+ GdkEvent *event = (GdkEvent *) user_data;
+ gboolean retval;
+
+
+ reply = dbus_pending_call_steal_reply (pending);
+ dbus_pending_call_unref (pending);
+
+ if (dbus_set_error_from_message (&error, reply)) {
+ g_warning ("%s", error.message);
+ dbus_error_free (&error);
+ retval = FALSE;
+ }
+ else {
+ if (!dbus_message_get_args (reply, &error,
+ DBUS_TYPE_BOOLEAN, &retval, DBUS_TYPE_INVALID)) {
+ g_warning ("%s", error.message);
+ dbus_error_free (&error);
+ retval = FALSE;
+ }
+ }
+
+ if (!retval) {
+ event->any.send_event = TRUE;
+ gdk_event_put (event);
+ }
+}
+
+gboolean
+gik_im_client_filter_keypress (GikIMClient *client, GdkEventKey *event)
+{
+ GikIMClientPrivate *priv = client->priv;
+
+ guint state = event->state & GDK_MODIFIER_MASK;
+ gboolean is_press = event->type == GDK_KEY_PRESS;
+
+ if (event->send_event) {
+ return FALSE;
+ }
+
+ /* Call IBus ProcessKeyEvent method */
+ if (!_ibus_call_with_reply (priv->ibus,
+ "ProcessKeyEvent",
+ _gik_filter_keypress_reply_cb,
+ gdk_event_copy ((GdkEvent *)event),
+ (DBusFreeFunction)gdk_event_free,
+ DBUS_TYPE_UINT32, &event->keyval,
+ DBUS_TYPE_BOOLEAN, &is_press,
+ DBUS_TYPE_UINT32, &state,
+ DBUS_TYPE_INVALID))
+ return FALSE;
+
+ return TRUE;
+}
+
+
+void
+gik_im_client_focus_in (GikIMClient *client)
+{
+ /* Call IBus FocusIn method */
+ _ibus_call_with_reply_and_block (client->priv->ibus,
+ "FocusIn",
+ DBUS_TYPE_INVALID,
+ DBUS_TYPE_INVALID);
+}
+
+void
+gik_im_client_focus_out (GikIMClient *client)
+{
+ /* Call IBus FocusOut method */
+ _ibus_call_with_reply_and_block (client->priv->ibus,
+ "FocusOut",
+ DBUS_TYPE_INVALID,
+ DBUS_TYPE_INVALID);
+
+}
+
+void
+gik_im_client_reset (GikIMClient *client)
+{
+ /* Call IBus Reset method */
+ _ibus_call_with_reply_and_block (client->priv->ibus,
+ "Reset",
+ DBUS_TYPE_INVALID,
+ DBUS_TYPE_INVALID);
+
+}
+
+
+gboolean
+gik_im_client_get_preedit_string (
+ GikIMClient *client,
+ gchar **str,
+ PangoAttrList **attrs,
+ gint *cursor_pos
+)
+{
+ GikIMClientPrivate *priv = client->priv;
+
+ if (str) {
+ *str = g_strdup (priv->preedit_string ? priv->preedit_string: "");
+ }
+
+ if (attrs) {
+ if (priv->preedit_attrs) {
+ *attrs = pango_attr_list_ref (priv->preedit_attrs);
+ }
+ else {
+ *attrs = pango_attr_list_new ();
+ }
+ }
+
+ if (cursor_pos) {
+ *cursor_pos = priv->preedit_cursor;
+ }
+
+ return TRUE;
+}
+
+
+void
+gik_im_client_set_client_window (GikIMClient *client, GdkWindow *window)
+{
+ GikIMClientPrivate *priv = client->priv;
+}
+
+void
+gik_im_client_set_cursor_location (GikIMClient *client, GdkRectangle *area)
+{
+ GikIMClientPrivate *priv = client->priv;
+
+ _ibus_call_with_reply_and_block (client->priv->ibus,
+ "SetCursorLocation",
+ DBUS_TYPE_INT32, &area->x,
+ DBUS_TYPE_INT32, &area->y,
+ DBUS_TYPE_INT32, &area->width,
+ DBUS_TYPE_INT32, &area->height,
+ DBUS_TYPE_INVALID,
+ DBUS_TYPE_INVALID);
+}
+
+
+gboolean
+gik_im_client_is_enabled (GikIMClient *client)
+{
+ return (client->priv->ibus != NULL) && (client->priv->enable);
+}
+
+static void
+gik_im_client_sync_hotkeys (GikIMClient *client)
+{
+ GError *error;
+ gchar **hotkeys = NULL;
+ gint i;
+
+ GikIMClientPrivate *priv = client->priv;
+#if 0
+ g_return_if_fail (priv->imm != NULL);
+
+ error = NULL;
+ if (!dbus_g_proxy_call (priv->imm, "get_hotkeys", &error,
+ G_TYPE_INVALID,
+ G_TYPE_STRV, &hotkeys,
+ G_TYPE_INVALID)) {
+ if (error) {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ }
+ return;
+ }
+
+ for (i = 0; i < g_strv_length (hotkeys); i++) {
+ g_debug ("hotkeys[%d] = %s", i, hotkeys[i]);
+ }
+ g_strfreev (hotkeys);
+#endif
+
+}
+
+/* Callback functions for slave context */
+#if 0
+static void
+_dbus_name_owner_changed_cb (
+ DBusGProxy *proxy,
+ const gchar *name,
+ const gchar *prev_owner,
+ const gchar *new_owner,
+ GikIMClient *client)
+{
+ GikIMClientPrivate *priv = client->priv;
+
+ if (strcmp (name, GIK_DBUS_SERVICE) == 0) {
+ if (strcmp (new_owner, "") == 0) {
+ /* Gik service exited */
+ if (priv->imm) {
+ g_object_unref (priv->imm);
+ priv->imm = NULL;
+ }
+ if (priv->ime) {
+ g_object_unref (priv->ime);
+ priv->ime = NULL;
+ }
+ }
+ else {
+ /* Gik service avaliable or owner changed */
+ _gik_im_client_reinit_imm (client);
+ }
+ }
+}
+
+#endif
diff --git a/gtk2/gikimclient.h b/gtk2/gikimclient.h
new file mode 100644
index 0000000..ba55448
--- /dev/null
+++ b/gtk2/gikimclient.h
@@ -0,0 +1,98 @@
+/* vim:set et ts=4: */
+/* GIK - The G Input Toolkit
+ * Copyright (C) 2008-2009 Huang Peng
+ *
+ * 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.
+ */
+#ifndef __GIK_IM_CLIENT_H_
+#define __GIK_IM_CLIENT_H_
+
+#include <gtk/gtk.h>
+
+/*
+ * Type macros.
+ */
+
+/* define GOBJECT macros */
+#define GIK_TYPE_IM_CLIENT \
+ (gik_im_client_get_type ())
+#define GIK_IM_CLIENT(obj) \
+ (GTK_CHECK_CAST ((obj), GIK_TYPE_IM_CLIENT, GikIMClient))
+#define GIK_IM_CLIENT_CLASS(klass) \
+ (GTK_CHECK_CLASS_CAST ((klass), GIK_TYPE_IM_CLIENT, GikIMClientClass))
+#define GIK_IS_IM_CLIENT(obj) \
+ (GTK_CHECK_TYPE ((obj), GIK_TYPE_IM_CLIENT))
+#define GIK_IS_IM_CLIENT_CLASS(klass) \
+ (GTK_CHECK_CLASS_TYPE ((klass), GIK_TYPE_IM_CLIENT))
+#define GIK_IM_CLIENT_GET_CLASS(obj) \
+ (GTK_CHECK_GET_CLASS ((obj), GIK_TYPE_IM_CLIENT, GikIMClientClass))
+
+#if 0
+#define DEBUG_FUNCTION_IN g_debug("%s IN", __FUNCTION__);
+#define DEBUG_FUNCTION_OUT g_debug("%s OUT", __FUNCTION__);
+#else
+#define DEBUG_FUNCTION_IN
+#define DEBUG_FUNCTION_OUT
+#endif
+
+
+
+#define GIK_DBUS_SERVICE "org.freedesktop.gik"
+#define GIK_DBUS_INTERFACE "org.freedesktop.gik.Manager"
+#define GIK_DBUS_PATH "/org/freedesktop/gik/Manager"
+
+G_BEGIN_DECLS
+typedef struct _GikIMClient GikIMClient;
+typedef struct _GikIMClientClass GikIMClientClass;
+typedef struct _GikIMClientPrivate GikIMClientPrivate;
+
+struct _GikIMClient {
+ GtkObject parent;
+ /* instance members */
+ GikIMClientPrivate *priv;
+};
+
+struct _GikIMClientClass {
+ GtkObjectClass parent;
+ /* class members */
+};
+
+GType gik_im_client_get_type (void);
+GikIMClient *gik_im_client_get_client (void);
+void gik_im_client_register_type (GTypeModule *type_module);
+void gik_im_client_shutdown (void);
+void gik_im_client_focus_in (GikIMClient *client);
+void gik_im_client_focus_out (GikIMClient *client);
+void gik_im_client_set_im_context (GikIMClient *client,
+ GtkIMContext *context);
+GtkIMContext *gik_im_client_get_im_context (GikIMClient *client);
+void gik_im_client_reset (GikIMClient *client);
+gboolean gik_im_client_filter_keypress (GikIMClient *client,
+ GdkEventKey *key);
+gboolean gik_im_client_get_preedit_string
+ (GikIMClient *client,
+ gchar **str,
+ PangoAttrList **attrs,
+ gint *cursor_pos);
+void gik_im_client_set_cursor_location
+ (GikIMClient *client,
+ GdkRectangle *area);
+gboolean gik_im_client_is_enabled (GikIMClient *client);
+
+
+G_END_DECLS
+#endif
+
diff --git a/gtk2/gikimcontext.c b/gtk2/gikimcontext.c
new file mode 100644
index 0000000..5cce476
--- /dev/null
+++ b/gtk2/gikimcontext.c
@@ -0,0 +1,374 @@
+/* vim:set et ts=4: */
+/* GIK - The G Input Toolkit
+ * Copyright (C) 2008-2009 Huang Peng
+ *
+ * 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 <gdk/gdkkeysyms.h>
+#include <gdk/gdkx.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/un.h>
+#include "gikimcontext.h"
+#include "gikimclient.h"
+
+/* define GOBJECT macros */
+#define GIK_TYPE_IM_CONTEXT \
+ (_gik_type_im_context)
+#define GIK_IM_CONTEXT(obj) \
+ (GTK_CHECK_CAST ((obj), GIK_TYPE_IM_CONTEXT, GikIMContext))
+#define GIK_IM_CONTEXT_CLASS(klass) \
+ (GTK_CHECK_CLASS_CAST ((klass), GIK_TYPE_IM_CONTEXT, GikIMContextClass))
+#define GIK_IS_IM_CONTEXT(obj) \
+ (GTK_CHECK_TYPE ((obj), GIK_TYPE_IM_CONTEXT))
+#define GIK_IS_IM_CONTEXT_CLASS(klass) \
+ (GTK_CHECK_CLASS_TYPE ((klass), GIK_TYPE_IM_CONTEXT))
+#define GIK_IM_CONTEXT_GET_CLASS(obj) \
+ (GTK_CHECK_GET_CLASS ((obj), GIK_TYPE_IM_CONTEXT, GikIMContextClass))
+
+#define CURRENT_CONTEXT (gik_im_client_get_im_context (priv->client))
+
+/* GikIMContextPriv */
+struct _GikIMContextPrivate {
+ GtkIMContext *slave;
+ GikIMClient *client;
+ GdkWindow *client_window;
+};
+
+
+/* functions prototype */
+static void gik_im_context_class_init (GikIMContextClass *klass);
+static void gik_im_context_init (GikIMContext *obj);
+static void gik_im_context_finalize (GObject *obj);
+static void gik_im_context_reset (GtkIMContext *context);
+static gboolean gik_im_context_filter_keypress
+ (GtkIMContext *context,
+ GdkEventKey *key);
+static void gik_im_context_focus_in (GtkIMContext *context);
+static void gik_im_context_focus_out (GtkIMContext *context);
+static void gik_im_context_get_preedit_string
+ (GtkIMContext *context,
+ gchar **str,
+ PangoAttrList **attrs,
+ gint *cursor_pos);
+static void gik_im_context_set_client_window
+ (GtkIMContext *context,
+ GdkWindow *client);
+static void gik_im_context_set_cursor_location
+ (GtkIMContext *context,
+ GdkRectangle *area);
+
+/* callback functions for slave context */
+static void _slave_commit_cb (GtkIMContext *slave,
+ gchar *string,
+ GikIMContext *context);
+static void _slave_preedit_changed_cb (GtkIMContext *slave,
+ GikIMContext *context);
+static void _slave_preedit_start_cb (GtkIMContext *slave,
+ GikIMContext *context);
+static void _slave_preedit_end_cb (GtkIMContext *slave,
+ GikIMContext *context);
+static void _slave_retrieve_surrounding_cb
+ (GtkIMContext *slave,
+ GikIMContext *context);
+static void _slave_delete_surrounding_cb
+ (GtkIMContext *slave,
+ gint arg1,
+ gint arg2,
+ GikIMContext *context);
+
+
+
+static GType _gik_type_im_context = 0;
+static GtkIMContextClass *parent_class = NULL;
+
+void
+gik_im_context_register_type (GTypeModule *type_module)
+{
+ static const GTypeInfo gik_im_context_info = {
+ sizeof (GikIMContextClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gik_im_context_class_init,
+ NULL, /* class finialize */
+ NULL, /* class data */
+ sizeof (GikIMContext),
+ 0,
+ (GInstanceInitFunc) gik_im_context_init,
+ };
+
+ if (! _gik_type_im_context ) {
+ _gik_type_im_context =
+ g_type_module_register_type (type_module,
+ GTK_TYPE_IM_CONTEXT,
+ "GikIMContext",
+ &gik_im_context_info,
+ (GTypeFlags)0);
+ }
+}
+
+GtkIMContext *
+gik_im_context_new (void)
+{
+ GikIMContext *obj;
+
+ obj = GIK_IM_CONTEXT(g_object_new (GIK_TYPE_IM_CONTEXT, NULL));
+
+ return GTK_IM_CONTEXT(obj);
+}
+
+static void
+gik_im_context_class_init (GikIMContextClass *klass)
+{
+ GtkIMContextClass *im_context_class = GTK_IM_CONTEXT_CLASS (klass);
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ parent_class = (GtkIMContextClass *) g_type_class_peek_parent (klass);
+
+ g_type_class_add_private (klass, sizeof (GikIMContextPrivate));
+
+ im_context_class->reset = &gik_im_context_reset;
+ im_context_class->focus_in = &gik_im_context_focus_in;
+ im_context_class->focus_out = &gik_im_context_focus_out;
+ im_context_class->filter_keypress = &gik_im_context_filter_keypress;
+ im_context_class->get_preedit_string = &gik_im_context_get_preedit_string;
+ im_context_class->set_client_window = &gik_im_context_set_client_window;
+ im_context_class->set_cursor_location = &gik_im_context_set_cursor_location;
+ gobject_class->finalize = &gik_im_context_finalize;
+}
+
+static void
+gik_im_context_init (GikIMContext *obj)
+{
+ DEBUG_FUNCTION_IN;
+
+ GError *error;
+ GikIMContext *gik = GIK_IM_CONTEXT (obj);
+ gik->priv = G_TYPE_INSTANCE_GET_PRIVATE (gik, GIK_TYPE_IM_CONTEXT, GikIMContextPrivate);
+
+ gik->priv->client = gik_im_client_get_client ();
+ gik->priv->client_window = NULL;
+
+ // Create slave im context
+ gik->priv->slave = gtk_im_context_simple_new ();
+ g_signal_connect (gik->priv->slave,
+ "commit", G_CALLBACK (_slave_commit_cb), obj);
+ g_signal_connect (gik->priv->slave,
+ "preedit-start", G_CALLBACK (_slave_preedit_start_cb), obj);
+ g_signal_connect (gik->priv->slave,
+ "preedit-end", G_CALLBACK (_slave_preedit_end_cb), obj);
+ g_signal_connect (gik->priv->slave,
+ "preedit-changed", G_CALLBACK (_slave_preedit_changed_cb), obj);
+ g_signal_connect (gik->priv->slave,
+ "retrieve-surrounding", G_CALLBACK (_slave_retrieve_surrounding_cb), obj);
+ g_signal_connect (gik->priv->slave,
+ "delete-surrounding", G_CALLBACK (_slave_delete_surrounding_cb), obj);
+}
+
+static void
+gik_im_context_finalize (GObject *obj)
+{
+ DEBUG_FUNCTION_IN;
+
+ GikIMContext *gik = GIK_IM_CONTEXT (obj);
+ GikIMContextPrivate *priv = gik->priv;
+
+ if (GTK_IM_CONTEXT (gik) == CURRENT_CONTEXT) {
+ gik_im_client_focus_out (priv->client);
+ gik_im_client_set_im_context (priv->client, NULL);
+ }
+
+ g_object_unref (priv->slave);
+ g_object_unref (priv->client);
+
+ G_OBJECT_CLASS(parent_class)->finalize (obj);
+}
+
+static gboolean
+gik_im_context_filter_keypress (GtkIMContext *context,
+ GdkEventKey *event)
+{
+ DEBUG_FUNCTION_IN;
+
+ GikIMContext *gik = GIK_IM_CONTEXT (context);
+ GikIMContextPrivate *priv = gik->priv;
+
+ if (context != CURRENT_CONTEXT)
+ return FALSE;
+
+ if (gik_im_client_filter_keypress (priv->client, event))
+ return TRUE;
+ return gtk_im_context_filter_keypress (priv->slave, event);
+}
+
+static void
+gik_im_context_focus_in (GtkIMContext *context)
+{
+ DEBUG_FUNCTION_IN;
+
+ GikIMContext *gik = GIK_IM_CONTEXT (context);
+ GikIMContextPrivate *priv = gik->priv;
+
+ if (context != CURRENT_CONTEXT) {
+ gik_im_client_focus_out (priv->client);
+ gik_im_client_set_im_context (priv->client, context);
+ }
+
+ gik_im_client_focus_in (priv->client);
+ gtk_im_context_focus_in (priv->slave);
+}
+
+static void
+gik_im_context_focus_out (GtkIMContext *context)
+{
+ DEBUG_FUNCTION_IN;
+
+ GikIMContext *gik = GIK_IM_CONTEXT (context);
+ GikIMContextPrivate *priv = gik->priv;
+
+ gik_im_client_focus_out (priv->client);
+ gtk_im_context_focus_out (priv->slave);
+}
+
+static void
+gik_im_context_reset (GtkIMContext *context)
+{
+ DEBUG_FUNCTION_IN;
+
+ GikIMContext *gik = GIK_IM_CONTEXT (context);
+ GikIMContextPrivate *priv = gik->priv;
+
+ if (context == CURRENT_CONTEXT) {
+ gik_im_client_reset (priv->client);
+ }
+ gtk_im_context_reset (priv->slave);
+}
+
+
+static void
+gik_im_context_get_preedit_string (GtkIMContext *context,
+ gchar **str,
+ PangoAttrList **attrs,
+ gint *cursor_pos)
+{
+ DEBUG_FUNCTION_IN;
+
+ GikIMContext *gik = GIK_IM_CONTEXT (context);
+ GikIMContextPrivate *priv = gik->priv;
+
+ if (context == CURRENT_CONTEXT &&
+ gik_im_client_is_enabled (priv->client) &&
+ gik_im_client_get_preedit_string (priv->client, str, attrs, cursor_pos)) {
+ return;
+ }
+ gtk_im_context_get_preedit_string (gik->priv->slave, str, attrs, cursor_pos);
+}
+
+
+static void
+gik_im_context_set_client_window (GtkIMContext *context, GdkWindow *client)
+{
+ DEBUG_FUNCTION_IN;
+
+ GikIMContext *gik = GIK_IM_CONTEXT (context);
+ GikIMContextPrivate *priv = gik->priv;
+ priv->client_window = client;
+ gtk_im_context_set_client_window (gik->priv->slave, client);
+}
+
+static void
+gik_im_context_set_cursor_location (GtkIMContext *context, GdkRectangle *area)
+{
+ DEBUG_FUNCTION_IN;
+
+ GikIMContext *gik = GIK_IM_CONTEXT (context);
+ GikIMContextPrivate *priv = gik->priv;
+ if (context == CURRENT_CONTEXT && gik_im_client_is_enabled (priv->client)) {
+ /* It is the focused context */
+ gint x, y;
+ gdk_window_get_origin (priv->client_window, &x, &y);
+ area->x += x;
+ area->y += y;
+ gik_im_client_set_cursor_location (priv->client, area);
+ }
+ gtk_im_context_set_cursor_location (priv->slave, area);
+}
+
+/* Callback functions for slave context */
+static void
+_slave_commit_cb (GtkIMContext *slave, gchar *string, GikIMContext *context)
+{
+ DEBUG_FUNCTION_IN;
+
+ GikIMContextPrivate *priv = context->priv;
+#if 0
+ if ((GtkIMContext *)context == CURRENT_CONTEXT && gik_im_client_is_enabled (priv->client))
+ return;
+#endif
+ g_signal_emit_by_name (context, "commit", string);
+}
+
+static void
+_slave_preedit_changed_cb (GtkIMContext *slave, GikIMContext *context)
+{
+ DEBUG_FUNCTION_IN;
+ GikIMContextPrivate *priv = context->priv;
+ if ((GtkIMContext *)context == CURRENT_CONTEXT && gik_im_client_is_enabled (priv->client))
+ return;
+ g_signal_emit_by_name (context, "preedit-changed");
+}
+
+static void
+_slave_preedit_start_cb (GtkIMContext *slave, GikIMContext *context)
+{
+ DEBUG_FUNCTION_IN;
+ GikIMContextPrivate *priv = context->priv;
+ if ((GtkIMContext *)context == CURRENT_CONTEXT && gik_im_client_is_enabled (priv->client))
+ return;
+ g_signal_emit_by_name (context, "preedit-start");
+}
+
+static void
+_slave_preedit_end_cb (GtkIMContext *slave, GikIMContext *context)
+{
+ DEBUG_FUNCTION_IN;
+ GikIMContextPrivate *priv = context->priv;
+ if ((GtkIMContext *)context == CURRENT_CONTEXT && gik_im_client_is_enabled (priv->client))
+ return;
+ g_signal_emit_by_name (context, "preedit-end");
+}
+
+static void
+_slave_retrieve_surrounding_cb (GtkIMContext *slave, GikIMContext *context)
+{
+ DEBUG_FUNCTION_IN;
+ GikIMContextPrivate *priv = context->priv;
+ if ((GtkIMContext *)context == CURRENT_CONTEXT && gik_im_client_is_enabled (priv->client))
+ return;
+ g_signal_emit_by_name (context, "retrieve-surrounding");
+}
+
+static void
+_slave_delete_surrounding_cb (GtkIMContext *slave, gint a1, gint a2, GikIMContext *context)
+{
+ DEBUG_FUNCTION_IN;
+ GikIMContextPrivate *priv = context->priv;
+ if ((GtkIMContext *)context == CURRENT_CONTEXT && gik_im_client_is_enabled (priv->client))
+ return;
+ g_signal_emit_by_name (context, "delete-surrounding", a1, a2);
+}
+
diff --git a/gtk2/gikimcontext.h b/gtk2/gikimcontext.h
new file mode 100644
index 0000000..39f8e4e
--- /dev/null
+++ b/gtk2/gikimcontext.h
@@ -0,0 +1,51 @@
+/* vim:set et ts=4: */
+/* GIK - The G Input Toolkit
+ * Copyright (C) 2008-2009 Huang Peng
+ *
+ * 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.
+ */
+#ifndef __GIK_IM_CONTEXT_H_
+#define __GIK_IM_CONTEXT_H_
+
+#include <gtk/gtk.h>
+
+/*
+ * Type macros.
+ */
+
+G_BEGIN_DECLS
+typedef struct _GikIMContext GikIMContext;
+typedef struct _GikIMContextClass GikIMContextClass;
+typedef struct _GikIMContextPrivate GikIMContextPrivate;
+
+struct _GikIMContext {
+ GtkIMContext parent;
+ /* instance members */
+ GikIMContextPrivate *priv;
+};
+
+struct _GikIMContextClass {
+ GtkIMContextClass parent;
+ /* class members */
+};
+
+GtkIMContext *gik_im_context_new (void);
+void gik_im_context_register_type (GTypeModule *type_module);
+void gik_im_context_shutdown (void);
+
+G_END_DECLS
+#endif
+
diff --git a/ibus/Makefile b/ibus/Makefile
new file mode 100644
index 0000000..f24037e
--- /dev/null
+++ b/ibus/Makefile
@@ -0,0 +1,6 @@
+PYTHON = env PYTHONPATH=../ python
+test-server:
+ $(PYTHON) ./ibusdaemon.py
+
+test-engine:
+ $(PYTHON) ./eng_demo.py
diff --git a/ibus/__init__.py b/ibus/__init__.py
new file mode 100644
index 0000000..8832e1e
--- /dev/null
+++ b/ibus/__init__.py
@@ -0,0 +1,11 @@
+from object import *
+from attribute import *
+from common import *
+from connection import *
+from interface import *
+from bus import *
+from client import *
+from engine import *
+from factorymanager import *
+from clientmanager import *
+from exception import *
diff --git a/ibus/attribute.py b/ibus/attribute.py
new file mode 100644
index 0000000..437bc2a
--- /dev/null
+++ b/ibus/attribute.py
@@ -0,0 +1,58 @@
+
+import dbus
+
+ATTR_TYPE_DECORATION = 1
+ATTR_TYPE_FOREGROUND = 2
+ATTR_TYPE_BACKGROUND = 3
+
+ATTR_DECORATION_NONE = 0
+ATTR_DECORATION_UNDERLINE = 1
+ATTR_DECORATION_HIGHLIGHT = 2
+ATTR_DECORATION_REVERSE = 4
+
+class Attribute:
+ def __init__ (self, type, value, start_index, end_index):
+ self._type = type
+ self._start_index = start_index
+ self._end_index = end_index
+ self._value = value
+
+ def get_values (self):
+ return [dbus.UInt32 (self._type),
+ dbus.UInt32 (self._value),
+ dbus.UInt32 (self._start_index),
+ dbus.UInt32 (self._end_index)]
+
+class AttributeDecoration (Attribute):
+ def __init__(self, value, start_index, end_index):
+ Attribute.__init__ (self, ATTR_TYPE_DECORATION, value, start_index, end_index)
+
+
+class AttributeForeground (Attribute):
+ def __init__(self, value, start_index, end_index):
+ Attribute.__init__ (self, ATTR_TYPE_FOREGROUND, value, start_index, end_index)
+
+class AttributeBackground (Attribute):
+ def __init__(self, value, start_index, end_index):
+ Attribute.__init__ (self, ATTR_TYPE_BACKGROUND, value, start_index, end_index)
+
+def ARGB (a, r, g, b):
+ return ((a & 0xff)<<24) + ((r & 0xff) << 16) + ((g & 0xff) << 8) + (b & 0xff)
+
+def RGB (r, g, b):
+ return ARGB (255, r, g, b)
+
+class AttrList:
+ def __init__ (self, attrs = []):
+ self._attrs = []
+ for attr in attrs:
+ self.append (attr)
+
+ def append (self, attr):
+ assert isinstance (attr, Attribute)
+ self._attrs.append (attr)
+
+ def get_array (self):
+ get_values = lambda attr: attr.get_values ()
+ return map (get_values, self._attrs)
+
diff --git a/ibus/bus.py b/ibus/bus.py
new file mode 100755
index 0000000..01e5e73
--- /dev/null
+++ b/ibus/bus.py
@@ -0,0 +1,168 @@
+#!/usr/bin/env python
+import weakref
+import dbus
+import ibus
+from ibus import keysyms
+
+class IBus (ibus.Object):
+ def __init__ (self):
+ ibus.Object.__init__ (self)
+ self._connections = {}
+ self._client_manager = ibus.ClientManager ()
+ self._factory_manager = ibus.FactoryManager ()
+
+ self._focused_client = None
+ self._last_focused_client = None
+
+ self._last_key = None
+
+ def new_connection (self, dbusconn):
+ assert dbusconn not in self._connections
+ self._connections[dbusconn] = ibus.Connection (dbusconn)
+
+ def remove_connection (self, dbusconn):
+ assert dbusconn in self._connections
+
+ # destroy the connection
+ self._connections[dbusconn].destroy ()
+ del self._connections[dbusconn]
+
+ def _lookup_ibus_connection (self, dbusconn):
+ if dbusconn not in self._connections:
+ raise ibus.IBusException ("can not find ibus.Connection")
+ return self._connections[dbusconn]
+
+ ##########################################################
+ # methods for im client
+ ##########################################################
+ def register_client (self, name, dbusconn):
+ ibusconn = self._lookup_ibus_connection (dbusconn)
+ client = self._client_manager.register_client (name, ibusconn)
+ factory = self._factory_manager.get_default_factory ()
+ client.set_engine_factory (factory)
+
+ def focus_in (self, dbusconn):
+ client = self._lookup_client (dbusconn)
+
+ if self._focused_client != client and self._focused_client != None:
+ self._focused_client.focus_out ()
+
+ self._focused_client = client
+ self._last_focused_client = client
+ client.focus_in ()
+
+ def focus_out (self, dbusconn):
+ client = self._lookup_client (dbusconn)
+ if client == self._focused_client:
+ self._focused_client = None
+ client.focus_out ()
+
+ def reset (self, dbusconn):
+ client = self._lookup_client (dbusconn)
+ client.reset ()
+
+ def is_enabled (self, dbusconn):
+ client = self._lookup_client (dbusconn)
+ return client.is_enabled ()
+
+ def process_key_event (self, keyval, is_press, state,
+ dbusconn, reply_cb, error_cb):
+ client = self._lookup_client (dbusconn)
+
+ if self._filter_hotkeys (client, keyval, is_press, state):
+ reply_cb (True)
+ return
+ else:
+ client.process_key_event (keyval, is_press, state, reply_cb, error_cb)
+
+ def set_cursor_location (self, x, y, w, h, dbusconn):
+ client = self._lookup_client (dbusconn)
+ client.set_cursor_location (x, y, w, h)
+
+ def _filter_hotkeys (self, client, keyval, is_press, state):
+ if is_press and keyval == keysyms.space \
+ and state == keysyms.CONTROL_MASK:
+ enable = not client.is_enabled ()
+ client.set_enable (enable)
+ if client.get_engine_factory () == None and enable:
+ factory = self._factory_manager.get_default_factory()
+ client.set_engine_factory (factory)
+ return True
+ return False
+
+ def _lookup_client (self, dbusconn):
+ ibusconn = self._lookup_ibus_connection (dbusconn)
+ return self._client_manager.lookup_client (ibusconn)
+ if dbusconn not in self._clients:
+ raise ibus.IBusException ("not register the client")
+ return self._clients[dbusconn]
+
+ ##########################################################
+ # methods for im client
+ ##########################################################
+ def register_factories (self, object_paths, dbusconn):
+ ibusconn = self._lookup_ibus_connection (dbusconn)
+ self._factory_manager.register_factories (object_paths, ibusconn)
+
+ def dispatch_dbus_signal (self, dbusconn, message):
+ ibusconn = self._lookup_ibus_connection (dbusconn)
+ ibusconn.dispatch_dbus_signal (message)
+
+ def _lookup_engine (self, dbusconn, path):
+ ibusconn = self._lookup_ibus_connection (dbusconn)
+ return self._factory_manager.lookup_engine (ibusconn, path)
+
+
+
+
+class IBusProxy (ibus.IIBus):
+ SUPPORTS_MULTIPLE_CONNECTIONS = True
+
+ def __init__ (self):
+ ibus.IIBus.__init__ (self)
+ self._ibus = IBus ()
+
+ def new_connection (self, dbusconn):
+ self._ibus.new_connection (dbusconn)
+
+ def remove_connection (self, dbusconn):
+ self._ibus.remove_connection (dbusconn)
+
+ def dispatch_dbus_signal (self, dbusconn, message):
+ return self._ibus.dispatch_dbus_signal (dbusconn, message)
+
+ def GetIBusAddress (self, dbusconn):
+ return self._ibus_addr
+
+ def RegisterClient (self, client_name, dbusconn):
+ self._ibus.register_client (client_name, dbusconn)
+
+ def RegisterFactories (self, object_paths, dbusconn):
+ self._ibus.register_factories (object_paths, dbusconn)
+
+ def UnregisterEngines (self, object_paths, dbusconn):
+ self._ibus.unregister_engines (object_paths, dbusconn)
+
+ def ProcessKeyEvent (self, keyval, is_press, state, \
+ dbusconn, reply_cb, error_cb):
+ try:
+ self._ibus.process_key_event (keyval, is_press, state,
+ dbusconn, reply_cb, error_cb)
+ except Exception, e:
+ error_cb (e)
+
+ def SetCursorLocation (self, x, y, w, h, dbusconn):
+ self._ibus.set_cursor_location (x, y, w, h, dbusconn)
+
+ def FocusIn (self, dbusconn):
+ self._ibus.focus_in (dbusconn)
+
+ def FocusOut (self, dbusconn):
+ self._ibus.focus_out (dbusconn)
+
+ def Reset (self, dbusconn):
+ self._ibus.reset (dbusconn)
+
+ def IsEnabled (self, dbusconn):
+ return self._ibus.is_enabled (dbusconn)
+
diff --git a/ibus/client.py b/ibus/client.py
new file mode 100644
index 0000000..21e7eac
--- /dev/null
+++ b/ibus/client.py
@@ -0,0 +1,107 @@
+import ibus
+
+class Client (ibus.Object):
+ def __init__ (self, name, ibusconn):
+ ibus.Object.__init__ (self)
+
+ self._ibusconn = ibusconn
+ self._ibusconn.connect ("destroy", self._ibusconn_destroy_cb)
+
+ # init default values
+ self._enable = False
+ self._factory = None
+ self._engine = None
+ self._engine_handler_ids = []
+
+ def process_key_event (self, keyval, is_press, state,
+ reply_cb, error_cb):
+ if self._engine != None and self._enable:
+ self._engine.process_key_event (keyval, is_press, state,
+ reply_cb, error_cb)
+ else:
+ reply_cb (False)
+
+ def set_cursor_location (self, x, y, w, h):
+ if self._engine:
+ self._engine.set_cursor_location (x, y, w, h)
+
+ def focus_in (self):
+ if self._engine:
+ self._engine.focus_in ()
+
+ def focus_out (self):
+ if self._engine:
+ self._engine.focus_out ()
+
+ def reset (self):
+ if self._engine:
+ self._engine.reset ()
+
+ def is_enabled (self):
+ return self._enable
+
+ def set_enable (self, enable):
+ if self._enable != enable:
+ self._enable = enable
+ if self._enable:
+ self._ibusconn.emit_dbus_signal ("Enabled")
+ else:
+ self._ibusconn.emit_dbus_signal ("Disabled")
+ if self._engine:
+ self._engine.set_enable (self._enable)
+
+ def commit_string (self, text):
+ self._ibusconn.emit_dbus_signal ("CommitString", text)
+
+ def preedit_changed (self, text, attrs, cursor):
+ self._ibusconn.emit_dbus_signal ("PreeditChanged", text, attrs.get_array (), cursor)
+
+ def set_engine_factory (self, factory):
+ if self._factory == factory:
+ return
+
+ if self._engine != None:
+ self._remove_engine_handlers ()
+ self._engine.destroy ()
+ self._engine = None
+
+ self._factory = factory
+
+ if self._factory:
+ self._engine = self._factory.create_engine ()
+ self._install_engine_handlers ()
+
+ def get_engine_factory (self):
+ return self._factory
+
+ def _engine_destroy_cb (self, engine):
+ if self._engine == engine:
+ self._remove_engine_handlers ()
+ self._engine = None
+ self._factory = None
+
+ def _ibusconn_destroy_cb (self, ibusconn):
+ self._factory = None
+ if self._engine != None:
+ self._remove_engine_handlers ()
+ self._engine.destroy ()
+ self._engine = None
+
+ def _commit_string_cb (self, engine, text):
+ self.commit_string (text)
+
+ def _preedit_changed_cb (self, engine, text, attrs, cursor):
+ self.preedit_changed (self, text, attrs, cursor)
+
+ def _remove_engine_handlers (self):
+ assert self._engine != None
+ for id in self._engine_handler_ids:
+ self._engine.disconnect (id)
+ self._engine_handler_ids = []
+
+ def _install_engine_handlers (self):
+ id = self._engine.connect ("destroy", self._engine_destroy_cb)
+ id = self._engine.connect ("commit-string", self._commit_string_cb)
+ self._engine_handler_ids.append (id)
+ id = self._engine.connect ("preedit-changed", self._preedit_changed_cb)
+ self._engine_handler_ids.append (id)
diff --git a/ibus/clientmanager.py b/ibus/clientmanager.py
new file mode 100644
index 0000000..92030da
--- /dev/null
+++ b/ibus/clientmanager.py
@@ -0,0 +1,20 @@
+import ibus
+
+class ClientManager (ibus.Object):
+ def __init__ (self):
+ self._clients = {}
+
+ def register_client (self, name, ibusconn):
+ if ibusconn in self._clients:
+ raise ibus.IBusException ("client has been registered")
+ client = ibus.Client (name, ibusconn)
+ self._clients[ibusconn] = client
+ ibusconn.connect ("destroy", self._ibusconn_destroy_cb)
+ return client
+
+ def lookup_client (self, ibusconn):
+ return self._clients[ibusconn]
+
+ def _ibusconn_destroy_cb (self, ibusconn):
+ del self._clients[ibusconn]
+
diff --git a/ibus/common.py b/ibus/common.py
new file mode 100644
index 0000000..76eab3e
--- /dev/null
+++ b/ibus/common.py
@@ -0,0 +1,20 @@
+IBUS_ADDR = "unix:abstract=/tmp/ibus"
+# IBUS_ADDR = "tcp:host=localhost,port=7799"
+
+IBUS_IFACE = "org.freedesktop.IBus"
+IBUS_PATH = "/org/freedesktop/IBus"
+IBUS_NAME = "org.freedesktop.IBus"
+
+IBUS_ENGINE_FACTORY_IFACE = "org.freedesktop.IBus.EngineFactory"
+IBUS_ENGINE_IFACE = "org.freedesktop.IBus.Engine"
+
+def default_reply_handler ( *args):
+ pass
+
+def default_error_handler (e):
+ print e
+
+DEFAULT_ASYNC_HANDLERS = {
+ "reply_handler" : default_reply_handler,
+ "error_handler" : default_error_handler
+}
diff --git a/ibus/connection.py b/ibus/connection.py
new file mode 100644
index 0000000..f1d2882
--- /dev/null
+++ b/ibus/connection.py
@@ -0,0 +1,32 @@
+import dbus.lowlevel
+import ibus
+import gobject
+
+class Connection (ibus.Object):
+ __gsignals__ = {
+ "dbus-signal" : (
+ gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ (gobject.TYPE_PYOBJECT, )
+ )
+ }
+ def __init__ (self, dbusconn):
+ ibus.Object.__init__ (self)
+ self._dbusconn = dbusconn
+
+ def get_object (self, path):
+ return self._dbusconn.get_object ("no.name", path)
+
+ def emit_dbus_signal (self, name, *args):
+ message = dbus.lowlevel.SignalMessage (ibus.IBUS_PATH, ibus.IBUS_IFACE, name)
+ message.append (*args)
+ self._dbusconn.send_message (message)
+ self._dbusconn.flush ()
+
+ def do_destroy (self):
+ self._dbusconn = None
+
+ def dispatch_dbus_signal (self, message):
+ self.emit ("dbus-signal", message)
+
+gobject.type_register (Connection)
diff --git a/ibus/driver.py b/ibus/driver.py
new file mode 100755
index 0000000..8b22e2a
--- /dev/null
+++ b/ibus/driver.py
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+
+import dbus
+import dbus.server
+import dbus.lowlevel
+import dbus.service
+import dbus.mainloop.glib
+import gobject
+
+class DBusObject (dbus.service.Object):
+ SUPPORTS_MULTIPLE_CONNECTIONS = True
+ def __init__ (self):
+ dbus.service.Object.__init__ (self)
+ self._max_id = 1
+
+ @dbus.service.method (dbus_interface=dbus.BUS_DAEMON_IFACE, out_signature="s", connection_keyword="connection")
+ def Hello (self, connection):
+ print "Hello is called"
+ name = "ibus.%d" % self._max_id
+ self._max_id = self._max_id +1
+ connection.set_unique_name (name)
+ return name
+
+
diff --git a/ibus/eng_demo.py b/ibus/eng_demo.py
new file mode 100755
index 0000000..f599394
--- /dev/null
+++ b/ibus/eng_demo.py
@@ -0,0 +1,136 @@
+#!/usr/bin/env python
+import interface
+import gobject
+import gtk
+import dbus.connection
+import dbus.mainloop.glib
+import ibus.keysyms as keysyms
+from ibus.common import \
+ IBUS_NAME, \
+ IBUS_IFACE, \
+ IBUS_PATH, \
+ IBUS_ADDR
+
+IBUS_DEMO_ENGINE_FACTORY_PATH = "/com/redhat/IBus/engines/Demo/Factory"
+IBUS_DEMO_ENGINE_PATH = "/com/redhat/IBus/engines/Demo/Engine/%d"
+
+class LookupTable (gtk.Window):
+ def __init__ (self):
+ gtk.Window.__init__ (self, gtk.WINDOW_POPUP)
+ self._enable = False
+ # create ui
+ vbox = gtk.VBox ()
+ self._preedit_label = gtk.Label ("preedit string")
+ self._candidates_label = gtk.Label ("candidates")
+ vbox.pack_start (self._preedit_label)
+ vbox.pack_start (self._candidates_label)
+ self.add (vbox)
+
+ def focus_in (self):
+ if self._enable:
+ self.show_all ()
+
+ def focus_out (self):
+ if self._enable:
+ self.hide_all ()
+
+ def set_enable (self, enable):
+ self._enable = enable
+ if enable:
+ self.show_all ()
+ else:
+ self.hide_all ()
+
+ def set_cursor_location (self, x, y, w, h):
+ self.move (x + w, y + h)
+
+class DemoEngineFactory (interface.IEngineFactory):
+ NAME = "DemoEngine"
+ LANG = "en"
+ ICON = ""
+ AUTHORS = "Huang Peng <shawn.p.huang@gmail.com>"
+ CREDITS = "GPLv2"
+
+ def __init__ (self, dbusconn):
+ interface.IEngineFactory.__init__ (self, dbusconn, object_path = IBUS_DEMO_ENGINE_FACTORY_PATH)
+ self._dbusconn = dbusconn
+ self._max_engine_id = 1
+
+ def GetInfo (self):
+ return [
+ self.NAME,
+ self.LANG,
+ self.ICON,
+ self.AUTHORS,
+ self.CREDITS
+ ]
+
+ def CreateEngine (self):
+ engine_path = IBUS_DEMO_ENGINE_PATH % self._max_engine_id
+ self._max_engine_id += 1
+ return DemoEngine (self._dbusconn, engine_path)
+
+
+class DemoEngine (interface.IEngine):
+
+ def __init__ (self, dbusconn, object_path):
+ interface.IEngine.__init__ (self, dbusconn, object_path = object_path)
+ self._dbusconn = dbusconn
+ self._lookup_table = LookupTable ()
+
+ def ProcessKeyEvent (self, keyval, is_press, state):
+ if not is_press:
+ return False
+ if keyval < 128 and (state & keysyms.CONTROL_MASK | keysyms.MOD1_MASK | keysyms.SHIFT_MASK) == 0:
+ self.CommitString (chr(keyval))
+ print "commit %s" % chr(keyval)
+ return True
+ return False
+
+ def FocusIn (self):
+ print "FocusIn"
+ self._lookup_table.focus_in ()
+
+ def FocusOut (self):
+ print "FocusOut"
+ self._lookup_table.focus_out ()
+
+ def Reset (self):
+ print "Reset"
+
+ def SetEnable (self, enable):
+ self._enable = enable
+ self._lookup_table.set_enable (enable)
+
+ def Destroy (self):
+ print "Destroy"
+ self._lookup_table.destroy ()
+
+ def SetCursorLocation (self, x, y, w, h):
+ self._lookup_table.set_cursor_location (x, y, w, h)
+
+
+class IMApp:
+ def __init__ (self):
+ self._dbusconn = dbus.connection.Connection (IBUS_ADDR)
+ self._dbusconn.add_signal_receiver (self._disconnected_cb,
+ "Disconnected",
+ dbus_interface=dbus.LOCAL_IFACE)
+ self._engine = DemoEngineFactory (self._dbusconn)
+ self._ibus = self._dbusconn.get_object (IBUS_NAME, IBUS_PATH)
+ self._ibus.RegisterFactories ([IBUS_DEMO_ENGINE_FACTORY_PATH])
+
+ def run (self):
+ gtk.main ()
+
+ def _disconnected_cb (self):
+ print "disconnected"
+ gtk.main_quit ()
+
+
+def main ():
+ IMApp ().run ()
+
+if __name__ == "__main__":
+ dbus.mainloop.glib.DBusGMainLoop (set_as_default=True)
+ main ()
diff --git a/ibus/engine.py b/ibus/engine.py
new file mode 100644
index 0000000..ec55a17
--- /dev/null
+++ b/ibus/engine.py
@@ -0,0 +1,123 @@
+import weakref
+import gobject
+import ibus
+
+class EngineFactory (ibus.Object):
+ def __init__ (self, ibusconn, object_path):
+ ibus.Object.__init__ (self)
+ self._ibusconn = ibusconn
+ self._object_path = object_path
+ self._factory = self._ibusconn.get_object (self._object_path)
+
+ self._ibusconn.connect ("destroy", self._ibusconn_destroy_cb)
+
+ self._ibusconn.connect ("dbus-signal", self._dbus_signal_cb)
+ self._engines = weakref.WeakValueDictionary ()
+
+ self._info = None
+
+ def get_object_path (self):
+ return self._object_path
+
+ def get_info (self):
+ if self._info == None:
+ self._info = self._factory.GetInfo ()
+ return self._info
+
+ def create_engine (self):
+ object_path = self._factory.CreateEngine ()
+ engine = Engine (self._ibusconn, object_path)
+ self._engines[object_path] = engine
+ return engine
+
+ def destroy (self):
+ ibus.Object.destroy (self)
+ self._ibusconn = None
+ self._factory = None
+
+ def _ibusconn_destroy_cb (self, ibusconn):
+ self.destroy ()
+
+ def _dbus_signal_cb (self, ibusconn, message):
+ object_path = message.get_path ()
+ if object_path in self._engines:
+ self._engines[object_path].handle_dbus_signal (message)
+
+ # methods for cmp
+ def __lt__ (self, other):
+ x = self.get_info ()
+ y = other.get_info ()
+ if x[1] < y[1]: return True
+ if x[1] == y[1]: return x[0] < y[0]
+
+ def __gt__ (self, other):
+ x = self.get_info ()
+ y = other.get_info ()
+ if x[1] > y[1]: return True
+ if x[1] == y[1]: return x[0] > y[0]
+
+
+class Engine (ibus.Object):
+ __gsignals__ = {
+ "commit-string" : (
+ gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ (gobject.TYPE_STRING, )),
+ "preedit-changed" : (
+ gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ (gobject.TYPE_STRING, gobject.TYPE_PYOBJECT, gobject.TYPE_UINT))
+ }
+
+ def __init__ (self, ibusconn, object_path):
+ ibus.Object.__init__ (self)
+ self._ibusconn = ibusconn
+ self._object_path = object_path
+ self._engine = ibusconn.get_object (self._object_path)
+ self._ibusconn.connect ("destroy", self._ibusconn_destroy_cb)
+
+ def handle_dbus_signal (self, message):
+ if message.is_signal (ibus.IBUS_ENGINE_IFACE, "CommitString"):
+ args = message.get_args_list ()
+ self.emit ("commit-string", args[0])
+ return True
+ elif message.is_signal (ibus.IBUS_ENGINE_IFACE, "PreeditChanged"):
+ args = message.get_args_list ()
+ self.emit ("preedit-changed", args[0], args[1], args[2])
+ return True
+ else:
+ return False
+
+ def focus_in (self):
+ self._engine.FocusIn (**ibus.DEFAULT_ASYNC_HANDLERS)
+
+ def focus_out (self):
+ self._engine.FocusOut (**ibus.DEFAULT_ASYNC_HANDLERS)
+
+ def reset (self):
+ self._engine.Reset (**ibus.DEFAULT_ASYNC_HANDLERS)
+
+ def process_key_event (self, keyval, is_press, state, reply_cb, error_cb):
+ self._engine.ProcessKeyEvent (keyval, is_press, state,
+ reply_handler = reply_cb,
+ error_handler = error_cb)
+
+ def set_cursor_location (self, x, y, w, h):
+ self._engine.SetCursorLocation (x, y, w, h)
+
+ def set_enable (self, enable):
+ self._engine.SetEnable (enable)
+
+ def destroy (self):
+ ibus.Object.destroy (self)
+ if self._engine:
+ self._engine.Destroy ()
+ self._engine = None
+ self._ibusconn = None
+
+ def _ibusconn_destroy_cb (self, ibusconn):
+ self._engine = None
+ self.destroy ()
+
+gobject.type_register (Engine)
+
diff --git a/ibus/exception.py b/ibus/exception.py
new file mode 100644
index 0000000..c699209
--- /dev/null
+++ b/ibus/exception.py
@@ -0,0 +1,2 @@
+class IBusException (Exception):
+ pass
diff --git a/ibus/factorymanager.py b/ibus/factorymanager.py
new file mode 100644
index 0000000..ffc7885
--- /dev/null
+++ b/ibus/factorymanager.py
@@ -0,0 +1,76 @@
+import weakref
+import gobject
+import ibus
+
+class FactoryManager (ibus.Object):
+ __gsignals__ = {
+ 'new-factories-added' : (
+ gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ (gobject.TYPE_PYOBJECT, )
+ )
+ }
+ def __init__ (self):
+ ibus.Object.__init__ (self)
+ self._factories = {}
+ self._ibusconn_factory_dict = {}
+ self._default_factory = None
+ self._sorted_factories = None
+
+ def register_factories (self, object_paths, ibusconn):
+ if ibusconn in self._factories:
+ raise ibus.IBusException ("this conn has registered factories!")
+
+ self._ibusconn_factory_dict[ibusconn] = []
+
+ for object_path in object_paths:
+ if object_path in self._factories:
+ raise ibus.IBusException (
+ "Factory [%s] has been registered!" % object_path)
+
+ factory = ibus.EngineFactory (ibusconn, object_path)
+ self._factories[object_path] = factory
+ self._ibusconn_factory_dict[ibusconn].append (object_path)
+
+ ibusconn.connect ("destroy", self._ibusconn_destroy_cb)
+
+ self.emit ("new-factories-added",
+ self._ibusconn_factory_dict[ibusconn][:])
+
+ def get_default_factory (self):
+ if self._default_factory == None:
+ factories = self._get_sorted_factories ()
+ if factories:
+ self._default_factory = factories[0]
+
+ return self._default_factory
+
+ def get_next_factory (self, factory):
+ factories = self._get_sorted_factories ()
+ i = factories.index (factory) + 1
+ if i >= len (factories):
+ i = 0
+
+ return factories[i]
+
+ def _get_sorted_factories (self, resort = False):
+ if not self._sorted_factories or resort:
+ factories = self._factories.values ()
+ factories.sort ()
+ self._sorted_factories = factories
+ return self._sorted_factories
+
+ def _ibusconn_destroy_cb (self, ibusconn):
+ assert ibusconn in self._ibusconn_factory_dict
+
+ for object_path in self._ibusconn_factory_dict[ibusconn]:
+ factory = self._factories[object_path]
+ if factory == self._default_factory:
+ self._default_factory = None
+ del self._factories[object_path]
+
+ del self._ibusconn_factory_dict[ibusconn]
+ self._sorted_factories = None
+
+gobject.type_register (FactoryManager)
+
diff --git a/ibus/ibusdaemon.py b/ibus/ibusdaemon.py
new file mode 100755
index 0000000..5093562
--- /dev/null
+++ b/ibus/ibusdaemon.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+import sys
+import gobject
+import dbus.server
+import dbus.lowlevel
+import dbus.mainloop.glib
+import ibus
+
+class IBusServer (dbus.server.Server):
+ def __init__ (self):
+ dbus.server.Server.__init__ (self, ibus.IBUS_ADDR)
+ self._ibus = ibus.IBusProxy ()
+
+ self.register_object (self._ibus, ibus.IBUS_PATH)
+
+ def new_connection (self, server, dbusconn):
+ dbusconn.add_message_filter (self.message_filter_cb)
+ self._ibus.new_connection (dbusconn)
+
+ def remove_connection (self, dbusconn):
+ self._ibus.remove_connection (dbusconn)
+
+ def message_filter_cb (self, dbusconn, message):
+ if message.is_method_call (dbus.LOCAL_IFACE, "Disconnected"):
+ return dbus.lowlevel.HANDLER_RESULT_NOT_YET_HANDLED
+
+ if message.get_type () == 4: # is signal
+ if self._ibus.dispatch_dbus_signal (dbusconn, message):
+ return dbus.lowlevel.HANDLER_RESULT_HANDLED
+
+ return dbus.lowlevel.HANDLER_RESULT_NOT_YET_HANDLED
+
+ def _print_message (self, message):
+ print "Got a Message (%s) : " % message.__class__.__name__
+ print "\t From: %s" % message.get_sender ()
+ print "\t To: %s" % message.get_destination ()
+ print "\t Interface: %s" % message.get_interface ()
+ print "\t Path: %s" % message.get_path ()
+ print "\t Member: %s" % message.get_member ()
+ print "\t Arguments:"
+ i = 0
+ for arg in message.get_args_list():
+ print "\t\t Arg[%d] : %s" % (i, arg)
+ i = i + 1
+
+if __name__ == "__main__":
+ dbus.mainloop.glib.DBusGMainLoop (set_as_default = True)
+ loop = gobject.MainLoop ()
+ bus = IBusServer ()
+ print "IBUS_ADDRESS=\"%s\"" % bus.get_address ()
+ try:
+ loop.run ()
+ except KeyboardInterrupt, e:
+ print "daemon exits"
+ sys.exit ()
+
diff --git a/ibus/interface.py b/ibus/interface.py
new file mode 100644
index 0000000..52a7028
--- /dev/null
+++ b/ibus/interface.py
@@ -0,0 +1,124 @@
+import dbus.service
+from common import \
+ IBUS_NAME, \
+ IBUS_IFACE, \
+ IBUS_PATH, \
+ IBUS_ENGINE_IFACE, \
+ IBUS_ENGINE_FACTORY_IFACE
+
+class IIBus (dbus.service.Object):
+ # define method decorator.
+ method = lambda **args: \
+ dbus.service.method (dbus_interface=IBUS_IFACE, \
+ connection_keyword="dbusconn", \
+ **args)
+
+ # define async method decorator.
+ async_method = lambda **args: \
+ dbus.service.method (dbus_interface=IBUS_IFACE, \
+ connection_keyword="dbusconn", \
+ async_callbacks=("reply_cb", "error_cb"), \
+ **args)
+
+ @method (out_signature="s")
+ def GetIBusAddress (self, dbusconn): pass
+
+ @method (in_signature="s")
+ def RegisterClient (self, client_name, dbusconn): pass
+
+ @method ()
+ def UnregisterClient (self, dbusconn): pass
+
+ @method (in_signature="ao")
+ def RegisterFactories (self, object_paths, dbusconn): pass
+
+ @method (in_signature="ao")
+ def UnregisterFactories (self, object_paths, dbusconn): pass
+
+ @async_method (in_signature="ubu", out_signature="b")
+ def ProcessKeyEvent (self, keyval, is_press, state, dbusconn, reply_cb, error_cb): pass
+
+ @method (in_signature="iiii")
+ def SetCursorLocation (self, x, y, w, h, dbusconn): pass
+
+ @method ()
+ def FocusIn (self, dbusconn): pass
+
+ @method ()
+ def FocusOut (self, dbusconn): pass
+
+ @method ()
+ def Reset (self, dbusconn): pass
+
+ @method (out_signature="b")
+ def IsEnabled (self, dbusconn): pass
+
+class IEngineFactory (dbus.service.Object):
+ # define method decorator.
+ method = lambda **args: \
+ dbus.service.method (dbus_interface=IBUS_ENGINE_FACTORY_IFACE, \
+ **args)
+
+ # define async method decorator.
+ async_method = lambda **args: \
+ dbus.service.method (dbus_interface=IBUS_ENGINE_FACTORY_IFACE, \
+ async_callbacks=("reply_cb", "error_cb"), \
+ **args)
+ # Return a array. [name, language, icon_path, authors, credits]
+ @method (out_signature="as")
+ def GetInfo (self): pass
+
+ # Factory should allocate all resources in this method
+ @method ()
+ def Initialize (self): pass
+
+ # Factory should free all allocated resources in this method
+ @method ()
+ def Uninitialize (self): pass
+
+ # Create an input context and return the id of the context.
+ # If failed, it will return "" or None.
+ @method (out_signature="o")
+ def CreateEngine (self): pass
+
+class IEngine (dbus.service.Object):
+ # define method decorator.
+ method = lambda **args: \
+ dbus.service.method (dbus_interface=IBUS_ENGINE_IFACE, \
+ **args)
+
+ # define signal decorator.
+ signal = lambda **args: \
+ dbus.service.signal (dbus_interface=IBUS_ENGINE_IFACE, \
+ **args)
+
+ # define async method decorator.
+ async_method = lambda **args: \
+ dbus.service.method (dbus_interface=IBUS_ENGINE_IFACE, \
+ async_callbacks=("reply_cb", "error_cb"), \
+ **args)
+
+ @method (in_signature="ubu", out_signature="b")
+ def ProcessKeyEvent (self, keyval, is_press, state):
+ pass
+
+ @method (in_signature="iiii")
+ def SetCursorLocation (self, x, y, w, h): pass
+
+ @method ()
+ def FocusIn (self): pass
+
+ @method ()
+ def FocusOut (self): pass
+
+ @method ()
+ def Reset (self): pass
+
+ @method (in_signature="b")
+ def SetEnable (self, enable): pass
+
+ @method ()
+ def Destroy (self): pass
+
+ @signal ()
+ def CommitString (self, text): pass
diff --git a/ibus/keysyms.py b/ibus/keysyms.py
new file mode 100644
index 0000000..e4678c2
--- /dev/null
+++ b/ibus/keysyms.py
@@ -0,0 +1,1521 @@
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# pygtk - Python bindings for the GTK toolkit.
+# Copyright (C) 1998-2003 James Henstridge
+#
+# gtk/keysyms.py: list of keysyms.
+#
+# 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.1 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
+
+SHIFT_MASK = 1 << 0
+LOCK_MASK = 1 << 1
+CONTROL_MASK = 1 << 2
+MOD1_MASK = 1 << 3
+MOD2_MASK = 1 << 4
+MOD3_MASK = 1 << 5
+MOD4_MASK = 1 << 6
+MOD5_MASK = 1 << 7
+BUTTON1_MASK = 1 << 8
+BUTTON2_MASK = 1 << 9
+BUTTON3_MASK = 1 << 10
+BUTTON4_MASK = 1 << 11
+BUTTON5_MASK = 1 << 12
+
+SUPER_MASK = 1 << 26
+HYPER_MASK = 1 << 27
+META_MASK = 1 << 28
+
+RELEASE_MASK = 1 << 30
+
+MODIFIER_MASK = 0x5c001fff
+
+VoidSymbol = 0xFFFFFF
+BackSpace = 0xFF08
+Tab = 0xFF09
+Linefeed = 0xFF0A
+Clear = 0xFF0B
+Return = 0xFF0D
+Pause = 0xFF13
+Scroll_Lock = 0xFF14
+Sys_Req = 0xFF15
+Escape = 0xFF1B
+Delete = 0xFFFF
+Multi_key = 0xFF20
+Codeinput = 0xFF37
+SingleCandidate = 0xFF3C
+MultipleCandidate = 0xFF3D
+PreviousCandidate = 0xFF3E
+Kanji = 0xFF21
+Muhenkan = 0xFF22
+Henkan_Mode = 0xFF23
+Henkan = 0xFF23
+Romaji = 0xFF24
+Hiragana = 0xFF25
+Katakana = 0xFF26
+Hiragana_Katakana = 0xFF27
+Zenkaku = 0xFF28
+Hankaku = 0xFF29
+Zenkaku_Hankaku = 0xFF2A
+Touroku = 0xFF2B
+Massyo = 0xFF2C
+Kana_Lock = 0xFF2D
+Kana_Shift = 0xFF2E
+Eisu_Shift = 0xFF2F
+Eisu_toggle = 0xFF30
+Kanji_Bangou = 0xFF37
+Zen_Koho = 0xFF3D
+Mae_Koho = 0xFF3E
+Home = 0xFF50
+Left = 0xFF51
+Up = 0xFF52
+Right = 0xFF53
+Down = 0xFF54
+Prior = 0xFF55
+Page_Up = 0xFF55
+Next = 0xFF56
+Page_Down = 0xFF56
+End = 0xFF57
+Begin = 0xFF58
+Select = 0xFF60
+Print = 0xFF61
+Execute = 0xFF62
+Insert = 0xFF63
+Undo = 0xFF65
+Redo = 0xFF66
+Menu = 0xFF67
+Find = 0xFF68
+Cancel = 0xFF69
+Help = 0xFF6A
+Break = 0xFF6B
+Mode_switch = 0xFF7E
+script_switch = 0xFF7E
+Num_Lock = 0xFF7F
+KP_Space = 0xFF80
+KP_Tab = 0xFF89
+KP_Enter = 0xFF8D
+KP_F1 = 0xFF91
+KP_F2 = 0xFF92
+KP_F3 = 0xFF93
+KP_F4 = 0xFF94
+KP_Home = 0xFF95
+KP_Left = 0xFF96
+KP_Up = 0xFF97
+KP_Right = 0xFF98
+KP_Down = 0xFF99
+KP_Prior = 0xFF9A
+KP_Page_Up = 0xFF9A
+KP_Next = 0xFF9B
+KP_Page_Down = 0xFF9B
+KP_End = 0xFF9C
+KP_Begin = 0xFF9D
+KP_Insert = 0xFF9E
+KP_Delete = 0xFF9F
+KP_Equal = 0xFFBD
+KP_Multiply = 0xFFAA
+KP_Add = 0xFFAB
+KP_Separator = 0xFFAC
+KP_Subtract = 0xFFAD
+KP_Decimal = 0xFFAE
+KP_Divide = 0xFFAF
+KP_0 = 0xFFB0
+KP_1 = 0xFFB1
+KP_2 = 0xFFB2
+KP_3 = 0xFFB3
+KP_4 = 0xFFB4
+KP_5 = 0xFFB5
+KP_6 = 0xFFB6
+KP_7 = 0xFFB7
+KP_8 = 0xFFB8
+KP_9 = 0xFFB9
+F1 = 0xFFBE
+F2 = 0xFFBF
+F3 = 0xFFC0
+F4 = 0xFFC1
+F5 = 0xFFC2
+F6 = 0xFFC3
+F7 = 0xFFC4
+F8 = 0xFFC5
+F9 = 0xFFC6
+F10 = 0xFFC7
+F11 = 0xFFC8
+L1 = 0xFFC8
+F12 = 0xFFC9
+L2 = 0xFFC9
+F13 = 0xFFCA
+L3 = 0xFFCA
+F14 = 0xFFCB
+L4 = 0xFFCB
+F15 = 0xFFCC
+L5 = 0xFFCC
+F16 = 0xFFCD
+L6 = 0xFFCD
+F17 = 0xFFCE
+L7 = 0xFFCE
+F18 = 0xFFCF
+L8 = 0xFFCF
+F19 = 0xFFD0
+L9 = 0xFFD0
+F20 = 0xFFD1
+L10 = 0xFFD1
+F21 = 0xFFD2
+R1 = 0xFFD2
+F22 = 0xFFD3
+R2 = 0xFFD3
+F23 = 0xFFD4
+R3 = 0xFFD4
+F24 = 0xFFD5
+R4 = 0xFFD5
+F25 = 0xFFD6
+R5 = 0xFFD6
+F26 = 0xFFD7
+R6 = 0xFFD7
+F27 = 0xFFD8
+R7 = 0xFFD8
+F28 = 0xFFD9
+R8 = 0xFFD9
+F29 = 0xFFDA
+R9 = 0xFFDA
+F30 = 0xFFDB
+R10 = 0xFFDB
+F31 = 0xFFDC
+R11 = 0xFFDC
+F32 = 0xFFDD
+R12 = 0xFFDD
+F33 = 0xFFDE
+R13 = 0xFFDE
+F34 = 0xFFDF
+R14 = 0xFFDF
+F35 = 0xFFE0
+R15 = 0xFFE0
+Shift_L = 0xFFE1
+Shift_R = 0xFFE2
+Control_L = 0xFFE3
+Control_R = 0xFFE4
+Caps_Lock = 0xFFE5
+Shift_Lock = 0xFFE6
+Meta_L = 0xFFE7
+Meta_R = 0xFFE8
+Alt_L = 0xFFE9
+Alt_R = 0xFFEA
+Super_L = 0xFFEB
+Super_R = 0xFFEC
+Hyper_L = 0xFFED
+Hyper_R = 0xFFEE
+ISO_Lock = 0xFE01
+ISO_Level2_Latch = 0xFE02
+ISO_Level3_Shift = 0xFE03
+ISO_Level3_Latch = 0xFE04
+ISO_Level3_Lock = 0xFE05
+ISO_Group_Shift = 0xFF7E
+ISO_Group_Latch = 0xFE06
+ISO_Group_Lock = 0xFE07
+ISO_Next_Group = 0xFE08
+ISO_Next_Group_Lock = 0xFE09
+ISO_Prev_Group = 0xFE0A
+ISO_Prev_Group_Lock = 0xFE0B
+ISO_First_Group = 0xFE0C
+ISO_First_Group_Lock = 0xFE0D
+ISO_Last_Group = 0xFE0E
+ISO_Last_Group_Lock = 0xFE0F
+ISO_Left_Tab = 0xFE20
+ISO_Move_Line_Up = 0xFE21
+ISO_Move_Line_Down = 0xFE22
+ISO_Partial_Line_Up = 0xFE23
+ISO_Partial_Line_Down = 0xFE24
+ISO_Partial_Space_Left = 0xFE25
+ISO_Partial_Space_Right = 0xFE26
+ISO_Set_Margin_Left = 0xFE27
+ISO_Set_Margin_Right = 0xFE28
+ISO_Release_Margin_Left = 0xFE29
+ISO_Release_Margin_Right = 0xFE2A
+ISO_Release_Both_Margins = 0xFE2B
+ISO_Fast_Cursor_Left = 0xFE2C
+ISO_Fast_Cursor_Right = 0xFE2D
+ISO_Fast_Cursor_Up = 0xFE2E
+ISO_Fast_Cursor_Down = 0xFE2F
+ISO_Continuous_Underline = 0xFE30
+ISO_Discontinuous_Underline = 0xFE31
+ISO_Emphasize = 0xFE32
+ISO_Center_Object = 0xFE33
+ISO_Enter = 0xFE34
+dead_grave = 0xFE50
+dead_acute = 0xFE51
+dead_circumflex = 0xFE52
+dead_tilde = 0xFE53
+dead_macron = 0xFE54
+dead_breve = 0xFE55
+dead_abovedot = 0xFE56
+dead_diaeresis = 0xFE57
+dead_abovering = 0xFE58
+dead_doubleacute = 0xFE59
+dead_caron = 0xFE5A
+dead_cedilla = 0xFE5B
+dead_ogonek = 0xFE5C
+dead_iota = 0xFE5D
+dead_voiced_sound = 0xFE5E
+dead_semivoiced_sound = 0xFE5F
+dead_belowdot = 0xFE60
+First_Virtual_Screen = 0xFED0
+Prev_Virtual_Screen = 0xFED1
+Next_Virtual_Screen = 0xFED2
+Last_Virtual_Screen = 0xFED4
+Terminate_Server = 0xFED5
+AccessX_Enable = 0xFE70
+AccessX_Feedback_Enable = 0xFE71
+RepeatKeys_Enable = 0xFE72
+SlowKeys_Enable = 0xFE73
+BounceKeys_Enable = 0xFE74
+StickyKeys_Enable = 0xFE75
+MouseKeys_Enable = 0xFE76
+MouseKeys_Accel_Enable = 0xFE77
+Overlay1_Enable = 0xFE78
+Overlay2_Enable = 0xFE79
+AudibleBell_Enable = 0xFE7A
+Pointer_Left = 0xFEE0
+Pointer_Right = 0xFEE1
+Pointer_Up = 0xFEE2
+Pointer_Down = 0xFEE3
+Pointer_UpLeft = 0xFEE4
+Pointer_UpRight = 0xFEE5
+Pointer_DownLeft = 0xFEE6
+Pointer_DownRight = 0xFEE7
+Pointer_Button_Dflt = 0xFEE8
+Pointer_Button1 = 0xFEE9
+Pointer_Button2 = 0xFEEA
+Pointer_Button3 = 0xFEEB
+Pointer_Button4 = 0xFEEC
+Pointer_Button5 = 0xFEED
+Pointer_DblClick_Dflt = 0xFEEE
+Pointer_DblClick1 = 0xFEEF
+Pointer_DblClick2 = 0xFEF0
+Pointer_DblClick3 = 0xFEF1
+Pointer_DblClick4 = 0xFEF2
+Pointer_DblClick5 = 0xFEF3
+Pointer_Drag_Dflt = 0xFEF4
+Pointer_Drag1 = 0xFEF5
+Pointer_Drag2 = 0xFEF6
+Pointer_Drag3 = 0xFEF7
+Pointer_Drag4 = 0xFEF8
+Pointer_Drag5 = 0xFEFD
+Pointer_EnableKeys = 0xFEF9
+Pointer_Accelerate = 0xFEFA
+Pointer_DfltBtnNext = 0xFEFB
+Pointer_DfltBtnPrev = 0xFEFC
+_3270_Duplicate = 0xFD01
+_3270_FieldMark = 0xFD02
+_3270_Right2 = 0xFD03
+_3270_Left2 = 0xFD04
+_3270_BackTab = 0xFD05
+_3270_EraseEOF = 0xFD06
+_3270_EraseInput = 0xFD07
+_3270_Reset = 0xFD08
+_3270_Quit = 0xFD09
+_3270_PA1 = 0xFD0A
+_3270_PA2 = 0xFD0B
+_3270_PA3 = 0xFD0C
+_3270_Test = 0xFD0D
+_3270_Attn = 0xFD0E
+_3270_CursorBlink = 0xFD0F
+_3270_AltCursor = 0xFD10
+_3270_KeyClick = 0xFD11
+_3270_Jump = 0xFD12
+_3270_Ident = 0xFD13
+_3270_Rule = 0xFD14
+_3270_Copy = 0xFD15
+_3270_Play = 0xFD16
+_3270_Setup = 0xFD17
+_3270_Record = 0xFD18
+_3270_ChangeScreen = 0xFD19
+_3270_DeleteWord = 0xFD1A
+_3270_ExSelect = 0xFD1B
+_3270_CursorSelect = 0xFD1C
+_3270_PrintScreen = 0xFD1D
+_3270_Enter = 0xFD1E
+space = 0x020
+exclam = 0x021
+quotedbl = 0x022
+numbersign = 0x023
+dollar = 0x024
+percent = 0x025
+ampersand = 0x026
+apostrophe = 0x027
+quoteright = 0x027
+parenleft = 0x028
+parenright = 0x029
+asterisk = 0x02a
+plus = 0x02b
+comma = 0x02c
+minus = 0x02d
+period = 0x02e
+slash = 0x02f
+_0 = 0x030
+_1 = 0x031
+_2 = 0x032
+_3 = 0x033
+_4 = 0x034
+_5 = 0x035
+_6 = 0x036
+_7 = 0x037
+_8 = 0x038
+_9 = 0x039
+colon = 0x03a
+semicolon = 0x03b
+less = 0x03c
+equal = 0x03d
+greater = 0x03e
+question = 0x03f
+at = 0x040
+A = 0x041
+B = 0x042
+C = 0x043
+D = 0x044
+E = 0x045
+F = 0x046
+G = 0x047
+H = 0x048
+I = 0x049
+J = 0x04a
+K = 0x04b
+L = 0x04c
+M = 0x04d
+N = 0x04e
+O = 0x04f
+P = 0x050
+Q = 0x051
+R = 0x052
+S = 0x053
+T = 0x054
+U = 0x055
+V = 0x056
+W = 0x057
+X = 0x058
+Y = 0x059
+Z = 0x05a
+bracketleft = 0x05b
+backslash = 0x05c
+bracketright = 0x05d
+asciicircum = 0x05e
+underscore = 0x05f
+grave = 0x060
+quoteleft = 0x060
+a = 0x061
+b = 0x062
+c = 0x063
+d = 0x064
+e = 0x065
+f = 0x066
+g = 0x067
+h = 0x068
+i = 0x069
+j = 0x06a
+k = 0x06b
+l = 0x06c
+m = 0x06d
+n = 0x06e
+o = 0x06f
+p = 0x070
+q = 0x071
+r = 0x072
+s = 0x073
+t = 0x074
+u = 0x075
+v = 0x076
+w = 0x077
+x = 0x078
+y = 0x079
+z = 0x07a
+braceleft = 0x07b
+bar = 0x07c
+braceright = 0x07d
+asciitilde = 0x07e
+nobreakspace = 0x0a0
+exclamdown = 0x0a1
+cent = 0x0a2
+sterling = 0x0a3
+currency = 0x0a4
+yen = 0x0a5
+brokenbar = 0x0a6
+section = 0x0a7
+diaeresis = 0x0a8
+copyright = 0x0a9
+ordfeminine = 0x0aa
+guillemotleft = 0x0ab
+notsign = 0x0ac
+hyphen = 0x0ad
+registered = 0x0ae
+macron = 0x0af
+degree = 0x0b0
+plusminus = 0x0b1
+twosuperior = 0x0b2
+threesuperior = 0x0b3
+acute = 0x0b4
+mu = 0x0b5
+paragraph = 0x0b6
+periodcentered = 0x0b7
+cedilla = 0x0b8
+onesuperior = 0x0b9
+masculine = 0x0ba
+guillemotright = 0x0bb
+onequarter = 0x0bc
+onehalf = 0x0bd
+threequarters = 0x0be
+questiondown = 0x0bf
+Agrave = 0x0c0
+Aacute = 0x0c1
+Acircumflex = 0x0c2
+Atilde = 0x0c3
+Adiaeresis = 0x0c4
+Aring = 0x0c5
+AE = 0x0c6
+Ccedilla = 0x0c7
+Egrave = 0x0c8
+Eacute = 0x0c9
+Ecircumflex = 0x0ca
+Ediaeresis = 0x0cb
+Igrave = 0x0cc
+Iacute = 0x0cd
+Icircumflex = 0x0ce
+Idiaeresis = 0x0cf
+ETH = 0x0d0
+Eth = 0x0d0
+Ntilde = 0x0d1
+Ograve = 0x0d2
+Oacute = 0x0d3
+Ocircumflex = 0x0d4
+Otilde = 0x0d5
+Odiaeresis = 0x0d6
+multiply = 0x0d7
+Ooblique = 0x0d8
+Ugrave = 0x0d9
+Uacute = 0x0da
+Ucircumflex = 0x0db
+Udiaeresis = 0x0dc
+Yacute = 0x0dd
+THORN = 0x0de
+Thorn = 0x0de
+ssharp = 0x0df
+agrave = 0x0e0
+aacute = 0x0e1
+acircumflex = 0x0e2
+atilde = 0x0e3
+adiaeresis = 0x0e4
+aring = 0x0e5
+ae = 0x0e6
+ccedilla = 0x0e7
+egrave = 0x0e8
+eacute = 0x0e9
+ecircumflex = 0x0ea
+ediaeresis = 0x0eb
+igrave = 0x0ec
+iacute = 0x0ed
+icircumflex = 0x0ee
+idiaeresis = 0x0ef
+eth = 0x0f0
+ntilde = 0x0f1
+ograve = 0x0f2
+oacute = 0x0f3
+ocircumflex = 0x0f4
+otilde = 0x0f5
+odiaeresis = 0x0f6
+division = 0x0f7
+oslash = 0x0f8
+ugrave = 0x0f9
+uacute = 0x0fa
+ucircumflex = 0x0fb
+udiaeresis = 0x0fc
+yacute = 0x0fd
+thorn = 0x0fe
+ydiaeresis = 0x0ff
+Aogonek = 0x1a1
+breve = 0x1a2
+Lstroke = 0x1a3
+Lcaron = 0x1a5
+Sacute = 0x1a6
+Scaron = 0x1a9
+Scedilla = 0x1aa
+Tcaron = 0x1ab
+Zacute = 0x1ac
+Zcaron = 0x1ae
+Zabovedot = 0x1af
+aogonek = 0x1b1
+ogonek = 0x1b2
+lstroke = 0x1b3
+lcaron = 0x1b5
+sacute = 0x1b6
+caron = 0x1b7
+scaron = 0x1b9
+scedilla = 0x1ba
+tcaron = 0x1bb
+zacute = 0x1bc
+doubleacute = 0x1bd
+zcaron = 0x1be
+zabovedot = 0x1bf
+Racute = 0x1c0
+Abreve = 0x1c3
+Lacute = 0x1c5
+Cacute = 0x1c6
+Ccaron = 0x1c8
+Eogonek = 0x1ca
+Ecaron = 0x1cc
+Dcaron = 0x1cf
+Dstroke = 0x1d0
+Nacute = 0x1d1
+Ncaron = 0x1d2
+Odoubleacute = 0x1d5
+Rcaron = 0x1d8
+Uring = 0x1d9
+Udoubleacute = 0x1db
+Tcedilla = 0x1de
+racute = 0x1e0
+abreve = 0x1e3
+lacute = 0x1e5
+cacute = 0x1e6
+ccaron = 0x1e8
+eogonek = 0x1ea
+ecaron = 0x1ec
+dcaron = 0x1ef
+dstroke = 0x1f0
+nacute = 0x1f1
+ncaron = 0x1f2
+odoubleacute = 0x1f5
+udoubleacute = 0x1fb
+rcaron = 0x1f8
+uring = 0x1f9
+tcedilla = 0x1fe
+abovedot = 0x1ff
+Hstroke = 0x2a1
+Hcircumflex = 0x2a6
+Iabovedot = 0x2a9
+Gbreve = 0x2ab
+Jcircumflex = 0x2ac
+hstroke = 0x2b1
+hcircumflex = 0x2b6
+idotless = 0x2b9
+gbreve = 0x2bb
+jcircumflex = 0x2bc
+Cabovedot = 0x2c5
+Ccircumflex = 0x2c6
+Gabovedot = 0x2d5
+Gcircumflex = 0x2d8
+Ubreve = 0x2dd
+Scircumflex = 0x2de
+cabovedot = 0x2e5
+ccircumflex = 0x2e6
+gabovedot = 0x2f5
+gcircumflex = 0x2f8
+ubreve = 0x2fd
+scircumflex = 0x2fe
+kra = 0x3a2
+kappa = 0x3a2
+Rcedilla = 0x3a3
+Itilde = 0x3a5
+Lcedilla = 0x3a6
+Emacron = 0x3aa
+Gcedilla = 0x3ab
+Tslash = 0x3ac
+rcedilla = 0x3b3
+itilde = 0x3b5
+lcedilla = 0x3b6
+emacron = 0x3ba
+gcedilla = 0x3bb
+tslash = 0x3bc
+ENG = 0x3bd
+eng = 0x3bf
+Amacron = 0x3c0
+Iogonek = 0x3c7
+Eabovedot = 0x3cc
+Imacron = 0x3cf
+Ncedilla = 0x3d1
+Omacron = 0x3d2
+Kcedilla = 0x3d3
+Uogonek = 0x3d9
+Utilde = 0x3dd
+Umacron = 0x3de
+amacron = 0x3e0
+iogonek = 0x3e7
+eabovedot = 0x3ec
+imacron = 0x3ef
+ncedilla = 0x3f1
+omacron = 0x3f2
+kcedilla = 0x3f3
+uogonek = 0x3f9
+utilde = 0x3fd
+umacron = 0x3fe
+OE = 0x13bc
+oe = 0x13bd
+Ydiaeresis = 0x13be
+overline = 0x47e
+kana_fullstop = 0x4a1
+kana_openingbracket = 0x4a2
+kana_closingbracket = 0x4a3
+kana_comma = 0x4a4
+kana_conjunctive = 0x4a5
+kana_middledot = 0x4a5
+kana_WO = 0x4a6
+kana_a = 0x4a7
+kana_i = 0x4a8
+kana_u = 0x4a9
+kana_e = 0x4aa
+kana_o = 0x4ab
+kana_ya = 0x4ac
+kana_yu = 0x4ad
+kana_yo = 0x4ae
+kana_tsu = 0x4af
+kana_tu = 0x4af
+prolongedsound = 0x4b0
+kana_A = 0x4b1
+kana_I = 0x4b2
+kana_U = 0x4b3
+kana_E = 0x4b4
+kana_O = 0x4b5
+kana_KA = 0x4b6
+kana_KI = 0x4b7
+kana_KU = 0x4b8
+kana_KE = 0x4b9
+kana_KO = 0x4ba
+kana_SA = 0x4bb
+kana_SHI = 0x4bc
+kana_SU = 0x4bd
+kana_SE = 0x4be
+kana_SO = 0x4bf
+kana_TA = 0x4c0
+kana_CHI = 0x4c1
+kana_TI = 0x4c1
+kana_TSU = 0x4c2
+kana_TU = 0x4c2
+kana_TE = 0x4c3
+kana_TO = 0x4c4
+kana_NA = 0x4c5
+kana_NI = 0x4c6
+kana_NU = 0x4c7
+kana_NE = 0x4c8
+kana_NO = 0x4c9
+kana_HA = 0x4ca
+kana_HI = 0x4cb
+kana_FU = 0x4cc
+kana_HU = 0x4cc
+kana_HE = 0x4cd
+kana_HO = 0x4ce
+kana_MA = 0x4cf
+kana_MI = 0x4d0
+kana_MU = 0x4d1
+kana_ME = 0x4d2
+kana_MO = 0x4d3
+kana_YA = 0x4d4
+kana_YU = 0x4d5
+kana_YO = 0x4d6
+kana_RA = 0x4d7
+kana_RI = 0x4d8
+kana_RU = 0x4d9
+kana_RE = 0x4da
+kana_RO = 0x4db
+kana_WA = 0x4dc
+kana_N = 0x4dd
+voicedsound = 0x4de
+semivoicedsound = 0x4df
+kana_switch = 0xFF7E
+Arabic_comma = 0x5ac
+Arabic_semicolon = 0x5bb
+Arabic_question_mark = 0x5bf
+Arabic_hamza = 0x5c1
+Arabic_maddaonalef = 0x5c2
+Arabic_hamzaonalef = 0x5c3
+Arabic_hamzaonwaw = 0x5c4
+Arabic_hamzaunderalef = 0x5c5
+Arabic_hamzaonyeh = 0x5c6
+Arabic_alef = 0x5c7
+Arabic_beh = 0x5c8
+Arabic_tehmarbuta = 0x5c9
+Arabic_teh = 0x5ca
+Arabic_theh = 0x5cb
+Arabic_jeem = 0x5cc
+Arabic_hah = 0x5cd
+Arabic_khah = 0x5ce
+Arabic_dal = 0x5cf
+Arabic_thal = 0x5d0
+Arabic_ra = 0x5d1
+Arabic_zain = 0x5d2
+Arabic_seen = 0x5d3
+Arabic_sheen = 0x5d4
+Arabic_sad = 0x5d5
+Arabic_dad = 0x5d6
+Arabic_tah = 0x5d7
+Arabic_zah = 0x5d8
+Arabic_ain = 0x5d9
+Arabic_ghain = 0x5da
+Arabic_tatweel = 0x5e0
+Arabic_feh = 0x5e1
+Arabic_qaf = 0x5e2
+Arabic_kaf = 0x5e3
+Arabic_lam = 0x5e4
+Arabic_meem = 0x5e5
+Arabic_noon = 0x5e6
+Arabic_ha = 0x5e7
+Arabic_heh = 0x5e7
+Arabic_waw = 0x5e8
+Arabic_alefmaksura = 0x5e9
+Arabic_yeh = 0x5ea
+Arabic_fathatan = 0x5eb
+Arabic_dammatan = 0x5ec
+Arabic_kasratan = 0x5ed
+Arabic_fatha = 0x5ee
+Arabic_damma = 0x5ef
+Arabic_kasra = 0x5f0
+Arabic_shadda = 0x5f1
+Arabic_sukun = 0x5f2
+Arabic_switch = 0xFF7E
+Serbian_dje = 0x6a1
+Macedonia_gje = 0x6a2
+Cyrillic_io = 0x6a3
+Ukrainian_ie = 0x6a4
+Ukranian_je = 0x6a4
+Macedonia_dse = 0x6a5
+Ukrainian_i = 0x6a6
+Ukranian_i = 0x6a6
+Ukrainian_yi = 0x6a7
+Ukranian_yi = 0x6a7
+Cyrillic_je = 0x6a8
+Serbian_je = 0x6a8
+Cyrillic_lje = 0x6a9
+Serbian_lje = 0x6a9
+Cyrillic_nje = 0x6aa
+Serbian_nje = 0x6aa
+Serbian_tshe = 0x6ab
+Macedonia_kje = 0x6ac
+Ukrainian_ghe_with_upturn = 0x6ad
+Byelorussian_shortu = 0x6ae
+Cyrillic_dzhe = 0x6af
+Serbian_dze = 0x6af
+numerosign = 0x6b0
+Serbian_DJE = 0x6b1
+Macedonia_GJE = 0x6b2
+Cyrillic_IO = 0x6b3
+Ukrainian_IE = 0x6b4
+Ukranian_JE = 0x6b4
+Macedonia_DSE = 0x6b5
+Ukrainian_I = 0x6b6
+Ukranian_I = 0x6b6
+Ukrainian_YI = 0x6b7
+Ukranian_YI = 0x6b7
+Cyrillic_JE = 0x6b8
+Serbian_JE = 0x6b8
+Cyrillic_LJE = 0x6b9
+Serbian_LJE = 0x6b9
+Cyrillic_NJE = 0x6ba
+Serbian_NJE = 0x6ba
+Serbian_TSHE = 0x6bb
+Macedonia_KJE = 0x6bc
+Ukrainian_GHE_WITH_UPTURN = 0x6bd
+Byelorussian_SHORTU = 0x6be
+Cyrillic_DZHE = 0x6bf
+Serbian_DZE = 0x6bf
+Cyrillic_yu = 0x6c0
+Cyrillic_a = 0x6c1
+Cyrillic_be = 0x6c2
+Cyrillic_tse = 0x6c3
+Cyrillic_de = 0x6c4
+Cyrillic_ie = 0x6c5
+Cyrillic_ef = 0x6c6
+Cyrillic_ghe = 0x6c7
+Cyrillic_ha = 0x6c8
+Cyrillic_i = 0x6c9
+Cyrillic_shorti = 0x6ca
+Cyrillic_ka = 0x6cb
+Cyrillic_el = 0x6cc
+Cyrillic_em = 0x6cd
+Cyrillic_en = 0x6ce
+Cyrillic_o = 0x6cf
+Cyrillic_pe = 0x6d0
+Cyrillic_ya = 0x6d1
+Cyrillic_er = 0x6d2
+Cyrillic_es = 0x6d3
+Cyrillic_te = 0x6d4
+Cyrillic_u = 0x6d5
+Cyrillic_zhe = 0x6d6
+Cyrillic_ve = 0x6d7
+Cyrillic_softsign = 0x6d8
+Cyrillic_yeru = 0x6d9
+Cyrillic_ze = 0x6da
+Cyrillic_sha = 0x6db
+Cyrillic_e = 0x6dc
+Cyrillic_shcha = 0x6dd
+Cyrillic_che = 0x6de
+Cyrillic_hardsign = 0x6df
+Cyrillic_YU = 0x6e0
+Cyrillic_A = 0x6e1
+Cyrillic_BE = 0x6e2
+Cyrillic_TSE = 0x6e3
+Cyrillic_DE = 0x6e4
+Cyrillic_IE = 0x6e5
+Cyrillic_EF = 0x6e6
+Cyrillic_GHE = 0x6e7
+Cyrillic_HA = 0x6e8
+Cyrillic_I = 0x6e9
+Cyrillic_SHORTI = 0x6ea
+Cyrillic_KA = 0x6eb
+Cyrillic_EL = 0x6ec
+Cyrillic_EM = 0x6ed
+Cyrillic_EN = 0x6ee
+Cyrillic_O = 0x6ef
+Cyrillic_PE = 0x6f0
+Cyrillic_YA = 0x6f1
+Cyrillic_ER = 0x6f2
+Cyrillic_ES = 0x6f3
+Cyrillic_TE = 0x6f4
+Cyrillic_U = 0x6f5
+Cyrillic_ZHE = 0x6f6
+Cyrillic_VE = 0x6f7
+Cyrillic_SOFTSIGN = 0x6f8
+Cyrillic_YERU = 0x6f9
+Cyrillic_ZE = 0x6fa
+Cyrillic_SHA = 0x6fb
+Cyrillic_E = 0x6fc
+Cyrillic_SHCHA = 0x6fd
+Cyrillic_CHE = 0x6fe
+Cyrillic_HARDSIGN = 0x6ff
+Greek_ALPHAaccent = 0x7a1
+Greek_EPSILONaccent = 0x7a2
+Greek_ETAaccent = 0x7a3
+Greek_IOTAaccent = 0x7a4
+Greek_IOTAdiaeresis = 0x7a5
+Greek_OMICRONaccent = 0x7a7
+Greek_UPSILONaccent = 0x7a8
+Greek_UPSILONdieresis = 0x7a9
+Greek_OMEGAaccent = 0x7ab
+Greek_accentdieresis = 0x7ae
+Greek_horizbar = 0x7af
+Greek_alphaaccent = 0x7b1
+Greek_epsilonaccent = 0x7b2
+Greek_etaaccent = 0x7b3
+Greek_iotaaccent = 0x7b4
+Greek_iotadieresis = 0x7b5
+Greek_iotaaccentdieresis = 0x7b6
+Greek_omicronaccent = 0x7b7
+Greek_upsilonaccent = 0x7b8
+Greek_upsilondieresis = 0x7b9
+Greek_upsilonaccentdieresis = 0x7ba
+Greek_omegaaccent = 0x7bb
+Greek_ALPHA = 0x7c1
+Greek_BETA = 0x7c2
+Greek_GAMMA = 0x7c3
+Greek_DELTA = 0x7c4
+Greek_EPSILON = 0x7c5
+Greek_ZETA = 0x7c6
+Greek_ETA = 0x7c7
+Greek_THETA = 0x7c8
+Greek_IOTA = 0x7c9
+Greek_KAPPA = 0x7ca
+Greek_LAMDA = 0x7cb
+Greek_LAMBDA = 0x7cb
+Greek_MU = 0x7cc
+Greek_NU = 0x7cd
+Greek_XI = 0x7ce
+Greek_OMICRON = 0x7cf
+Greek_PI = 0x7d0
+Greek_RHO = 0x7d1
+Greek_SIGMA = 0x7d2
+Greek_TAU = 0x7d4
+Greek_UPSILON = 0x7d5
+Greek_PHI = 0x7d6
+Greek_CHI = 0x7d7
+Greek_PSI = 0x7d8
+Greek_OMEGA = 0x7d9
+Greek_alpha = 0x7e1
+Greek_beta = 0x7e2
+Greek_gamma = 0x7e3
+Greek_delta = 0x7e4
+Greek_epsilon = 0x7e5
+Greek_zeta = 0x7e6
+Greek_eta = 0x7e7
+Greek_theta = 0x7e8
+Greek_iota = 0x7e9
+Greek_kappa = 0x7ea
+Greek_lamda = 0x7eb
+Greek_lambda = 0x7eb
+Greek_mu = 0x7ec
+Greek_nu = 0x7ed
+Greek_xi = 0x7ee
+Greek_omicron = 0x7ef
+Greek_pi = 0x7f0
+Greek_rho = 0x7f1
+Greek_sigma = 0x7f2
+Greek_finalsmallsigma = 0x7f3
+Greek_tau = 0x7f4
+Greek_upsilon = 0x7f5
+Greek_phi = 0x7f6
+Greek_chi = 0x7f7
+Greek_psi = 0x7f8
+Greek_omega = 0x7f9
+Greek_switch = 0xFF7E
+leftradical = 0x8a1
+topleftradical = 0x8a2
+horizconnector = 0x8a3
+topintegral = 0x8a4
+botintegral = 0x8a5
+vertconnector = 0x8a6
+topleftsqbracket = 0x8a7
+botleftsqbracket = 0x8a8
+toprightsqbracket = 0x8a9
+botrightsqbracket = 0x8aa
+topleftparens = 0x8ab
+botleftparens = 0x8ac
+toprightparens = 0x8ad
+botrightparens = 0x8ae
+leftmiddlecurlybrace = 0x8af
+rightmiddlecurlybrace = 0x8b0
+topleftsummation = 0x8b1
+botleftsummation = 0x8b2
+topvertsummationconnector = 0x8b3
+botvertsummationconnector = 0x8b4
+toprightsummation = 0x8b5
+botrightsummation = 0x8b6
+rightmiddlesummation = 0x8b7
+lessthanequal = 0x8bc
+notequal = 0x8bd
+greaterthanequal = 0x8be
+integral = 0x8bf
+therefore = 0x8c0
+variation = 0x8c1
+infinity = 0x8c2
+nabla = 0x8c5
+approximate = 0x8c8
+similarequal = 0x8c9
+ifonlyif = 0x8cd
+implies = 0x8ce
+identical = 0x8cf
+radical = 0x8d6
+includedin = 0x8da
+includes = 0x8db
+intersection = 0x8dc
+union = 0x8dd
+logicaland = 0x8de
+logicalor = 0x8df
+partialderivative = 0x8ef
+function = 0x8f6
+leftarrow = 0x8fb
+uparrow = 0x8fc
+rightarrow = 0x8fd
+downarrow = 0x8fe
+blank = 0x9df
+soliddiamond = 0x9e0
+checkerboard = 0x9e1
+ht = 0x9e2
+ff = 0x9e3
+cr = 0x9e4
+lf = 0x9e5
+nl = 0x9e8
+vt = 0x9e9
+lowrightcorner = 0x9ea
+uprightcorner = 0x9eb
+upleftcorner = 0x9ec
+lowleftcorner = 0x9ed
+crossinglines = 0x9ee
+horizlinescan1 = 0x9ef
+horizlinescan3 = 0x9f0
+horizlinescan5 = 0x9f1
+horizlinescan7 = 0x9f2
+horizlinescan9 = 0x9f3
+leftt = 0x9f4
+rightt = 0x9f5
+bott = 0x9f6
+topt = 0x9f7
+vertbar = 0x9f8
+emspace = 0xaa1
+enspace = 0xaa2
+em3space = 0xaa3
+em4space = 0xaa4
+digitspace = 0xaa5
+punctspace = 0xaa6
+thinspace = 0xaa7
+hairspace = 0xaa8
+emdash = 0xaa9
+endash = 0xaaa
+signifblank = 0xaac
+ellipsis = 0xaae
+doubbaselinedot = 0xaaf
+onethird = 0xab0
+twothirds = 0xab1
+onefifth = 0xab2
+twofifths = 0xab3
+threefifths = 0xab4
+fourfifths = 0xab5
+onesixth = 0xab6
+fivesixths = 0xab7
+careof = 0xab8
+figdash = 0xabb
+leftanglebracket = 0xabc
+decimalpoint = 0xabd
+rightanglebracket = 0xabe
+marker = 0xabf
+oneeighth = 0xac3
+threeeighths = 0xac4
+fiveeighths = 0xac5
+seveneighths = 0xac6
+trademark = 0xac9
+signaturemark = 0xaca
+trademarkincircle = 0xacb
+leftopentriangle = 0xacc
+rightopentriangle = 0xacd
+emopencircle = 0xace
+emopenrectangle = 0xacf
+leftsinglequotemark = 0xad0
+rightsinglequotemark = 0xad1
+leftdoublequotemark = 0xad2
+rightdoublequotemark = 0xad3
+prescription = 0xad4
+minutes = 0xad6
+seconds = 0xad7
+latincross = 0xad9
+hexagram = 0xada
+filledrectbullet = 0xadb
+filledlefttribullet = 0xadc
+filledrighttribullet = 0xadd
+emfilledcircle = 0xade
+emfilledrect = 0xadf
+enopencircbullet = 0xae0
+enopensquarebullet = 0xae1
+openrectbullet = 0xae2
+opentribulletup = 0xae3
+opentribulletdown = 0xae4
+openstar = 0xae5
+enfilledcircbullet = 0xae6
+enfilledsqbullet = 0xae7
+filledtribulletup = 0xae8
+filledtribulletdown = 0xae9
+leftpointer = 0xaea
+rightpointer = 0xaeb
+club = 0xaec
+diamond = 0xaed
+heart = 0xaee
+maltesecross = 0xaf0
+dagger = 0xaf1
+doubledagger = 0xaf2
+checkmark = 0xaf3
+ballotcross = 0xaf4
+musicalsharp = 0xaf5
+musicalflat = 0xaf6
+malesymbol = 0xaf7
+femalesymbol = 0xaf8
+telephone = 0xaf9
+telephonerecorder = 0xafa
+phonographcopyright = 0xafb
+caret = 0xafc
+singlelowquotemark = 0xafd
+doublelowquotemark = 0xafe
+cursor = 0xaff
+leftcaret = 0xba3
+rightcaret = 0xba6
+downcaret = 0xba8
+upcaret = 0xba9
+overbar = 0xbc0
+downtack = 0xbc2
+upshoe = 0xbc3
+downstile = 0xbc4
+underbar = 0xbc6
+jot = 0xbca
+quad = 0xbcc
+uptack = 0xbce
+circle = 0xbcf
+upstile = 0xbd3
+downshoe = 0xbd6
+rightshoe = 0xbd8
+leftshoe = 0xbda
+lefttack = 0xbdc
+righttack = 0xbfc
+hebrew_doublelowline = 0xcdf
+hebrew_aleph = 0xce0
+hebrew_bet = 0xce1
+hebrew_beth = 0xce1
+hebrew_gimel = 0xce2
+hebrew_gimmel = 0xce2
+hebrew_dalet = 0xce3
+hebrew_daleth = 0xce3
+hebrew_he = 0xce4
+hebrew_waw = 0xce5
+hebrew_zain = 0xce6
+hebrew_zayin = 0xce6
+hebrew_chet = 0xce7
+hebrew_het = 0xce7
+hebrew_tet = 0xce8
+hebrew_teth = 0xce8
+hebrew_yod = 0xce9
+hebrew_finalkaph = 0xcea
+hebrew_kaph = 0xceb
+hebrew_lamed = 0xcec
+hebrew_finalmem = 0xced
+hebrew_mem = 0xcee
+hebrew_finalnun = 0xcef
+hebrew_nun = 0xcf0
+hebrew_samech = 0xcf1
+hebrew_samekh = 0xcf1
+hebrew_ayin = 0xcf2
+hebrew_finalpe = 0xcf3
+hebrew_pe = 0xcf4
+hebrew_finalzade = 0xcf5
+hebrew_finalzadi = 0xcf5
+hebrew_zade = 0xcf6
+hebrew_zadi = 0xcf6
+hebrew_qoph = 0xcf7
+hebrew_kuf = 0xcf7
+hebrew_resh = 0xcf8
+hebrew_shin = 0xcf9
+hebrew_taw = 0xcfa
+hebrew_taf = 0xcfa
+Hebrew_switch = 0xFF7E
+Thai_kokai = 0xda1
+Thai_khokhai = 0xda2
+Thai_khokhuat = 0xda3
+Thai_khokhwai = 0xda4
+Thai_khokhon = 0xda5
+Thai_khorakhang = 0xda6
+Thai_ngongu = 0xda7
+Thai_chochan = 0xda8
+Thai_choching = 0xda9
+Thai_chochang = 0xdaa
+Thai_soso = 0xdab
+Thai_chochoe = 0xdac
+Thai_yoying = 0xdad
+Thai_dochada = 0xdae
+Thai_topatak = 0xdaf
+Thai_thothan = 0xdb0
+Thai_thonangmontho = 0xdb1
+Thai_thophuthao = 0xdb2
+Thai_nonen = 0xdb3
+Thai_dodek = 0xdb4
+Thai_totao = 0xdb5
+Thai_thothung = 0xdb6
+Thai_thothahan = 0xdb7
+Thai_thothong = 0xdb8
+Thai_nonu = 0xdb9
+Thai_bobaimai = 0xdba
+Thai_popla = 0xdbb
+Thai_phophung = 0xdbc
+Thai_fofa = 0xdbd
+Thai_phophan = 0xdbe
+Thai_fofan = 0xdbf
+Thai_phosamphao = 0xdc0
+Thai_moma = 0xdc1
+Thai_yoyak = 0xdc2
+Thai_rorua = 0xdc3
+Thai_ru = 0xdc4
+Thai_loling = 0xdc5
+Thai_lu = 0xdc6
+Thai_wowaen = 0xdc7
+Thai_sosala = 0xdc8
+Thai_sorusi = 0xdc9
+Thai_sosua = 0xdca
+Thai_hohip = 0xdcb
+Thai_lochula = 0xdcc
+Thai_oang = 0xdcd
+Thai_honokhuk = 0xdce
+Thai_paiyannoi = 0xdcf
+Thai_saraa = 0xdd0
+Thai_maihanakat = 0xdd1
+Thai_saraaa = 0xdd2
+Thai_saraam = 0xdd3
+Thai_sarai = 0xdd4
+Thai_saraii = 0xdd5
+Thai_saraue = 0xdd6
+Thai_sarauee = 0xdd7
+Thai_sarau = 0xdd8
+Thai_sarauu = 0xdd9
+Thai_phinthu = 0xdda
+Thai_maihanakat_maitho = 0xdde
+Thai_baht = 0xddf
+Thai_sarae = 0xde0
+Thai_saraae = 0xde1
+Thai_sarao = 0xde2
+Thai_saraaimaimuan = 0xde3
+Thai_saraaimaimalai = 0xde4
+Thai_lakkhangyao = 0xde5
+Thai_maiyamok = 0xde6
+Thai_maitaikhu = 0xde7
+Thai_maiek = 0xde8
+Thai_maitho = 0xde9
+Thai_maitri = 0xdea
+Thai_maichattawa = 0xdeb
+Thai_thanthakhat = 0xdec
+Thai_nikhahit = 0xded
+Thai_leksun = 0xdf0
+Thai_leknung = 0xdf1
+Thai_leksong = 0xdf2
+Thai_leksam = 0xdf3
+Thai_leksi = 0xdf4
+Thai_lekha = 0xdf5
+Thai_lekhok = 0xdf6
+Thai_lekchet = 0xdf7
+Thai_lekpaet = 0xdf8
+Thai_lekkao = 0xdf9
+Hangul = 0xff31
+Hangul_Start = 0xff32
+Hangul_End = 0xff33
+Hangul_Hanja = 0xff34
+Hangul_Jamo = 0xff35
+Hangul_Romaja = 0xff36
+Hangul_Codeinput = 0xff37
+Hangul_Jeonja = 0xff38
+Hangul_Banja = 0xff39
+Hangul_PreHanja = 0xff3a
+Hangul_PostHanja = 0xff3b
+Hangul_SingleCandidate = 0xff3c
+Hangul_MultipleCandidate = 0xff3d
+Hangul_PreviousCandidate = 0xff3e
+Hangul_Special = 0xff3f
+Hangul_switch = 0xFF7E
+Hangul_Kiyeog = 0xea1
+Hangul_SsangKiyeog = 0xea2
+Hangul_KiyeogSios = 0xea3
+Hangul_Nieun = 0xea4
+Hangul_NieunJieuj = 0xea5
+Hangul_NieunHieuh = 0xea6
+Hangul_Dikeud = 0xea7
+Hangul_SsangDikeud = 0xea8
+Hangul_Rieul = 0xea9
+Hangul_RieulKiyeog = 0xeaa
+Hangul_RieulMieum = 0xeab
+Hangul_RieulPieub = 0xeac
+Hangul_RieulSios = 0xead
+Hangul_RieulTieut = 0xeae
+Hangul_RieulPhieuf = 0xeaf
+Hangul_RieulHieuh = 0xeb0
+Hangul_Mieum = 0xeb1
+Hangul_Pieub = 0xeb2
+Hangul_SsangPieub = 0xeb3
+Hangul_PieubSios = 0xeb4
+Hangul_Sios = 0xeb5
+Hangul_SsangSios = 0xeb6
+Hangul_Ieung = 0xeb7
+Hangul_Jieuj = 0xeb8
+Hangul_SsangJieuj = 0xeb9
+Hangul_Cieuc = 0xeba
+Hangul_Khieuq = 0xebb
+Hangul_Tieut = 0xebc
+Hangul_Phieuf = 0xebd
+Hangul_Hieuh = 0xebe
+Hangul_A = 0xebf
+Hangul_AE = 0xec0
+Hangul_YA = 0xec1
+Hangul_YAE = 0xec2
+Hangul_EO = 0xec3
+Hangul_E = 0xec4
+Hangul_YEO = 0xec5
+Hangul_YE = 0xec6
+Hangul_O = 0xec7
+Hangul_WA = 0xec8
+Hangul_WAE = 0xec9
+Hangul_OE = 0xeca
+Hangul_YO = 0xecb
+Hangul_U = 0xecc
+Hangul_WEO = 0xecd
+Hangul_WE = 0xece
+Hangul_WI = 0xecf
+Hangul_YU = 0xed0
+Hangul_EU = 0xed1
+Hangul_YI = 0xed2
+Hangul_I = 0xed3
+Hangul_J_Kiyeog = 0xed4
+Hangul_J_SsangKiyeog = 0xed5
+Hangul_J_KiyeogSios = 0xed6
+Hangul_J_Nieun = 0xed7
+Hangul_J_NieunJieuj = 0xed8
+Hangul_J_NieunHieuh = 0xed9
+Hangul_J_Dikeud = 0xeda
+Hangul_J_Rieul = 0xedb
+Hangul_J_RieulKiyeog = 0xedc
+Hangul_J_RieulMieum = 0xedd
+Hangul_J_RieulPieub = 0xede
+Hangul_J_RieulSios = 0xedf
+Hangul_J_RieulTieut = 0xee0
+Hangul_J_RieulPhieuf = 0xee1
+Hangul_J_RieulHieuh = 0xee2
+Hangul_J_Mieum = 0xee3
+Hangul_J_Pieub = 0xee4
+Hangul_J_PieubSios = 0xee5
+Hangul_J_Sios = 0xee6
+Hangul_J_SsangSios = 0xee7
+Hangul_J_Ieung = 0xee8
+Hangul_J_Jieuj = 0xee9
+Hangul_J_Cieuc = 0xeea
+Hangul_J_Khieuq = 0xeeb
+Hangul_J_Tieut = 0xeec
+Hangul_J_Phieuf = 0xeed
+Hangul_J_Hieuh = 0xeee
+Hangul_RieulYeorinHieuh = 0xeef
+Hangul_SunkyeongeumMieum = 0xef0
+Hangul_SunkyeongeumPieub = 0xef1
+Hangul_PanSios = 0xef2
+Hangul_KkogjiDalrinIeung = 0xef3
+Hangul_SunkyeongeumPhieuf = 0xef4
+Hangul_YeorinHieuh = 0xef5
+Hangul_AraeA = 0xef6
+Hangul_AraeAE = 0xef7
+Hangul_J_PanSios = 0xef8
+Hangul_J_KkogjiDalrinIeung = 0xef9
+Hangul_J_YeorinHieuh = 0xefa
+Korean_Won = 0xeff
+Armenian_eternity = 0x14a1
+Armenian_section_sign = 0x14a2
+Armenian_full_stop = 0x14a3
+Armenian_verjaket = 0x14a3
+Armenian_parenright = 0x14a4
+Armenian_parenleft = 0x14a5
+Armenian_guillemotright = 0x14a6
+Armenian_guillemotleft = 0x14a7
+Armenian_em_dash = 0x14a8
+Armenian_dot = 0x14a9
+Armenian_mijaket = 0x14a9
+Armenian_separation_mark = 0x14aa
+Armenian_but = 0x14aa
+Armenian_comma = 0x14ab
+Armenian_en_dash = 0x14ac
+Armenian_hyphen = 0x14ad
+Armenian_yentamna = 0x14ad
+Armenian_ellipsis = 0x14ae
+Armenian_exclam = 0x14af
+Armenian_amanak = 0x14af
+Armenian_accent = 0x14b0
+Armenian_shesht = 0x14b0
+Armenian_question = 0x14b1
+Armenian_paruyk = 0x14b1
+Armenian_AYB = 0x14b2
+Armenian_ayb = 0x14b3
+Armenian_BEN = 0x14b4
+Armenian_ben = 0x14b5
+Armenian_GIM = 0x14b6
+Armenian_gim = 0x14b7
+Armenian_DA = 0x14b8
+Armenian_da = 0x14b9
+Armenian_YECH = 0x14ba
+Armenian_yech = 0x14bb
+Armenian_ZA = 0x14bc
+Armenian_za = 0x14bd
+Armenian_E = 0x14be
+Armenian_e = 0x14bf
+Armenian_AT = 0x14c0
+Armenian_at = 0x14c1
+Armenian_TO = 0x14c2
+Armenian_to = 0x14c3
+Armenian_ZHE = 0x14c4
+Armenian_zhe = 0x14c5
+Armenian_INI = 0x14c6
+Armenian_ini = 0x14c7
+Armenian_LYUN = 0x14c8
+Armenian_lyun = 0x14c9
+Armenian_KHE = 0x14ca
+Armenian_khe = 0x14cb
+Armenian_TSA = 0x14cc
+Armenian_tsa = 0x14cd
+Armenian_KEN = 0x14ce
+Armenian_ken = 0x14cf
+Armenian_HO = 0x14d0
+Armenian_ho = 0x14d1
+Armenian_DZA = 0x14d2
+Armenian_dza = 0x14d3
+Armenian_GHAT = 0x14d4
+Armenian_ghat = 0x14d5
+Armenian_TCHE = 0x14d6
+Armenian_tche = 0x14d7
+Armenian_MEN = 0x14d8
+Armenian_men = 0x14d9
+Armenian_HI = 0x14da
+Armenian_hi = 0x14db
+Armenian_NU = 0x14dc
+Armenian_nu = 0x14dd
+Armenian_SHA = 0x14de
+Armenian_sha = 0x14df
+Armenian_VO = 0x14e0
+Armenian_vo = 0x14e1
+Armenian_CHA = 0x14e2
+Armenian_cha = 0x14e3
+Armenian_PE = 0x14e4
+Armenian_pe = 0x14e5
+Armenian_JE = 0x14e6
+Armenian_je = 0x14e7
+Armenian_RA = 0x14e8
+Armenian_ra = 0x14e9
+Armenian_SE = 0x14ea
+Armenian_se = 0x14eb
+Armenian_VEV = 0x14ec
+Armenian_vev = 0x14ed
+Armenian_TYUN = 0x14ee
+Armenian_tyun = 0x14ef
+Armenian_RE = 0x14f0
+Armenian_re = 0x14f1
+Armenian_TSO = 0x14f2
+Armenian_tso = 0x14f3
+Armenian_VYUN = 0x14f4
+Armenian_vyun = 0x14f5
+Armenian_PYUR = 0x14f6
+Armenian_pyur = 0x14f7
+Armenian_KE = 0x14f8
+Armenian_ke = 0x14f9
+Armenian_O = 0x14fa
+Armenian_o = 0x14fb
+Armenian_FE = 0x14fc
+Armenian_fe = 0x14fd
+Armenian_apostrophe = 0x14fe
+Armenian_ligature_ew = 0x14ff
+Georgian_an = 0x15d0
+Georgian_ban = 0x15d1
+Georgian_gan = 0x15d2
+Georgian_don = 0x15d3
+Georgian_en = 0x15d4
+Georgian_vin = 0x15d5
+Georgian_zen = 0x15d6
+Georgian_tan = 0x15d7
+Georgian_in = 0x15d8
+Georgian_kan = 0x15d9
+Georgian_las = 0x15da
+Georgian_man = 0x15db
+Georgian_nar = 0x15dc
+Georgian_on = 0x15dd
+Georgian_par = 0x15de
+Georgian_zhar = 0x15df
+Georgian_rae = 0x15e0
+Georgian_san = 0x15e1
+Georgian_tar = 0x15e2
+Georgian_un = 0x15e3
+Georgian_phar = 0x15e4
+Georgian_khar = 0x15e5
+Georgian_ghan = 0x15e6
+Georgian_qar = 0x15e7
+Georgian_shin = 0x15e8
+Georgian_chin = 0x15e9
+Georgian_can = 0x15ea
+Georgian_jil = 0x15eb
+Georgian_cil = 0x15ec
+Georgian_char = 0x15ed
+Georgian_xan = 0x15ee
+Georgian_jhan = 0x15ef
+Georgian_hae = 0x15f0
+Georgian_he = 0x15f1
+Georgian_hie = 0x15f2
+Georgian_we = 0x15f3
+Georgian_har = 0x15f4
+Georgian_hoe = 0x15f5
+Georgian_fi = 0x15f6
+EcuSign = 0x20a0
+ColonSign = 0x20a1
+CruzeiroSign = 0x20a2
+FFrancSign = 0x20a3
+LiraSign = 0x20a4
+MillSign = 0x20a5
+NairaSign = 0x20a6
+PesetaSign = 0x20a7
+RupeeSign = 0x20a8
+WonSign = 0x20a9
+NewSheqelSign = 0x20aa
+DongSign = 0x20ab
+EuroSign = 0x20ac
diff --git a/ibus/object.py b/ibus/object.py
new file mode 100644
index 0000000..af6a0fe
--- /dev/null
+++ b/ibus/object.py
@@ -0,0 +1,14 @@
+import gobject
+
+class Object (gobject.GObject):
+ __gsignals__ = {
+ 'destroy' : (
+ gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
+ ())
+ }
+
+ def destroy (self):
+ self.emit ("destroy")
+
+gobject.type_register (Object)
diff --git a/ibus/server.py b/ibus/server.py
new file mode 100755
index 0000000..6bd6642
--- /dev/null
+++ b/ibus/server.py
@@ -0,0 +1,62 @@
+#!/usr/bin/env python
+import dbus
+import dbus.server
+import dbus.lowlevel
+import dbus.mainloop.glib
+import gobject
+from ibus import keysyms
+from ibus import attribute
+from ibus import client
+from ibus import interface
+from ibus import IBus
+from ibus import Object
+
+from ibus.common import \
+ IBUS_PATH, \
+ IBUS_ADDR
+
+class IBusServer (Object):
+ def __init__ (self):
+ Object.__init__ (self)
+ self._server = dbus.server.Server (IBUS_ADDR)
+ self._ibus = IBus ()
+ self._server.register_object (self._ibus, IBUS_PATH)
+
+ def get_address (self):
+ return self._server.get_address ()
+
+ def new_connection (self, server, connection):
+ connection.add_message_filter (self.message_filter_cb)
+ pass
+
+ def remove_connection (self, connection):
+ pass
+
+ def message_filter_cb (self, connection, message):
+ if message.get_interface() == "org.freedesktop.DBus.Local" and \
+ message.get_member() == "Disconnected":
+ return dbus.lowlevel.HANDLER_RESULT_NOT_YET_HANDLED
+
+ return dbus.lowlevel.HANDLER_RESULT_NOT_YET_HANDLED
+
+ print "Got a Message (%s) : " % message.__class__.__name__
+ print "\t From: %s" % message.get_sender ()
+ print "\t To: %s" % message.get_destination ()
+ print "\t Interface: %s" % message.get_interface ()
+ print "\t Path: %s" % message.get_path ()
+ print "\t Member: %s" % message.get_member ()
+ print "\t Arguments:"
+ i = 0
+ for arg in message.get_args_list():
+ print "\t\t Arg[%d] : %s" % (i, arg)
+ i = i + 1
+
+ return dbus.lowlevel.HANDLER_RESULT_NOT_YET_HANDLED
+
+if __name__ == "__main__":
+ dbus.mainloop.glib.DBusGMainLoop (set_as_default = True)
+ loop = gobject.MainLoop ()
+ bus = IBusServer ()
+ print "IBUS_ADDRESS=\"%s\"" % bus.get_address ()
+ loop.run ()
+
diff --git a/m4/Makefile.am b/m4/Makefile.am
new file mode 100644
index 0000000..c5ec3b2
--- /dev/null
+++ b/m4/Makefile.am
@@ -0,0 +1,27 @@
+# vim:set noet ts=4:
+#
+# gik - The G Input Toolkit
+#
+# Copyright (c) 2007-2008 Huang Peng <shawn.p.huang@gmail.com>
+#
+#
+# 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 program; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+# Boston, MA 02111-1307 USA
+#
+# $Id: $
+#
+EXTRA_DIST = \
+ as-version.m4 \
+ $(NULL)
diff --git a/m4/as-version.m4 b/m4/as-version.m4
new file mode 100644
index 0000000..a5b4399
--- /dev/null
+++ b/m4/as-version.m4
@@ -0,0 +1,71 @@
+dnl as-version.m4 0.2.0
+
+dnl autostars m4 macro for versioning
+
+dnl Thomas Vander Stichele <thomas at apestaart dot org>
+
+dnl $Id: as-version.m4,v 1.4 2004/06/01 09:40:05 thomasvs Exp $
+
+dnl AS_VERSION
+
+dnl example
+dnl AS_VERSION
+
+dnl this macro
+dnl - AC_SUBST's PACKAGE_VERSION_MAJOR, _MINOR, _MICRO
+dnl - AC_SUBST's PACKAGE_VERSION_RELEASE,
+dnl which can be used for rpm release fields
+dnl - doesn't call AM_INIT_AUTOMAKE anymore because it prevents
+dnl maintainer mode from running correctly
+dnl
+dnl don't forget to put #undef PACKAGE_VERSION_RELEASE in acconfig.h
+dnl if you use acconfig.h
+
+AC_DEFUN([AS_VERSION],
+[
+ PACKAGE_VERSION_MAJOR=$(echo AC_PACKAGE_VERSION | cut -d'.' -f1)
+ PACKAGE_VERSION_MINOR=$(echo AC_PACKAGE_VERSION | cut -d'.' -f2)
+ PACKAGE_VERSION_MICRO=$(echo AC_PACKAGE_VERSION | cut -d'.' -f3)
+
+ AC_SUBST(PACKAGE_VERSION_MAJOR)
+ AC_SUBST(PACKAGE_VERSION_MINOR)
+ AC_SUBST(PACKAGE_VERSION_MICRO)
+])
+
+dnl AS_NANO(ACTION-IF-NO-NANO, [ACTION-IF-NANO])
+
+dnl requires AC_INIT to be called before
+dnl For projects using a fourth or nano number in your versioning to indicate
+dnl development or prerelease snapshots, this macro allows the build to be
+dnl set up differently accordingly.
+
+dnl this macro:
+dnl - parses AC_PACKAGE_VERSION, set by AC_INIT, and extracts the nano number
+dnl - sets the variable PACKAGE_VERSION_NANO
+dnl - sets the variable PACKAGE_VERSION_RELEASE, which can be used
+dnl for rpm release fields
+dnl - executes ACTION-IF-NO-NANO or ACTION-IF-NANO
+
+dnl example:
+dnl AS_NANO(RELEASE="yes", RELEASE="no")
+
+AC_DEFUN([AS_NANO],
+[
+ AC_MSG_CHECKING(nano version)
+
+ NANO=$(echo AC_PACKAGE_VERSION | cut -d'.' -f4)
+
+ if test x"$NANO" = x || test "x$NANO" = "x0" ; then
+ AC_MSG_RESULT([0 (release)])
+ NANO=0
+ PACKAGE_VERSION_RELEASE=1
+ ifelse([$1], , :, [$1])
+ else
+ AC_MSG_RESULT($NANO)
+ PACKAGE_VERSION_RELEASE=0.`date +%Y%m%d.%H%M%S`
+ ifelse([$2], , :, [$2])
+ fi
+ PACKAGE_VERSION_NANO=$NANO
+ AC_SUBST(PACKAGE_VERSION_NANO)
+ AC_SUBST(PACKAGE_VERSION_RELEASE)
+])
diff --git a/po/Makevars b/po/Makevars
new file mode 100644
index 0000000..7d73dbd
--- /dev/null
+++ b/po/Makevars
@@ -0,0 +1,41 @@
+# Makefile variables for PO directory in any package using GNU gettext.
+
+# Usually the message domain is the same as the package name.
+DOMAIN = $(PACKAGE)
+
+# These two variables depend on the location of this directory.
+subdir = po
+top_builddir = ..
+
+# These options get passed to xgettext.
+XGETTEXT_OPTIONS = --keyword=_ --keyword=N_
+
+# This is the copyright holder that gets inserted into the header of the
+# $(DOMAIN).pot file. Set this to the copyright holder of the surrounding
+# package. (Note that the msgstr strings, extracted from the package's
+# sources, belong to the copyright holder of the package.) Translators are
+# expected to transfer the copyright for their translations to this person
+# or entity, or to disclaim their copyright. The empty string stands for
+# the public domain; in this case the translators are expected to disclaim
+# their copyright.
+COPYRIGHT_HOLDER = Huang Peng <shawn.p.huang@gmail.com>
+
+# This is the email address or URL to which the translators shall report
+# bugs in the untranslated strings:
+# - Strings which are not entire sentences, see the maintainer guidelines
+# in the GNU gettext documentation, section 'Preparing Strings'.
+# - Strings which use unclear terms or require additional context to be
+# understood.
+# - Strings which make invalid assumptions about notation of date, time or
+# money.
+# - Pluralisation problems.
+# - Incorrect English spelling.
+# - Incorrect formatting.
+# It can be your email address, or a mailing list address where translators
+# can write to without being subscribed, or the URL of a web page through
+# which the translators can contact you.
+MSGID_BUGS_ADDRESS = $(PACKAGE_BUGREPORT)
+
+# This is the list of locale categories, beyond LC_MESSAGES, for which the
+# message catalogs shall be used. It is usually empty.
+EXTRA_LOCALE_CATEGORIES =
diff --git a/po/POTFILES.in b/po/POTFILES.in
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/po/POTFILES.in