summaryrefslogtreecommitdiff
path: root/engine
diff options
context:
space:
mode:
authorfujiwarat <takao.fujiwara1@gmail.com>2014-01-30 17:33:33 +0900
committerfujiwarat <takao.fujiwara1@gmail.com>2014-01-30 17:33:33 +0900
commit2e8e2bef7a7943ed351278c2f6c601339abd4d54 (patch)
tree702155a2687952da2b18d029e5154ea829643877 /engine
parent85330465240ba6a028c92290d74ef05dcb5d7cb9 (diff)
downloadibus-anthy-2e8e2bef7a7943ed351278c2f6c601339abd4d54.tar.gz
Added python3.
The default is to use 'python' and --with-python option can change it. ./configure --with-python=python3
Diffstat (limited to 'engine')
-rw-r--r--engine/Makefile.am130
-rw-r--r--engine/python2/Makefile.am144
-rw-r--r--engine/python2/_config.py.in (renamed from engine/_config.py.in)0
-rw-r--r--engine/python2/anthy.i (renamed from engine/anthy.i)0
-rw-r--r--engine/python2/anthy.xml.in.in (renamed from engine/anthy.xml.in.in)0
-rw-r--r--engine/python2/default.xml.in.in (renamed from engine/default.xml.in.in)0
-rw-r--r--engine/python2/engine.py (renamed from engine/engine.py)4
-rw-r--r--engine/python2/factory.py (renamed from engine/factory.py)0
-rw-r--r--engine/python2/ibus-engine-anthy.in (renamed from engine/ibus-engine-anthy.in)0
-rw-r--r--engine/python2/jastring.py (renamed from engine/jastring.py)0
-rw-r--r--engine/python2/kana.py (renamed from engine/kana.py)0
-rw-r--r--engine/python2/main.py (renamed from engine/main.py)0
-rw-r--r--engine/python2/romaji.py (renamed from engine/romaji.py)0
-rw-r--r--engine/python2/segment.py (renamed from engine/segment.py)0
-rw-r--r--engine/python2/tables.py (renamed from engine/tables.py)0
-rw-r--r--engine/python2/test.py (renamed from engine/test.py)0
-rw-r--r--engine/python2/thumb.py (renamed from engine/thumb.py)0
-rw-r--r--engine/python3/Makefile.am144
-rw-r--r--engine/python3/_config.py.in30
-rw-r--r--engine/python3/anthy.i125
-rw-r--r--engine/python3/anthy.xml.in.in19
-rw-r--r--engine/python3/default.xml.in.in19
-rw-r--r--engine/python3/engine.py2780
-rw-r--r--engine/python3/factory.py80
-rw-r--r--engine/python3/ibus-engine-anthy.in33
-rw-r--r--engine/python3/jastring.py304
-rw-r--r--engine/python3/kana.py170
-rw-r--r--engine/python3/main.py188
-rw-r--r--engine/python3/romaji.py263
-rw-r--r--engine/python3/segment.py95
-rw-r--r--engine/python3/tables.py731
-rw-r--r--engine/python3/test.py21
-rw-r--r--engine/python3/thumb.py657
33 files changed, 5813 insertions, 124 deletions
diff --git a/engine/Makefile.am b/engine/Makefile.am
index a96f831..3c64425 100644
--- a/engine/Makefile.am
+++ b/engine/Makefile.am
@@ -2,9 +2,8 @@
#
# ibus-anthy - The Anthy engine for IBus
#
-# Copyright (c) 2007-2008 Peng Huang <shawn.p.huang@gmail.com>
-# Copyright (c) 2010-2013 Takao Fujiwara <takao.fujiwara1@gmail.com>
-# Copyright (c) 2007-2013 Red Hat, Inc.
+# Copyright (c) 2014 Takao Fujiwara <takao.fujiwara1@gmail.com>
+# Copyright (c) 2014 Red Hat, Inc.
#
# 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
@@ -20,125 +19,12 @@
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-BUILT_SOURCES = _config.py
+SUBDIRS =
-engine_anthy_PYTHON = \
- _config.py \
- engine.py \
- factory.py \
- jastring.py \
- kana.py \
- main.py \
- romaji.py \
- segment.py \
- tables.py \
- thumb.py \
- $(NULL)
-engine_anthydir = $(pkgdatadir)/engine
-engine_anthy_built_files = $(BUILT_SOURCES)
-engine_anthy_built_in_files = $(addsuffix .in, $(engine_anthy_built_files))
-
-PYGTK2_ANTHY_RAW = anthy.i
-PYGTK2_ANTHY_GEN = anthy.py anthy_wrap.c
-
-if HAVE_PYGTK2_ANTHY
-anthy_DATA = \
- anthy.py \
- $(NULL)
-anthy_LTLIBRARIES = _anthy.la
-anthydir = @pyexecdir@
-
-_anthy_la_SOURCES = \
- $(NULL)
-
-nodist__anthy_la_SOURCES = \
- anthy_wrap.c \
- $(NULL)
-
-_anthy_la_CFLAGS = \
- @ANTHY_CFLAGS@ \
- @PYTHON_CFLAGS@ \
- $(NULL)
-
-_anthy_la_LDFLAGS = \
- @ANTHY_LIBS@ \
- @PYTHON_LIBS@ \
- -avoid-version \
- -module \
- $(NULL)
-
-anthy.py anthy_wrap.c: anthy.i
- $(SWIG) -python $(ANTHY_CFLAGS) -I/usr/include -o anthy_wrap.c $(srcdir)/anthy.i
+if ENABLE_PYTHON2
+SUBDIRS += python2
endif
-libexec_SCRIPTS = ibus-engine-anthy
-component_DATA = anthy.xml
-componentdir = $(datadir)/ibus/component
-engine_DATA = default.xml
-enginedir = $(pkgdatadir)/engine
-
-anthy.xml: anthy.xml.in
- ( \
- libexecdir=${libexecdir}; \
- pkgdatadir=${pkgdatadir}; \
- s=`cat $<`; \
- eval "echo \"$${s}\""; \
- ) > $@
-
-default.xml: default.xml.in
- ( \
- libexecdir=${libexecdir}; \
- pkgdatadir=${pkgdatadir}; \
- s=`cat $<`; \
- eval "echo \"$${s}\""; \
- ) > $@
-
-_config.py: _config.py.in
- ( \
- PKGDATADIR=$(pkgdatadir); \
- LIBEXECDIR=$(libexecdir); \
- DATADIR=$(datadir); \
- LAYOUT=$(LAYOUT); \
- SYMBOL_CHAR_INT=$(SYMBOL_CHAR_INT); \
- ICON_PREFERENCE=$(ICON_PREFERENCE); \
- s=`cat $<`; \
- eval "echo \"$${s}\""; \
- ) > $@
-
-test:
- $(ENV_IBUS_TEST) \
- DBUS_DEBUG=true \
- IBUS_ANTHY_PKGDATADIR=$(abs_top_srcdir) \
- PYTHONPATH=$(builddir)/.libs:@pyexecdir@ \
- $(PYTHON) \
- $(srcdir)/main.py
-
-EXTRA_DIST = \
- $(engine_anthy_built_in_files) \
- $(PYGTK2_ANTHY_RAW) \
- anthy.xml.in.in \
- default.xml.in.in \
- ibus-engine-anthy.in \
- $(NULL)
-
-CLEANFILES = \
- $(BUILT_SOURCES) \
- $(PYGTK2_ANTHY_GEN) \
- anthy.xml \
- default.xml \
- *.pyc \
- $(NULL)
-
-DISTCLEANFILES = \
- $(NULL)
-
-# Need a time lag between .py and .py.in files to build .py files
-# because *_PYTHON valuables are installed in the tarball.
-dist-hook:
- @sleep 1; \
- for in_file in $(engine_anthy_built_in_files) ; do \
- if [ -f $(distdir)/$(srcdir)/$$in_file ] ; then \
- touch $(distdir)/$(srcdir)/$$in_file; \
- fi; \
- done;
-
+if ENABLE_PYTHON3
+SUBDIRS += python3
+endif
diff --git a/engine/python2/Makefile.am b/engine/python2/Makefile.am
new file mode 100644
index 0000000..a96f831
--- /dev/null
+++ b/engine/python2/Makefile.am
@@ -0,0 +1,144 @@
+# vim:set noet ts=4:
+#
+# ibus-anthy - The Anthy engine for IBus
+#
+# Copyright (c) 2007-2008 Peng Huang <shawn.p.huang@gmail.com>
+# Copyright (c) 2010-2013 Takao Fujiwara <takao.fujiwara1@gmail.com>
+# Copyright (c) 2007-2013 Red Hat, Inc.
+#
+# 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.
+
+BUILT_SOURCES = _config.py
+
+engine_anthy_PYTHON = \
+ _config.py \
+ engine.py \
+ factory.py \
+ jastring.py \
+ kana.py \
+ main.py \
+ romaji.py \
+ segment.py \
+ tables.py \
+ thumb.py \
+ $(NULL)
+engine_anthydir = $(pkgdatadir)/engine
+engine_anthy_built_files = $(BUILT_SOURCES)
+engine_anthy_built_in_files = $(addsuffix .in, $(engine_anthy_built_files))
+
+PYGTK2_ANTHY_RAW = anthy.i
+PYGTK2_ANTHY_GEN = anthy.py anthy_wrap.c
+
+if HAVE_PYGTK2_ANTHY
+anthy_DATA = \
+ anthy.py \
+ $(NULL)
+anthy_LTLIBRARIES = _anthy.la
+anthydir = @pyexecdir@
+
+_anthy_la_SOURCES = \
+ $(NULL)
+
+nodist__anthy_la_SOURCES = \
+ anthy_wrap.c \
+ $(NULL)
+
+_anthy_la_CFLAGS = \
+ @ANTHY_CFLAGS@ \
+ @PYTHON_CFLAGS@ \
+ $(NULL)
+
+_anthy_la_LDFLAGS = \
+ @ANTHY_LIBS@ \
+ @PYTHON_LIBS@ \
+ -avoid-version \
+ -module \
+ $(NULL)
+
+anthy.py anthy_wrap.c: anthy.i
+ $(SWIG) -python $(ANTHY_CFLAGS) -I/usr/include -o anthy_wrap.c $(srcdir)/anthy.i
+endif
+
+libexec_SCRIPTS = ibus-engine-anthy
+component_DATA = anthy.xml
+componentdir = $(datadir)/ibus/component
+engine_DATA = default.xml
+enginedir = $(pkgdatadir)/engine
+
+anthy.xml: anthy.xml.in
+ ( \
+ libexecdir=${libexecdir}; \
+ pkgdatadir=${pkgdatadir}; \
+ s=`cat $<`; \
+ eval "echo \"$${s}\""; \
+ ) > $@
+
+default.xml: default.xml.in
+ ( \
+ libexecdir=${libexecdir}; \
+ pkgdatadir=${pkgdatadir}; \
+ s=`cat $<`; \
+ eval "echo \"$${s}\""; \
+ ) > $@
+
+_config.py: _config.py.in
+ ( \
+ PKGDATADIR=$(pkgdatadir); \
+ LIBEXECDIR=$(libexecdir); \
+ DATADIR=$(datadir); \
+ LAYOUT=$(LAYOUT); \
+ SYMBOL_CHAR_INT=$(SYMBOL_CHAR_INT); \
+ ICON_PREFERENCE=$(ICON_PREFERENCE); \
+ s=`cat $<`; \
+ eval "echo \"$${s}\""; \
+ ) > $@
+
+test:
+ $(ENV_IBUS_TEST) \
+ DBUS_DEBUG=true \
+ IBUS_ANTHY_PKGDATADIR=$(abs_top_srcdir) \
+ PYTHONPATH=$(builddir)/.libs:@pyexecdir@ \
+ $(PYTHON) \
+ $(srcdir)/main.py
+
+EXTRA_DIST = \
+ $(engine_anthy_built_in_files) \
+ $(PYGTK2_ANTHY_RAW) \
+ anthy.xml.in.in \
+ default.xml.in.in \
+ ibus-engine-anthy.in \
+ $(NULL)
+
+CLEANFILES = \
+ $(BUILT_SOURCES) \
+ $(PYGTK2_ANTHY_GEN) \
+ anthy.xml \
+ default.xml \
+ *.pyc \
+ $(NULL)
+
+DISTCLEANFILES = \
+ $(NULL)
+
+# Need a time lag between .py and .py.in files to build .py files
+# because *_PYTHON valuables are installed in the tarball.
+dist-hook:
+ @sleep 1; \
+ for in_file in $(engine_anthy_built_in_files) ; do \
+ if [ -f $(distdir)/$(srcdir)/$$in_file ] ; then \
+ touch $(distdir)/$(srcdir)/$$in_file; \
+ fi; \
+ done;
+
diff --git a/engine/_config.py.in b/engine/python2/_config.py.in
index 4d5738b..4d5738b 100644
--- a/engine/_config.py.in
+++ b/engine/python2/_config.py.in
diff --git a/engine/anthy.i b/engine/python2/anthy.i
index 68a3aa9..68a3aa9 100644
--- a/engine/anthy.i
+++ b/engine/python2/anthy.i
diff --git a/engine/anthy.xml.in.in b/engine/python2/anthy.xml.in.in
index 9a93744..9a93744 100644
--- a/engine/anthy.xml.in.in
+++ b/engine/python2/anthy.xml.in.in
diff --git a/engine/default.xml.in.in b/engine/python2/default.xml.in.in
index 27e3c82..27e3c82 100644
--- a/engine/default.xml.in.in
+++ b/engine/python2/default.xml.in.in
diff --git a/engine/engine.py b/engine/python2/engine.py
index f38ebcf..be91802 100644
--- a/engine/engine.py
+++ b/engine/python2/engine.py
@@ -2350,7 +2350,7 @@ class Engine(IBus.EngineSimple):
self.__convert_chars = UN(clipboard_text)
for i in xrange(0, len(self.__convert_chars)):
keyval = self.__convert_chars[i]
- self.__preedit_ja_string.insert(unichr(ord (keyval)))
+ self.__preedit_ja_string.insert(unichr(ord(keyval)))
self.__context.set_string(self.__convert_chars.encode('utf-8'))
nr_segments = self.__context.get_nr_segments()
@@ -2484,7 +2484,7 @@ class Engine(IBus.EngineSimple):
self.__cursor_pos = 0
text, cursor = self.__get_preedit()
self.__convert_chars = text
- self.__context.set_string(text.encode ('utf-8'))
+ self.__context.set_string(text.encode('utf-8'))
self.__lookup_table.clear()
self.__lookup_table.set_cursor_visible(False)
diff --git a/engine/factory.py b/engine/python2/factory.py
index d4aa075..d4aa075 100644
--- a/engine/factory.py
+++ b/engine/python2/factory.py
diff --git a/engine/ibus-engine-anthy.in b/engine/python2/ibus-engine-anthy.in
index c54b10a..c54b10a 100644
--- a/engine/ibus-engine-anthy.in
+++ b/engine/python2/ibus-engine-anthy.in
diff --git a/engine/jastring.py b/engine/python2/jastring.py
index aeb7e6e..aeb7e6e 100644
--- a/engine/jastring.py
+++ b/engine/python2/jastring.py
diff --git a/engine/kana.py b/engine/python2/kana.py
index c85a199..c85a199 100644
--- a/engine/kana.py
+++ b/engine/python2/kana.py
diff --git a/engine/main.py b/engine/python2/main.py
index b899681..b899681 100644
--- a/engine/main.py
+++ b/engine/python2/main.py
diff --git a/engine/romaji.py b/engine/python2/romaji.py
index 48167c6..48167c6 100644
--- a/engine/romaji.py
+++ b/engine/python2/romaji.py
diff --git a/engine/segment.py b/engine/python2/segment.py
index d423f19..d423f19 100644
--- a/engine/segment.py
+++ b/engine/python2/segment.py
diff --git a/engine/tables.py b/engine/python2/tables.py
index 2e41366..2e41366 100644
--- a/engine/tables.py
+++ b/engine/python2/tables.py
diff --git a/engine/test.py b/engine/python2/test.py
index cd67997..cd67997 100644
--- a/engine/test.py
+++ b/engine/python2/test.py
diff --git a/engine/thumb.py b/engine/python2/thumb.py
index 6a7e3d2..6a7e3d2 100644
--- a/engine/thumb.py
+++ b/engine/python2/thumb.py
diff --git a/engine/python3/Makefile.am b/engine/python3/Makefile.am
new file mode 100644
index 0000000..a96f831
--- /dev/null
+++ b/engine/python3/Makefile.am
@@ -0,0 +1,144 @@
+# vim:set noet ts=4:
+#
+# ibus-anthy - The Anthy engine for IBus
+#
+# Copyright (c) 2007-2008 Peng Huang <shawn.p.huang@gmail.com>
+# Copyright (c) 2010-2013 Takao Fujiwara <takao.fujiwara1@gmail.com>
+# Copyright (c) 2007-2013 Red Hat, Inc.
+#
+# 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.
+
+BUILT_SOURCES = _config.py
+
+engine_anthy_PYTHON = \
+ _config.py \
+ engine.py \
+ factory.py \
+ jastring.py \
+ kana.py \
+ main.py \
+ romaji.py \
+ segment.py \
+ tables.py \
+ thumb.py \
+ $(NULL)
+engine_anthydir = $(pkgdatadir)/engine
+engine_anthy_built_files = $(BUILT_SOURCES)
+engine_anthy_built_in_files = $(addsuffix .in, $(engine_anthy_built_files))
+
+PYGTK2_ANTHY_RAW = anthy.i
+PYGTK2_ANTHY_GEN = anthy.py anthy_wrap.c
+
+if HAVE_PYGTK2_ANTHY
+anthy_DATA = \
+ anthy.py \
+ $(NULL)
+anthy_LTLIBRARIES = _anthy.la
+anthydir = @pyexecdir@
+
+_anthy_la_SOURCES = \
+ $(NULL)
+
+nodist__anthy_la_SOURCES = \
+ anthy_wrap.c \
+ $(NULL)
+
+_anthy_la_CFLAGS = \
+ @ANTHY_CFLAGS@ \
+ @PYTHON_CFLAGS@ \
+ $(NULL)
+
+_anthy_la_LDFLAGS = \
+ @ANTHY_LIBS@ \
+ @PYTHON_LIBS@ \
+ -avoid-version \
+ -module \
+ $(NULL)
+
+anthy.py anthy_wrap.c: anthy.i
+ $(SWIG) -python $(ANTHY_CFLAGS) -I/usr/include -o anthy_wrap.c $(srcdir)/anthy.i
+endif
+
+libexec_SCRIPTS = ibus-engine-anthy
+component_DATA = anthy.xml
+componentdir = $(datadir)/ibus/component
+engine_DATA = default.xml
+enginedir = $(pkgdatadir)/engine
+
+anthy.xml: anthy.xml.in
+ ( \
+ libexecdir=${libexecdir}; \
+ pkgdatadir=${pkgdatadir}; \
+ s=`cat $<`; \
+ eval "echo \"$${s}\""; \
+ ) > $@
+
+default.xml: default.xml.in
+ ( \
+ libexecdir=${libexecdir}; \
+ pkgdatadir=${pkgdatadir}; \
+ s=`cat $<`; \
+ eval "echo \"$${s}\""; \
+ ) > $@
+
+_config.py: _config.py.in
+ ( \
+ PKGDATADIR=$(pkgdatadir); \
+ LIBEXECDIR=$(libexecdir); \
+ DATADIR=$(datadir); \
+ LAYOUT=$(LAYOUT); \
+ SYMBOL_CHAR_INT=$(SYMBOL_CHAR_INT); \
+ ICON_PREFERENCE=$(ICON_PREFERENCE); \
+ s=`cat $<`; \
+ eval "echo \"$${s}\""; \
+ ) > $@
+
+test:
+ $(ENV_IBUS_TEST) \
+ DBUS_DEBUG=true \
+ IBUS_ANTHY_PKGDATADIR=$(abs_top_srcdir) \
+ PYTHONPATH=$(builddir)/.libs:@pyexecdir@ \
+ $(PYTHON) \
+ $(srcdir)/main.py
+
+EXTRA_DIST = \
+ $(engine_anthy_built_in_files) \
+ $(PYGTK2_ANTHY_RAW) \
+ anthy.xml.in.in \
+ default.xml.in.in \
+ ibus-engine-anthy.in \
+ $(NULL)
+
+CLEANFILES = \
+ $(BUILT_SOURCES) \
+ $(PYGTK2_ANTHY_GEN) \
+ anthy.xml \
+ default.xml \
+ *.pyc \
+ $(NULL)
+
+DISTCLEANFILES = \
+ $(NULL)
+
+# Need a time lag between .py and .py.in files to build .py files
+# because *_PYTHON valuables are installed in the tarball.
+dist-hook:
+ @sleep 1; \
+ for in_file in $(engine_anthy_built_in_files) ; do \
+ if [ -f $(distdir)/$(srcdir)/$$in_file ] ; then \
+ touch $(distdir)/$(srcdir)/$$in_file; \
+ fi; \
+ done;
+
diff --git a/engine/python3/_config.py.in b/engine/python3/_config.py.in
new file mode 100644
index 0000000..f68b50a
--- /dev/null
+++ b/engine/python3/_config.py.in
@@ -0,0 +1,30 @@
+# vim:set et sts=4 sw=4:
+# -*- coding: utf-8 -*-
+#
+# ibus-anthy - The Anthy engine for IBus
+#
+# Copyright (c) 2007-2008 Peng Huang <shawn.p.huang@gmail.com>
+# Copyright (c) 2010-2014 Takao Fujiwara <takao.fujiwara1@gmail.com>
+# Copyright (c) 2007-2014 Red Hat, Inc.
+#
+# 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.
+
+PKGDATADIR = '${PKGDATADIR}'
+LIBEXECDIR = '${LIBEXECDIR}'
+LOCALEDIR = '${DATADIR}/locale'
+LAYOUT = '${LAYOUT}'
+SYMBOL_CHAR = chr(${SYMBOL_CHAR_INT})
+ICON_PREFERENCE = '${ICON_PREFERENCE}'
+DEBUG = False
diff --git a/engine/python3/anthy.i b/engine/python3/anthy.i
new file mode 100644
index 0000000..68a3aa9
--- /dev/null
+++ b/engine/python3/anthy.i
@@ -0,0 +1,125 @@
+/* vim:set et ts=4: */
+/*
+ * ibus-anthy - The Anthy engine for IBus
+ *
+ * Copyright (c) 2007-2008 Peng Huang <shawn.p.huang@gmail.com>
+ * Copyright (c) 2010-2013 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ * Copyright (c) 2007-2013 Red Hat, Inc.
+ *
+ * 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.
+ */
+
+%module anthy
+%{
+ /* Put header files here or function declarations like below */
+#include <anthy/anthy.h>
+%}
+
+%init %{
+ anthy_init ();
+%}
+
+/* anthy_context_t */
+%include anthy/anthy.h
+struct anthy_context {};
+%extend anthy_context {
+ anthy_context () {
+ return anthy_create_context ();
+ }
+
+ void reset () {
+ anthy_reset_context (self);
+ }
+
+ int set_string (char *str) {
+ return anthy_set_string (self, str);
+ }
+
+ void resize_segment (int a1, int a2) {
+ anthy_resize_segment (self, a1, a2);
+ }
+
+ int get_stat (struct anthy_conv_stat *a1) {
+ return anthy_get_stat (self, a1);
+ }
+
+ int get_segment_stat (int a1, struct anthy_segment_stat *a2) {
+ return anthy_get_segment_stat (self, a1, a2);
+ }
+
+ char *get_segment (int a1, int a2) {
+ int len;
+ static char temp[512];
+
+ len = anthy_get_segment (self, a1, a2, temp, sizeof (temp));
+ if (len >= 0)
+ return temp;
+ else
+ return NULL;
+ }
+
+ int commit_segment (int a1, int a2) {
+ return anthy_commit_segment (self, a1, a2);
+ }
+
+ int set_prediction_string (const char *a1) {
+ return anthy_set_prediction_string (self, a1);
+ }
+
+ int get_prediction_stat (struct anthy_prediction_stat *a1) {
+ return anthy_get_prediction_stat (self, a1);
+ }
+
+ char *get_prediction (int a1) {
+ int len;
+ static char temp[512];
+
+ len = anthy_get_prediction (self, a1, temp, sizeof (temp));
+
+ if (len >= 0)
+ return temp;
+ else
+ return NULL;
+ }
+
+ int commit_prediction (int a1) {
+ return anthy_commit_prediction(self, a1);
+ }
+
+ void _print () {
+ anthy_print_context (self);
+ }
+
+ int _set_encoding (int encoding) {
+ return anthy_context_set_encoding (self, encoding);
+ }
+
+ int set_reconversion_mode (int mode) {
+ return anthy_set_reconversion_mode (self, mode);
+ }
+
+ int init_personality (void) {
+ return anthy_init_personality ();
+ }
+
+ int do_set_personality (const char *id) {
+ return anthy_do_set_personality (id);
+ }
+
+ ~anthy_context () {
+ anthy_release_context (self);
+ }
+};
+
diff --git a/engine/python3/anthy.xml.in.in b/engine/python3/anthy.xml.in.in
new file mode 100644
index 0000000..9a93744
--- /dev/null
+++ b/engine/python3/anthy.xml.in.in
@@ -0,0 +1,19 @@
+<?xml version=\"1.0\" encoding=\"utf-8\"?>
+<!-- filename: anthy.xml -->
+<component>
+ <name>org.freedesktop.IBus.Anthy</name>
+ <description>Anthy Component</description>
+ <exec>${libexecdir}/ibus-engine-anthy --ibus</exec>
+ <version>@VERSION@</version>
+ <author>Peng Huang &lt;shawn.p.huang@gmail.com&gt;</author>
+ <license>GPL</license>
+ <homepage>http://code.google.com/p/ibus</homepage>
+ <textdomain>ibus-anthy</textdomain>
+
+ <!-- for engines -->
+ <observed-paths>
+ <path>~/.config/ibus-anthy/engines.xml</path>
+ <path>${pkgdatadir}/engine/default.xml</path>
+ </observed-paths>
+ <engines exec=\"${libexecdir}/ibus-engine-anthy --xml\" />
+</component>
diff --git a/engine/python3/default.xml.in.in b/engine/python3/default.xml.in.in
new file mode 100644
index 0000000..27e3c82
--- /dev/null
+++ b/engine/python3/default.xml.in.in
@@ -0,0 +1,19 @@
+<?xml version=\"1.0\" encoding=\"utf-8\"?>
+<engines>
+ <engine>
+ <name>anthy</name>
+ <language>ja</language>
+ <license>GPL</license>
+ <author>Peng Huang &lt;shawn.p.huang@gmail.com&gt;</author>
+ <icon>ibus-anthy</icon>
+ @LAYOUT_XML@
+ <layout_variant></layout_variant>
+ <layout_option></layout_option>
+ <longname>Anthy</longname>
+ <description>Anthy Input Method</description>
+ <rank>99</rank>
+ @HOTKEYS_XML@
+ @SYMBOL_XML@
+ <version>@PACKAGE_VERSION@</version>
+ </engine>
+</engines>
diff --git a/engine/python3/engine.py b/engine/python3/engine.py
new file mode 100644
index 0000000..2119c39
--- /dev/null
+++ b/engine/python3/engine.py
@@ -0,0 +1,2780 @@
+# vim:set et sts=4 sw=4:
+# -*- coding: utf-8 -*-
+#
+# ibus-anthy - The Anthy engine for IBus
+#
+# Copyright (c) 2007-2008 Peng Huang <shawn.p.huang@gmail.com>
+# Copyright (c) 2010-2014 Takao Fujiwara <takao.fujiwara1@gmail.com>
+# Copyright (c) 2007-2014 Red Hat, Inc.
+#
+# 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.
+
+import binascii
+import os
+from os import environ, path
+import signal
+import sys
+from gettext import dgettext
+
+from main import get_userhome
+
+try:
+ from locale import getpreferredencoding
+except:
+ pass
+
+from gi.repository import GLib
+from gi.repository import IBus
+
+from gi.repository import Anthy
+NTH_UNCONVERTED_CANDIDATE = Anthy.NTH_UNCONVERTED_CANDIDATE
+NTH_KATAKANA_CANDIDATE = Anthy.NTH_KATAKANA_CANDIDATE
+NTH_HIRAGANA_CANDIDATE = Anthy.NTH_HIRAGANA_CANDIDATE
+NTH_HALFKANA_CANDIDATE = Anthy.NTH_HALFKANA_CANDIDATE
+
+import _config as config
+from tables import *
+import jastring
+from segment import unichar_half_to_full
+
+sys.path.append(path.join(config.PKGDATADIR, 'setup'))
+from anthyprefs import AnthyPrefs
+
+_ = lambda a : dgettext('ibus-anthy', a)
+N_ = lambda a : a
+UN = lambda a : unicode(a, 'utf-8')
+
+printerr = AnthyPrefs.printerr
+
+INPUT_MODE_HIRAGANA, \
+INPUT_MODE_KATAKANA, \
+INPUT_MODE_HALF_WIDTH_KATAKANA, \
+INPUT_MODE_LATIN, \
+INPUT_MODE_WIDE_LATIN = list(range(5))
+
+CONV_MODE_OFF, \
+CONV_MODE_ANTHY, \
+CONV_MODE_HIRAGANA, \
+CONV_MODE_KATAKANA, \
+CONV_MODE_HALF_WIDTH_KATAKANA, \
+CONV_MODE_LATIN_0, \
+CONV_MODE_LATIN_1, \
+CONV_MODE_LATIN_2, \
+CONV_MODE_LATIN_3, \
+CONV_MODE_WIDE_LATIN_0, \
+CONV_MODE_WIDE_LATIN_1, \
+CONV_MODE_WIDE_LATIN_2, \
+CONV_MODE_WIDE_LATIN_3, \
+CONV_MODE_PREDICTION = list(range(14))
+
+SEGMENT_DEFAULT = 0
+SEGMENT_SINGLE = 1 << 0
+SEGMENT_IMMEDIATE = 1 << 1
+
+CLIPBOARD_RECONVERT = list(range(1))
+
+LINK_DICT_EMBEDDED, \
+LINK_DICT_SINGLE = list(range(2))
+
+IMPORTED_EMBEDDED_DICT_DIR = 'imported_words_default.d'
+IMPORTED_EMBEDDED_DICT_PREFIX = 'ibus__'
+IMPORTED_SINGLE_DICT_PREFIX = 'imported_words_ibus__'
+
+KP_Table = {}
+for s in dir(IBus):
+ if s.startswith('KEY_KP_'):
+ v = IBus.keyval_from_name(s[7:])
+ if v:
+ KP_Table[IBus.keyval_from_name(s[4:])] = v
+for k, v in zip(['KEY_KP_Add', 'KEY_KP_Decimal', 'KEY_KP_Divide', 'KEY_KP_Enter',
+ 'KEY_KP_Equal', 'KEY_KP_Multiply', 'KEY_KP_Separator',
+ 'KEY_KP_Space', 'KEY_KP_Subtract'],
+ ['KEY_plus', 'KEY_period', 'KEY_slash', 'KEY_Return',
+ 'KEY_equal', 'KEY_asterisk', 'KEY_comma',
+ 'KEY_space', 'KEY_minus']):
+ KP_Table[getattr(IBus, k)] = getattr(IBus, v)
+
+class Engine(IBus.EngineSimple):
+ __input_mode = None
+ __typing_mode = None
+ __segment_mode = None
+ __dict_mode = None
+
+ __setup_pid = 0
+ __prefs = None
+ __keybind = {}
+ __thumb = None
+ __latin_with_shift = True
+
+ def __init__(self, bus, object_path):
+ super(Engine, self).__init__(engine_name="anthy",
+ connection=bus.get_connection(),
+ object_path=object_path)
+
+ # create anthy context
+ self.__context = Anthy.GContext()
+ self.__context.set_encoding(Anthy.UTF8_ENCODING)
+
+ # init state
+ self.__idle_id = 0
+ self.__prop_dict = {}
+ self.__input_purpose = 0
+ self.__has_input_purpose = False
+ if hasattr(IBus, 'InputPurpose'):
+ self.__has_input_purpose = True
+ try:
+ self.__is_utf8 = (getpreferredencoding().lower() == 'utf-8')
+ except:
+ self.__is_utf8 = False
+ self.__ibus_version = 0.0
+
+# self.__lookup_table = ibus.LookupTable.new(page_size=9,
+# cursor_pos=0,
+# cursor_visible=True,
+# round=True)
+ size = self.__prefs.get_value('common', 'page_size')
+ self.__lookup_table = IBus.LookupTable.new(page_size=size,
+ cursor_pos=0,
+ cursor_visible=True,
+ round=True)
+ self.__prop_list = self.__init_props()
+
+ # Do not use self.do_process_key_event to work ISO 14755
+ # with Ctrl+Shift+u .
+ # The super (parent) method of do_process_key_event is called
+ # loop infinitely if this class overrides it.
+ # self.process_key_event is not accessible too.
+ self.connect('process-key-event', self.__process_key_event)
+ self.connect('destroy', self.__destroy)
+
+ self.__init_signal()
+ # use reset to init values
+ self.__reset()
+
+ ibus_config = bus.get_config()
+ if ibus_config != None:
+ ibus_config.connect('value-changed',
+ self.__config_value_changed_cb)
+
+ def __get_ibus_version(self):
+ if self.__ibus_version == 0.0:
+ self.__ibus_version = \
+ IBus.MAJOR_VERSION + IBus.MINOR_VERSION / 1000.0 + \
+ IBus.MICRO_VERSION / 1000000.0
+ return self.__ibus_version
+
+ # reset values of engine
+ def __reset(self):
+ self.__preedit_ja_string = jastring.JaString(Engine.__typing_mode,
+ self.__latin_with_shift)
+ self.__convert_chars = ''
+ self.__cursor_pos = 0
+ self.__convert_mode = CONV_MODE_OFF
+ self.__segments = list()
+ self.__lookup_table.clear()
+ self.__lookup_table_visible = False
+ self._MM = 0
+ self._SS = 0
+ self._H = 0
+ self._RMM = 0
+ self._RSS = 0
+ if self.__idle_id != 0:
+ GLib.source_remove(self.__idle_id)
+ self.__idle_id = 0
+
+ def __init_props(self):
+ anthy_props = IBus.PropList()
+
+ self.__set_input_mode_props(anthy_props)
+ self.__set_typing_method_props(anthy_props)
+ self.__set_segment_mode_props(anthy_props)
+ self.__set_dict_mode_props(anthy_props)
+ self.__set_dict_config_props(anthy_props)
+
+ if not self.__prefs.get_value('common', 'show-preferences'):
+ return anthy_props
+
+ anthy_props.append(IBus.Property(key='setup',
+ label=IBus.Text.new_from_string(_("Preferences - Anthy")),
+ icon=config.ICON_PREFERENCE,
+ tooltip=IBus.Text.new_from_string(_("Configure Anthy")),
+ sensitive=True,
+ visible=True))
+
+ return anthy_props
+
+ def __init_signal(self):
+ signal.signal(signal.SIGHUP, self.__signal_cb)
+ signal.signal(signal.SIGINT, self.__signal_cb)
+ signal.signal(signal.SIGQUIT, self.__signal_cb)
+ signal.signal(signal.SIGABRT, self.__signal_cb)
+ signal.signal(signal.SIGTERM, self.__signal_cb)
+
+ def __signal_cb(self, signum, object):
+ self.__remove_dict_files()
+ signal.signal(signum, signal.SIG_DFL)
+ os.kill(os.getpid(), signum)
+
+ def __set_input_mode_props(self, anthy_props):
+ # The class method is kept even if the engine is switched.
+ if Engine.__input_mode == None:
+ # The config value is readonly for initial engine and
+ # the engine keeps the class method in the memory.
+ Engine.__input_mode = INPUT_MODE_HIRAGANA
+ Engine.__input_mode = self.__prefs.get_value('common',
+ 'input_mode')
+
+ if not self.__prefs.get_value('common', 'show-input-mode'):
+ return
+
+ # init input mode properties
+ symbol = 'あ'
+ '''
+ Need to split _() by line for intltool to detect them.
+ '''
+ # Translators: Specify the order of %s with your translation.
+ # It will be "Input Mode (A)" for example.
+ label = _("%(description)s (%(symbol)s)") % \
+ { 'description' : _("Input mode"), 'symbol' : symbol }
+ input_mode_prop = IBus.Property(key='InputMode',
+ prop_type=IBus.PropType.MENU,
+ label=IBus.Text.new_from_string(label),
+ symbol=IBus.Text.new_from_string(symbol),
+ icon='',
+ tooltip=IBus.Text.new_from_string(_("Switch input mode")),
+ sensitive=True,
+ visible=True,
+ state=IBus.PropState.UNCHECKED,
+ sub_props=None)
+ self.__prop_dict['InputMode'] = input_mode_prop
+
+ props = IBus.PropList()
+ props.append(IBus.Property(key='InputMode.Hiragana',
+ prop_type=IBus.PropType.RADIO,
+ label=IBus.Text.new_from_string(_("Hiragana")),
+ icon=None,
+ tooltip=None,
+ sensitive=True,
+ visible=True,
+ state=IBus.PropState.UNCHECKED,
+ sub_props=None))
+ props.append(IBus.Property(key='InputMode.Katakana',
+ prop_type=IBus.PropType.RADIO,
+ label=IBus.Text.new_from_string(_("Katakana")),
+ icon=None,
+ tooltip=None,
+ sensitive=True,
+ visible=True,
+ state=IBus.PropState.UNCHECKED,
+ sub_props=None))
+ props.append(IBus.Property(key='InputMode.HalfWidthKatakana',
+ prop_type=IBus.PropType.RADIO,
+ label=IBus.Text.new_from_string(_("Halfwidth Katakana")),
+ icon=None,
+ tooltip=None,
+ sensitive=True,
+ visible=True,
+ state=IBus.PropState.UNCHECKED,
+ sub_props=None))
+ props.append(IBus.Property(key='InputMode.Latin',
+ prop_type=IBus.PropType.RADIO,
+ label=IBus.Text.new_from_string(_("Latin")),
+ icon=None,
+ tooltip=None,
+ sensitive=True,
+ visible=True,
+ state=IBus.PropState.UNCHECKED,
+ sub_props=None))
+ props.append(IBus.Property(key='InputMode.WideLatin',
+ prop_type=IBus.PropType.RADIO,
+ label=IBus.Text.new_from_string(_("Wide Latin")),
+ icon=None,
+ tooltip=None,
+ sensitive=True,
+ visible=True,
+ state=IBus.PropState.UNCHECKED,
+ sub_props=None))
+
+ props.get(Engine.__input_mode).set_state(IBus.PropState.CHECKED)
+
+ i = 0
+ while props.get(i) != None:
+ prop = props.get(i)
+ self.__prop_dict[prop.get_key()] = prop
+ i += 1
+
+ input_mode_prop.set_sub_props(props)
+ anthy_props.append(input_mode_prop)
+
+ mode = Engine.__input_mode
+ mode = 'InputMode.' + ['Hiragana', 'Katakana', 'HalfWidthKatakana',
+ 'Latin', 'WideLatin'][mode]
+ self.__input_mode_activate(mode, IBus.PropState.CHECKED)
+
+ def __set_typing_method_props(self, anthy_props):
+ if Engine.__typing_mode == None:
+ Engine.__typing_mode = jastring.TYPING_MODE_ROMAJI
+ Engine.__typing_mode = self.__prefs.get_value('common',
+ 'typing_method')
+
+ if not self.__prefs.get_value('common', 'show-typing-method'):
+ return
+
+ # typing input mode properties
+ symbol = 'R'
+ label = _("%(description)s (%(symbol)s)") % \
+ { 'description' : _("Typing method"), 'symbol' : symbol }
+ typing_mode_prop = IBus.Property(key='TypingMode',
+ prop_type=IBus.PropType.MENU,
+ label=IBus.Text.new_from_string(label),
+ symbol=IBus.Text.new_from_string(symbol),
+ icon='',
+ tooltip=IBus.Text.new_from_string(_("Switch typing method")),
+ sensitive=True,
+ visible=True,
+ state=IBus.PropState.UNCHECKED,
+ sub_props=None)
+ self.__prop_dict['TypingMode'] = typing_mode_prop
+
+ props = IBus.PropList()
+ props.append(IBus.Property(key='TypingMode.Romaji',
+ prop_type=IBus.PropType.RADIO,
+ label=IBus.Text.new_from_string(_("Romaji")),
+ icon=None,
+ tooltip=None,
+ sensitive=True,
+ visible=True,
+ state=IBus.PropState.UNCHECKED,
+ sub_props=None))
+ props.append(IBus.Property(key='TypingMode.Kana',
+ prop_type=IBus.PropType.RADIO,
+ label=IBus.Text.new_from_string(_("Kana")),
+ icon=None,
+ tooltip=None,
+ sensitive=True,
+ visible=True,
+ state=IBus.PropState.UNCHECKED,
+ sub_props=None))
+ props.append(IBus.Property(key='TypingMode.ThumbShift',
+ prop_type=IBus.PropType.RADIO,
+ label=IBus.Text.new_from_string(_("Thumb shift")),
+ icon=None,
+ tooltip=None,
+ sensitive=True,
+ visible=True,
+ state=IBus.PropState.UNCHECKED,
+ sub_props=None))
+ props.get(Engine.__typing_mode).set_state(IBus.PropState.CHECKED)
+
+ i = 0
+ while props.get(i) != None:
+ prop = props.get(i)
+ self.__prop_dict[prop.get_key()] = prop
+ i += 1
+
+ typing_mode_prop.set_sub_props(props)
+ anthy_props.append(typing_mode_prop)
+
+ mode = Engine.__typing_mode
+ mode = 'TypingMode.' + ['Romaji', 'Kana', 'ThumbShift'][mode]
+ self.__typing_mode_activate(mode, IBus.PropState.CHECKED)
+
+ def __set_segment_mode_props(self, anthy_props):
+ if Engine.__segment_mode == None:
+ Engine.__segment_mode = SEGMENT_DEFAULT
+ Engine.__segment_mode = self.__prefs.get_value('common',
+ 'conversion_segment_mode')
+
+ if not self.__prefs.get_value('common', 'show-segment-mode'):
+ return
+
+ symbol = '連'
+ label = _("%(description)s (%(symbol)s)") % \
+ { 'description' : _("Segment mode"), 'symbol' : symbol }
+ segment_mode_prop = IBus.Property(key='SegmentMode',
+ prop_type=IBus.PropType.MENU,
+ label=IBus.Text.new_from_string(label),
+ symbol=IBus.Text.new_from_string(symbol),
+ icon=None,
+ tooltip=IBus.Text.new_from_string(_("Switch conversion mode")),
+ sensitive=True,
+ visible=True,
+ state=IBus.PropState.UNCHECKED,
+ sub_props=None)
+ self.__prop_dict['SegmentMode'] = segment_mode_prop
+
+ props = IBus.PropList()
+ props.append(IBus.Property(key='SegmentMode.Multi',
+ prop_type=IBus.PropType.RADIO,
+ label=IBus.Text.new_from_string(_("Multiple segment")),
+ icon=None,
+ tooltip=None,
+ sensitive=True,
+ visible=True,
+ state=IBus.PropState.UNCHECKED,
+ sub_props=None))
+ props.append(IBus.Property(key='SegmentMode.Single',
+ prop_type=IBus.PropType.RADIO,
+ label=IBus.Text.new_from_string(_("Single segment")),
+ icon=None,
+ tooltip=None,
+ sensitive=True,
+ visible=True,
+ state=IBus.PropState.UNCHECKED,
+ sub_props=None))
+ props.append(IBus.Property(key='SegmentMode.ImmediateMulti',
+ prop_type=IBus.PropType.RADIO,
+ label=IBus.Text.new_from_string(_("Immediate conversion (multiple segment)")),
+ icon=None,
+ tooltip=None,
+ sensitive=True,
+ visible=True,
+ state=IBus.PropState.UNCHECKED,
+ sub_props=None))
+ props.append(IBus.Property(key='SegmentMode.ImmediateSingle',
+ prop_type=IBus.PropType.RADIO,
+ label=IBus.Text.new_from_string(_("Immediate conversion (single segment)")),
+ icon=None,
+ tooltip=None,
+ sensitive=True,
+ visible=True,
+ state=IBus.PropState.UNCHECKED,
+ sub_props=None))
+ props.get(Engine.__segment_mode).set_state(IBus.PropState.CHECKED)
+
+ i = 0
+ while props.get(i) != None:
+ prop = props.get(i)
+ self.__prop_dict[prop.get_key()] = prop
+ i += 1
+
+ segment_mode_prop.set_sub_props(props)
+ anthy_props.append(segment_mode_prop)
+
+ mode = Engine.__segment_mode
+ mode = 'SegmentMode.' + ['Multi', 'Single',
+ 'ImmediateMulti', 'ImmediateSingle'][mode]
+ self.__segment_mode_activate(mode, IBus.PropState.CHECKED)
+
+ def __set_dict_mode_props(self, anthy_props, update_prop=False):
+ if Engine.__dict_mode == None:
+ Engine.__dict_mode = 0
+
+ if not self.__prefs.get_value('common', 'show-dict-mode'):
+ return
+
+ short_label = self.__prefs.get_value('dict/file/embedded',
+ 'short_label')
+ label = _("%(description)s (%(symbol)s)") % \
+ { 'description' : _("Dictionary mode"), 'symbol' : short_label }
+ dict_mode_prop = IBus.Property(key='DictMode',
+ prop_type=IBus.PropType.MENU,
+ label=IBus.Text.new_from_string(label),
+ symbol=IBus.Text.new_from_string(short_label),
+ icon=None,
+ tooltip=IBus.Text.new_from_string(_("Switch dictionary")),
+ sensitive=True,
+ visible=True,
+ state=IBus.PropState.UNCHECKED,
+ sub_props=None)
+ self.__prop_dict['DictMode'] = dict_mode_prop
+ props = IBus.PropList()
+
+ long_label = self.__prefs.get_value('dict/file/embedded',
+ 'long_label')
+ props.append(IBus.Property(key='DictMode.embedded',
+ prop_type=IBus.PropType.RADIO,
+ # if long_label is UTF-8
+ label=IBus.Text.new_from_string(_(long_label)),
+ icon=None,
+ tooltip=None,
+ sensitive=True,
+ visible=True,
+ state=IBus.PropState.UNCHECKED,
+ sub_props=None))
+ for file in self.__prefs.get_value('dict', 'files'):
+ if not self.__link_dict_file(file):
+ continue
+ id = self.__get_dict_id_from_file(file)
+ section = 'dict/file/' + id
+ if not self.__prefs.get_value(section, 'single'):
+ continue
+ key = 'DictMode.' + id
+ long_label = self.__prefs.get_value(section, 'long_label')
+
+ # ibus-config 'value-changed' signal updated dict/files but
+ # not dict/file/new yet.
+ if long_label == None:
+ continue
+
+ if 'is_system' in self.__prefs.keys(section) and \
+ self.__prefs.get_value(section, 'is_system'):
+ uni_long_label = _(long_label)
+ else:
+ uni_long_label = long_label
+ props.append(IBus.Property(key=key,
+ prop_type=IBus.PropType.RADIO,
+ label=IBus.Text.new_from_string(uni_long_label),
+ icon=None,
+ tooltip=None,
+ sensitive=True,
+ visible=True,
+ state=IBus.PropState.UNCHECKED,
+ sub_props=None))
+
+ props.get(Engine.__dict_mode).set_state(IBus.PropState.CHECKED)
+
+ i = 0
+ while props.get(i) != None:
+ prop = props.get(i)
+ self.__prop_dict[prop.get_key()] = prop
+ i += 1
+
+ dict_mode_prop.set_sub_props(props)
+
+ if update_prop:
+ # focus-in event will call register_properties().
+ # Need to switch another IME to update menus on GtkStatusIcon?
+ anthy_props.update_property(dict_mode_prop)
+ else:
+ anthy_props.append(dict_mode_prop)
+
+ prop_name = self.__dict_mode_get_prop_name(Engine.__dict_mode)
+ if prop_name == None:
+ return
+ self.__dict_mode_activate(prop_name,
+ IBus.PropState.CHECKED)
+
+ def __set_dict_config_props(self, anthy_props):
+ if not self.__prefs.get_value('common', 'show-dict-config'):
+ return
+
+ admin_command = self.__prefs.get_value('common', 'dict_admin_command')
+ icon_path = self.__prefs.get_value('common', 'dict_config_icon')
+
+ if not path.exists(admin_command[0]):
+ return
+ label = _("Dictionary - Anthy")
+ if icon_path and path.exists(icon_path):
+ icon = icon_path
+ else:
+ # Translators: "Dic" means 'dictionary', One kanji may be good.
+ label = _("Dic")
+ icon = ''
+
+ dict_prop = IBus.Property(key='setup-dict-kasumi',
+ prop_type=IBus.PropType.MENU,
+ label=IBus.Text.new_from_string(label),
+ icon=icon,
+ tooltip=IBus.Text.new_from_string(_("Configure dictionaries")),
+ sensitive=True,
+ visible=True,
+ state=IBus.PropState.UNCHECKED,
+ sub_props=None)
+ self.__prop_dict['setup-dict-kasumi'] = dict_prop
+
+ props = IBus.PropList()
+ props.append(IBus.Property(key='setup-dict-kasumi-admin',
+ prop_type=IBus.PropType.NORMAL,
+ label=IBus.Text.new_from_string(_("Edit dictionaries")),
+ icon=icon,
+ tooltip=IBus.Text.new_from_string(_("Launch the dictionary tool")),
+ sensitive=True,
+ visible=True,
+ state=IBus.PropState.UNCHECKED,
+ sub_props=None))
+ props.append(IBus.Property(key='setup-dict-kasumi-word',
+ prop_type=IBus.PropType.NORMAL,
+ label=IBus.Text.new_from_string(_("Add words")),
+ icon=icon,
+ tooltip=IBus.Text.new_from_string(_("Add words to the dictionary")),
+ sensitive=True,
+ visible=True,
+ state=IBus.PropState.UNCHECKED,
+ sub_props=None))
+
+ i = 0
+ while props.get(i) != None:
+ prop = props.get(i)
+ self.__prop_dict[prop.get_key()] = prop
+ i += 1
+
+ dict_prop.set_sub_props(props)
+ anthy_props.append(dict_prop)
+
+ def __get_clipboard(self, clipboard, text, data):
+ clipboard_text = clipboard.wait_for_text ()
+
+ if data == CLIPBOARD_RECONVERT:
+ self.__update_reconvert(clipboard_text)
+
+ return clipboard_text
+
+ def __get_single_dict_files(self):
+ files = self.__prefs.get_value('dict', 'files')
+ single_files = []
+ for file in files:
+ if not path.exists(file):
+ continue
+ id = self.__get_dict_id_from_file(file)
+ section = 'dict/file/' + id
+ if self.__prefs.get_value(section, 'single'):
+ single_files.append(file)
+ return single_files
+
+ def __remove_dict_files(self):
+ for file in self.__prefs.get_value('dict', 'files'):
+ self.__remove_dict_file(file)
+
+ def update_preedit(self, string, attrs, cursor_pos, visible):
+ text = IBus.Text.new_from_string(string)
+ i = 0
+ while attrs.get(i) != None:
+ attr = attrs.get(i)
+ text.append_attribute(attr.get_attr_type(),
+ attr.get_value(),
+ attr.get_start_index(),
+ attr.get_end_index())
+ i += 1
+ mode = self.__prefs.get_value('common', 'behavior_on_focus_out')
+ if self.__get_ibus_version() >= 1.003 and mode == 1:
+ self.update_preedit_text_with_mode(text,
+ cursor_pos, visible,
+ IBus.PreeditFocusMode.COMMIT)
+ else:
+ self.update_preedit_text(text,
+ cursor_pos, visible)
+
+ def update_aux_string(self, string, attrs, visible):
+ text = IBus.Text.new_from_string(string)
+ i = 0
+ while attrs.get(i) != None:
+ attr = attrs.get(i)
+ text.append_attribute(attr.get_attr_type(),
+ attr.get_value(),
+ attr.get_start_index(),
+ attr.get_end_index())
+ i += 1
+ self.update_auxiliary_text(text, visible)
+
+ def do_page_up(self):
+ # only process cursor down in convert mode
+ if self.__convert_mode != CONV_MODE_ANTHY:
+ return False
+
+ if not self.__lookup_table.page_up():
+ return False
+
+ index = self.__lookup_table.get_cursor_pos()
+ candidate = self.__lookup_table.get_candidate(index).get_text()
+ self.__segments[self.__cursor_pos] = index, candidate
+ self.__invalidate()
+ return True
+
+ def do_page_down(self):
+ # only process cursor down in convert mode
+ if self.__convert_mode != CONV_MODE_ANTHY:
+ return False
+
+ if not self.__lookup_table.page_down():
+ return False
+
+ index = self.__lookup_table.get_cursor_pos()
+ candidate = self.__lookup_table.get_candidate(index).get_text()
+ self.__segments[self.__cursor_pos] = index, candidate
+ self.__invalidate()
+ return True
+
+ def do_cursor_up(self):
+ # only process cursor down in convert mode
+ # if self.__convert_mode != CONV_MODE_ANTHY:
+ if self.__convert_mode != CONV_MODE_ANTHY and self.__convert_mode != CONV_MODE_PREDICTION:
+ return False
+
+ if not self.__lookup_table.cursor_up():
+ return False
+
+ index = self.__lookup_table.get_cursor_pos()
+ candidate = self.__lookup_table.get_candidate(index).get_text()
+ self.__segments[self.__cursor_pos] = index, candidate
+ self.__invalidate()
+ return True
+
+ def do_cursor_down(self):
+ # only process cursor down in convert mode
+ # if self.__convert_mode != CONV_MODE_ANTHY:
+ if self.__convert_mode != CONV_MODE_ANTHY and self.__convert_mode != CONV_MODE_PREDICTION:
+ return False
+
+ if not self.__lookup_table.cursor_down():
+ return False
+
+ index = self.__lookup_table.get_cursor_pos()
+ candidate = self.__lookup_table.get_candidate(index).get_text()
+ self.__segments[self.__cursor_pos] = index, candidate
+ self.__invalidate()
+ return True
+
+ def do_candidate_clicked(self, index, button, state):
+ if index == 9:
+ keyval = IBus.KEY_0
+ else:
+ keyval = IBus.KEY_1 + index
+ self.__on_key_number(keyval)
+
+ def __commit_string(self, text):
+ self.__reset()
+ self.commit_text(IBus.Text.new_from_string(text))
+ self.__invalidate()
+
+ def __shrink_segment(self, relative_size):
+ self.__context.resize_segment(self.__cursor_pos, relative_size)
+ nr_segments = self.__context.get_nr_segments()
+ del self.__segments[self.__cursor_pos:]
+ for i in range(self.__cursor_pos, nr_segments):
+ buf = self.__context.get_segment(i, 0)
+ text = buf
+ self.__segments.append((0, text))
+ self.__lookup_table_visible = False
+ self.__fill_lookup_table()
+ self.__invalidate()
+ return True
+
+ def do_property_activate(self, prop_name, state):
+
+ if state == IBus.PropState.CHECKED:
+ if prop_name == None:
+ return
+ elif prop_name.startswith('InputMode.'):
+ self.__input_mode_activate(prop_name, state)
+ return
+ elif prop_name.startswith('TypingMode.'):
+ self.__typing_mode_activate(prop_name, state)
+ return
+ elif prop_name.startswith('SegmentMode.'):
+ self.__segment_mode_activate(prop_name, state)
+ return
+ elif prop_name.startswith('DictMode.'):
+ self.__dict_mode_activate(prop_name, state)
+ return
+ else:
+ if prop_name == 'setup':
+ self.__start_setup()
+ elif prop_name == 'setup-dict-kasumi-admin':
+ self.__start_dict_admin()
+ elif prop_name == 'setup-dict-kasumi-word':
+ self.__start_add_word()
+ else:
+ self.__prop_dict[prop_name].set_state(state)
+ if prop_name == 'DictMode':
+ sub_name = self.__dict_mode_get_prop_name(self.__dict_mode)
+ if sub_name == None:
+ return
+ self.__dict_mode_activate(sub_name,
+ IBus.PropState.CHECKED)
+
+ def __input_mode_activate(self, prop_name, state):
+ input_modes = {
+ 'InputMode.Hiragana' : (INPUT_MODE_HIRAGANA, 'あ'),
+ 'InputMode.Katakana' : (INPUT_MODE_KATAKANA, 'ア'),
+ 'InputMode.HalfWidthKatakana' : (INPUT_MODE_HALF_WIDTH_KATAKANA, '_ア'),
+ 'InputMode.Latin' : (INPUT_MODE_LATIN, '_A'),
+ 'InputMode.WideLatin' : (INPUT_MODE_WIDE_LATIN, 'A'),
+ }
+
+ if prop_name not in input_modes:
+ printerr('Unknown prop_name = %s' % prop_name)
+ return
+ self.__prop_dict[prop_name].set_state(state)
+ self.update_property(self.__prop_dict[prop_name])
+
+ mode, symbol = input_modes[prop_name]
+
+ label = _("%(description)s (%(symbol)s)") % \
+ { 'description' : _("Input mode"), 'symbol' : symbol }
+ Engine.__input_mode = mode
+ prop = self.__prop_dict['InputMode']
+ prop.set_symbol(IBus.Text.new_from_string(symbol))
+ prop.set_label(IBus.Text.new_from_string(label))
+ self.update_property(prop)
+
+ self.__reset()
+ self.__invalidate()
+
+ def __typing_mode_activate(self, prop_name, state):
+ typing_modes = {
+ 'TypingMode.Romaji' : (jastring.TYPING_MODE_ROMAJI, 'R'),
+ 'TypingMode.Kana' : (jastring.TYPING_MODE_KANA, 'か'),
+ 'TypingMode.ThumbShift' : (jastring.TYPING_MODE_THUMB_SHIFT, '親'),
+ }
+
+ if prop_name not in typing_modes:
+ printerr('Unknown prop_name = %s' % prop_name)
+ return
+ self.__prop_dict[prop_name].set_state(state)
+ self.update_property(self.__prop_dict[prop_name])
+ if prop_name == 'TypingMode.ThumbShift':
+ self._reset_thumb()
+
+ mode, symbol = typing_modes[prop_name]
+
+ label = _("%(description)s (%(symbol)s)") % \
+ { 'description' : _("Typing method"), 'symbol' : symbol }
+ Engine.__typing_mode = mode
+ prop = self.__prop_dict['TypingMode']
+ prop.set_symbol(IBus.Text.new_from_string(symbol))
+ prop.set_label(IBus.Text.new_from_string(label))
+ self.update_property(prop)
+
+ self.__reset()
+ self.__invalidate()
+
+ def __refresh_typing_mode_property(self):
+ if 'TypingMode' not in self.__prop_dict:
+ return
+
+ prop = self.__prop_dict['TypingMode']
+ modes = {
+ jastring.TYPING_MODE_ROMAJI : ('TypingMode.Romaji', 'R'),
+ jastring.TYPING_MODE_KANA : ('TypingMode.Kana', 'か'),
+ jastring.TYPING_MODE_THUMB_SHIFT : ('TypingMode.ThumbShift', '親'),
+ }
+ prop_name, symbol = modes.get(Engine.__typing_mode, (None, None))
+ if prop_name == None or symbol == None:
+ return
+ label = _("%(description)s (%(symbol)s)") % \
+ { 'description' : _("Typing method"), 'symbol' : symbol }
+ _prop = self.__prop_dict[prop_name]
+ _prop.set_state(IBus.PropState.CHECKED)
+ self.update_property(_prop)
+ prop.set_symbol(IBus.Text.new_from_string(symbol))
+ prop.set_label(IBus.Text.new_from_string(label))
+ self.update_property(prop)
+
+ def __segment_mode_activate(self, prop_name, state):
+ segment_modes = {
+ 'SegmentMode.Multi' : (SEGMENT_DEFAULT, '連'),
+ 'SegmentMode.Single' : (SEGMENT_SINGLE, '単'),
+ 'SegmentMode.ImmediateMulti' : (SEGMENT_IMMEDIATE, '逐|連'),
+ 'SegmentMode.ImmediateSingle' :
+ (SEGMENT_IMMEDIATE | SEGMENT_SINGLE, '逐|単'),
+ }
+
+ if prop_name not in segment_modes:
+ printerr('Unknown prop_name = %s' % prop_name)
+ return
+ self.__prop_dict[prop_name].set_state(state)
+ self.update_property(self.__prop_dict[prop_name])
+
+ mode, symbol = segment_modes[prop_name]
+
+ label = _("%(description)s (%(symbol)s)") % \
+ { 'description' : _("Segment mode"), 'symbol' : symbol }
+ Engine.__segment_mode = mode
+ prop = self.__prop_dict['SegmentMode']
+ prop.set_symbol(IBus.Text.new_from_string(symbol))
+ prop.set_label(IBus.Text.new_from_string(label))
+ self.update_property(prop)
+
+ self.__reset()
+ self.__invalidate()
+
+ def __dict_mode_get_prop_name(self, mode):
+ if mode == 0:
+ id = 'embedded'
+ else:
+ single_files = self.__get_single_dict_files()
+ file = single_files[mode - 1]
+ id = self.__get_dict_id_from_file(file)
+ return 'DictMode.' + id
+
+ def __dict_mode_activate(self, prop_name, state):
+ if prop_name not in list(self.__prop_dict.keys()):
+ # The prop_name is added. Need to restart.
+ return
+ i = prop_name.find('.')
+ if i < 0:
+ return
+ # The id is already quoted.
+ id = prop_name[i + 1:]
+
+ file = None
+ single_files = self.__get_single_dict_files()
+
+ if id == 'embedded':
+ pass
+ else:
+ found = False
+ for file in single_files:
+ if id == self.__get_quoted_id(file):
+ found = True
+ break
+ if found == False:
+ return
+
+ if id == 'embedded':
+ dict_name = 'default'
+ Engine.__dict_mode = 0
+ else:
+ if file not in single_files:
+ printerr('Index error', file, single_files)
+ return
+ dict_name = 'ibus__' + id
+ Engine.__dict_mode = single_files.index(file) + 1
+ self.__prop_dict[prop_name].set_state(state)
+ self.update_property(self.__prop_dict[prop_name])
+ self.__context.init_personality()
+ # dict_name is unicode but the argument is str.
+ self.__context.do_set_personality(str(dict_name))
+
+ prop = self.__prop_dict['DictMode']
+ section = 'dict/file/' + id
+ symbol = self.__prefs.get_value(section, 'short_label')
+ label = _("%(description)s (%(symbol)s)") % \
+ { 'description' : _("Dictionary mode"), 'symbol' : symbol }
+ prop.set_symbol(IBus.Text.new_from_string(symbol))
+ prop.set_label(IBus.Text.new_from_string(label))
+ self.update_property(prop)
+
+ def __argb(self, a, r, g, b):
+ return ((a & 0xff)<<24) + ((r & 0xff) << 16) + ((g & 0xff) << 8) + (b & 0xff)
+
+ def __rgb(self, r, g, b):
+ return self.__argb(255, r, g, b)
+
+ def do_focus_in(self):
+ self.register_properties(self.__prop_list)
+ self.__refresh_typing_mode_property()
+ mode = self.__prefs.get_value('common', 'behavior_on_focus_out')
+ if mode == 2:
+ self.__update_input_chars()
+# self.__reset()
+# self.__invalidate()
+ size = self.__prefs.get_value('common', 'page_size')
+ if size != self.__lookup_table.get_page_size():
+ self.__lookup_table.set_page_size(size)
+
+ def do_focus_out(self):
+ if self.__has_input_purpose:
+ self.__input_purpose = 0
+ mode = self.__prefs.get_value('common', 'behavior_on_focus_out')
+ if mode == 0 or mode == 1:
+ self.__reset()
+ self.__invalidate()
+
+ def do_set_content_type(self, purpose, hints):
+ if self.__has_input_purpose:
+ self.__input_purpose = purpose
+
+ def do_disable(self):
+ self.__reset()
+ self.__invalidate()
+
+ def do_reset(self):
+ self.__reset()
+ self.__invalidate()
+
+ def __destroy(self, obj):
+ if self.__idle_id != 0:
+ GLib.source_remove(self.__idle_id)
+ self.__idle_id = 0
+ # It seems do_destroy() is called when launch_engine() is called.
+ #self.__remove_dict_files()
+ # It seems super.destroy() does not unref the engine.
+
+ def __join_all_segments(self):
+ while True:
+ nr_segments = self.__context.get_nr_segments()
+ seg = nr_segments - self.__cursor_pos
+
+ if seg > 1:
+ self.__context.resize_segment(self.__cursor_pos, 1)
+ else:
+ break
+
+ def __normalize_preedit(self, preedit):
+ if not self.__is_utf8:
+ return preedit
+ for key in list(romaji_normalize_rule.keys()):
+ if preedit.find(key) >= 0:
+ for value in romaji_normalize_rule[key]:
+ preedit = preedit.replace(key, value)
+ return preedit
+
+ # begine convert
+ def __begin_anthy_convert(self):
+ if Engine.__segment_mode & SEGMENT_IMMEDIATE:
+ self.__end_anthy_convert()
+ if self.__convert_mode == CONV_MODE_ANTHY:
+ return
+ self.__convert_mode = CONV_MODE_ANTHY
+
+# text, cursor = self.__preedit_ja_string.get_hiragana()
+ text, cursor = self.__preedit_ja_string.get_hiragana(True)
+
+ text = self.__normalize_preedit(text)
+ self.__context.set_string(text)
+ if Engine.__segment_mode & SEGMENT_SINGLE:
+ self.__join_all_segments()
+ nr_segments = self.__context.get_nr_segments()
+
+ for i in range(0, nr_segments):
+ buf = self.__context.get_segment(i, 0)
+ text = buf
+ self.__segments.append((0, text))
+
+ if Engine.__segment_mode & SEGMENT_IMMEDIATE:
+ self.__cursor_pos = nr_segments - 1
+ else:
+ self.__cursor_pos = 0
+ self.__fill_lookup_table()
+ self.__lookup_table_visible = False
+
+ def __end_anthy_convert(self):
+ if self.__convert_mode == CONV_MODE_OFF:
+ return
+
+ self.__convert_mode = CONV_MODE_OFF
+ self.__convert_chars = ''
+ self.__segments = list()
+ self.__cursor_pos = 0
+ self.__lookup_table.clear()
+ self.__lookup_table_visible = False
+
+ def __end_convert(self):
+ self.__end_anthy_convert()
+
+ # test case 'verudhi' can show U+3046 + U+309B and U+3094
+ def __candidate_cb(self, candidate):
+ if not self.__is_utf8:
+ return
+ for key in list(romaji_utf8_rule.keys()):
+ if candidate.find(key) >= 0:
+ for value in romaji_utf8_rule[key]:
+ candidate = candidate.replace(key, value)
+ self.__lookup_table.append_candidate(IBus.Text.new_from_string(candidate))
+
+ def __fill_lookup_table(self):
+ if self.__convert_mode == CONV_MODE_PREDICTION:
+ nr_predictions = self.__context.get_nr_predictions()
+
+ # fill lookup_table
+ self.__lookup_table.clear()
+ for i in range(0, seg_stat.nr_predictions):
+ buf = self.__context.get_prediction(i)
+ candidate = buf
+ self.__lookup_table.append_candidate(IBus.Text.new_from_string(candidate))
+ self.__candidate_cb(candidate)
+ return
+
+ # get segment stat
+ nr_candidates = self.__context.get_nr_candidates(self.__cursor_pos)
+
+ # fill lookup_table
+ self.__lookup_table.clear()
+ for i in range(0, nr_candidates):
+ buf = self.__context.get_segment(self.__cursor_pos, i)
+ candidate = buf
+ self.__lookup_table.append_candidate(IBus.Text.new_from_string(candidate))
+ self.__candidate_cb(candidate)
+
+
+ def __invalidate(self):
+ if self.__idle_id != 0:
+ return
+ self.__idle_id = GLib.idle_add(self.__update,
+ priority = GLib.PRIORITY_LOW)
+
+# def __get_preedit(self):
+ def __get_preedit(self, commit=False):
+ if Engine.__input_mode == INPUT_MODE_HIRAGANA:
+# text, cursor = self.__preedit_ja_string.get_hiragana()
+ text, cursor = self.__preedit_ja_string.get_hiragana(commit)
+ elif Engine.__input_mode == INPUT_MODE_KATAKANA:
+# text, cursor = self.__preedit_ja_string.get_katakana()
+ text, cursor = self.__preedit_ja_string.get_katakana(commit)
+ elif Engine.__input_mode == INPUT_MODE_HALF_WIDTH_KATAKANA:
+# text, cursor = self.__preedit_ja_string.get_half_width_katakana()
+ text, cursor = self.__preedit_ja_string.get_half_width_katakana(commit)
+ else:
+ text, cursor = '', 0
+ return text, cursor
+
+ def __update_input_chars(self):
+ text, cursor = self.__get_preedit()
+ attrs = IBus.AttrList()
+ attrs.append(IBus.attr_underline_new(
+ IBus.AttrUnderline.SINGLE, 0,
+ len(text)))
+
+ self.update_preedit(text,
+ attrs, cursor, not self.__preedit_ja_string.is_empty())
+ self.update_aux_string('', IBus.AttrList(), False)
+ self.update_lookup_table(self.__lookup_table,
+ self.__lookup_table_visible)
+
+ def __update_convert_chars(self):
+# if self.__convert_mode == CONV_MODE_ANTHY:
+ if self.__convert_mode == CONV_MODE_ANTHY or self.__convert_mode == CONV_MODE_PREDICTION:
+ self.__update_anthy_convert_chars()
+ return
+ if self.__convert_mode == CONV_MODE_HIRAGANA:
+# text, cursor = self.__preedit_ja_string.get_hiragana()
+ text, cursor = self.__preedit_ja_string.get_hiragana(True)
+ elif self.__convert_mode == CONV_MODE_KATAKANA:
+# text, cursor = self.__preedit_ja_string.get_katakana()
+ text, cursor = self.__preedit_ja_string.get_katakana(True)
+ elif self.__convert_mode == CONV_MODE_HALF_WIDTH_KATAKANA:
+# text, cursor = self.__preedit_ja_string.get_half_width_katakana()
+ text, cursor = self.__preedit_ja_string.get_half_width_katakana(True)
+ elif self.__convert_mode == CONV_MODE_LATIN_0:
+ text, cursor = self.__preedit_ja_string.get_latin()
+ if text == text.lower():
+ self.__convert_mode = CONV_MODE_LATIN_1
+ elif self.__convert_mode == CONV_MODE_LATIN_1:
+ text, cursor = self.__preedit_ja_string.get_latin()
+ text = text.lower()
+ elif self.__convert_mode == CONV_MODE_LATIN_2:
+ text, cursor = self.__preedit_ja_string.get_latin()
+ text = text.upper()
+ elif self.__convert_mode == CONV_MODE_LATIN_3:
+ text, cursor = self.__preedit_ja_string.get_latin()
+ text = text.capitalize()
+ elif self.__convert_mode == CONV_MODE_WIDE_LATIN_0:
+ text, cursor = self.__preedit_ja_string.get_wide_latin()
+ if text == text.lower():
+ self.__convert_mode = CONV_MODE_WIDE_LATIN_1
+ elif self.__convert_mode == CONV_MODE_WIDE_LATIN_1:
+ text, cursor = self.__preedit_ja_string.get_wide_latin()
+ text = text.lower()
+ elif self.__convert_mode == CONV_MODE_WIDE_LATIN_2:
+ text, cursor = self.__preedit_ja_string.get_wide_latin()
+ text = text.upper()
+ elif self.__convert_mode == CONV_MODE_WIDE_LATIN_3:
+ text, cursor = self.__preedit_ja_string.get_wide_latin()
+ text = text.capitalize()
+ self.__convert_chars = text
+ attrs = IBus.AttrList()
+ attrs.append(IBus.attr_underline_new(
+ IBus.AttrUnderline.SINGLE, 0, len(text)))
+ attrs.append(IBus.attr_background_new(self.__rgb(200, 200, 240),
+ 0, len(text)))
+ attrs.append(IBus.attr_foreground_new(self.__rgb(0, 0, 0),
+ 0, len(text)))
+ self.update_preedit(text, attrs, len(text), True)
+
+ self.update_aux_string('',
+ IBus.AttrList(), self.__lookup_table_visible)
+ self.update_lookup_table(self.__lookup_table,
+ self.__lookup_table_visible)
+
+ def __update_anthy_convert_chars(self):
+ self.__convert_chars = ''
+ pos = 0
+ for i, (seg_index, text) in enumerate(self.__segments):
+ self.__convert_chars += text
+ if i < self.__cursor_pos:
+ pos += len(text)
+ attrs = IBus.AttrList()
+ attrs.append(IBus.attr_underline_new(
+ IBus.AttrUnderline.SINGLE, 0, len(self.__convert_chars)))
+ attrs.append(IBus.attr_background_new(self.__rgb(200, 200, 240),
+ pos, pos + len(self.__segments[self.__cursor_pos][1])))
+ attrs.append(IBus.attr_foreground_new(self.__rgb(0, 0, 0),
+ pos, pos + len(self.__segments[self.__cursor_pos][1])))
+ self.update_preedit(self.__convert_chars, attrs, pos, True)
+ aux_string = '( %d / %d )' % (self.__lookup_table.get_cursor_pos() + 1, self.__lookup_table.get_number_of_candidates())
+ self.update_aux_string(aux_string,
+ IBus.AttrList(), self.__lookup_table_visible)
+ self.update_lookup_table(self.__lookup_table,
+ self.__lookup_table_visible)
+
+ def __update(self):
+ if self.__convert_mode == CONV_MODE_OFF:
+ self.__update_input_chars()
+ else:
+ self.__update_convert_chars()
+ self.__idle_id = 0
+
+ def __on_key_return(self):
+ if self.__preedit_ja_string.is_empty():
+ return False
+
+ if self.__convert_mode == CONV_MODE_OFF:
+# text, cursor = self.__get_preedit()
+ text, cursor = self.__get_preedit(True)
+ self.__commit_string(text)
+ elif self.__convert_mode == CONV_MODE_ANTHY:
+ for i, (seg_index, text) in enumerate(self.__segments):
+ self.__context.commit_segment(i, seg_index)
+ self.__commit_string(self.__convert_chars)
+ elif self.__convert_mode == CONV_MODE_PREDICTION:
+ self.__context.commit_prediction(self.__segments[0][0])
+ self.__commit_string(self.__convert_chars)
+ else:
+ self.__commit_string(self.__convert_chars)
+
+ return True
+
+ def __on_key_escape(self):
+ if self.__preedit_ja_string.is_empty():
+ return False
+ self.__reset()
+ self.__invalidate()
+ return True
+
+ def __on_key_back_space(self):
+ if self.__preedit_ja_string.is_empty():
+ return False
+
+ if self.__convert_mode != CONV_MODE_OFF:
+ if self.__lookup_table_visible:
+ if self.__lookup_table.get_number_of_candidates() > 0:
+ self.__lookup_table.set_cursor_pos(0)
+ candidate = self.__lookup_table.get_candidate(0).get_text()
+ self.__segments[self.__cursor_pos] = 0, candidate
+ self.__lookup_table_visible = False
+ elif self.__segments[self.__cursor_pos][0] != \
+ NTH_UNCONVERTED_CANDIDATE:
+ buf = self.__context.get_segment(self.__cursor_pos,
+ NTH_UNCONVERTED_CANDIDATE)
+ self.__segments[self.__cursor_pos] = \
+ NTH_UNCONVERTED_CANDIDATE, buf
+ #elif self._chk_mode('25'):
+ '''
+ # FIXME: Delete the last char in the active segment.
+ #
+ # If we are able to delete a char in the active segment,
+ # we also should be able to add a char in the active segment.
+ # Currently plain preedit, no segment mode, i.e.
+ # using self.__preedit_ja_string, can delete or add a char
+ # but anthy active segoment mode, i.e.
+ # using self.__segments, can not delete or add a char.
+ # Deleting a char could be easy here but adding a char is
+ # difficult because we need to update both self.__segments
+ # and self.__preedit_ja_string but self.__preedit_ja_string
+ # has no segment. To convert self.__segments to
+ # self.__preedit_ja_string, we may use the reconvert mode
+ # but no idea to convert keyvals to hiragana
+ # in self__on_key_common() with multiple key typings.
+
+ # Delete a char in the active segment
+ all_text = ''
+ nr_segments = self.__context.get_nr_segments()
+ for i in xrange(0, nr_segments):
+ buf = self.__context.get_segment(i,
+ NTH_UNCONVERTED_CANDIDATE)
+ text = buf
+ if i == self.__cursor_pos and len(text) > 0:
+ text = text[:len(text) - 1]
+ all_text += text
+
+ if all_text == '':
+ return
+
+ # Set self.__preedit_ja_string by anthy context.
+ self.__preedit_ja_string = jastring.JaString(Engine.__typing_mode,
+ self.__latin_with_shift)
+ self.__convert_chars = self.__normalize_preedit(all_text)
+ for i in xrange(0, len(self.__convert_chars)):
+ keyval = self.__convert_chars[i]
+ self.__preedit_ja_string.insert(chr(ord(keyval)))
+ self.__context.set_string(self.__convert_chars)
+
+ # Set self.__segments by anty context
+ # for editable self.__segments,
+ # save NTH_UNCONVERTED_CANDIDATE
+ nr_segments = self.__context.get_nr_segments()
+ if self.__cursor_pos >= nr_segments and \
+ nr_segments > 0:
+ self.__cursor_pos = nr_segments - 1
+ for i in xrange(self.__cursor_pos, nr_segments):
+ if i == self.__cursor_pos:
+ index = NTH_UNCONVERTED_CANDIDATE
+ else:
+ index = 0
+ buf = self.__context.get_segment(i,
+ index)
+ text = buf
+ self.__segments[i] = index, text
+
+ # Update self.__lookup_table
+ self.__fill_lookup_table()
+ '''
+ else:
+ self.__end_convert()
+ else:
+ self.__preedit_ja_string.remove_before()
+
+ self.__invalidate()
+ return True
+
+ def __on_key_delete(self):
+ if self.__preedit_ja_string.is_empty():
+ return False
+
+ if self.__convert_mode != CONV_MODE_OFF:
+ self.__end_convert()
+ else:
+ self.__preedit_ja_string.remove_after()
+
+ self.__invalidate()
+ return True
+
+ '''def __on_key_hiragana_katakana(self):
+ if self.__convert_mode == CONV_MODE_ANTHY:
+ self.__end_anthy_convert()
+
+ if Engine.__input_mode >= INPUT_MODE_HIRAGANA and \
+ Engine.__input_mode < INPUT_MODE_HALF_WIDTH_KATAKANA:
+ Engine.__input_mode += 1
+ else:
+ Engine.__input_mode = INPUT_MODE_HIRAGANA
+
+ modes = { INPUT_MODE_HIRAGANA: 'あ',
+ INPUT_MODE_KATAKANA: 'ア',
+ INPUT_MODE_HALF_WIDTH_KATAKANA: '_ア' }
+
+ prop = self.__prop_dict[u'InputMode']
+ label = modes[Engine.__input_mode]
+ prop.set_label(IBus.Text.new_from_string(label))
+ self.update_property(prop)
+
+ self.__invalidate()
+ return True'''
+
+ '''def __on_key_muhenka(self):
+ if self.__preedit_ja_string.is_empty():
+ return False
+
+ if self.__convert_mode == CONV_MODE_ANTHY:
+ self.__end_anthy_convert()
+
+ new_mode = CONV_MODE_HIRAGANA
+ if self.__convert_mode < CONV_MODE_WIDE_LATIN_3 and \
+ self.__convert_mode >= CONV_MODE_HIRAGANA :
+ self.__convert_mode += 1
+ else:
+ self.__convert_mode = CONV_MODE_HIRAGANA
+
+ self.__invalidate()
+
+ return True'''
+
+ '''def __on_key_henkan(self):
+ if self.__preedit_ja_string.is_empty():
+ return False
+ if self.__convert_mode != CONV_MODE_ANTHY:
+ self.__begin_anthy_convert()
+ self.__invalidate()
+ elif self.__convert_mode == CONV_MODE_ANTHY:
+ self.__lookup_table_visible = True
+ self.do_cursor_down()
+ return True'''
+
+ '''def __on_key_space(self, wide=False):
+ if Engine.__input_mode == INPUT_MODE_WIDE_LATIN or wide:
+ # Input Wide space U+3000
+ wide_char = symbol_rule[chr(IBus.KEY_space)]
+ self.__commit_string(wide_char)
+ return True
+
+ if self.__preedit_ja_string.is_empty():
+ if Engine.__input_mode in (INPUT_MODE_HIRAGANA, INPUT_MODE_KATAKANA):
+ # Input Wide space U+3000
+ wide_char = symbol_rule[chr(IBus.KEY_space)]
+ self.__commit_string(wide_char)
+ return True
+ else:
+ # Input Half space U+0020
+ self.__commit_string(chr(IBus.KEY_space))
+ return True
+
+ if self.__convert_mode != CONV_MODE_ANTHY:
+ self.__begin_anthy_convert()
+ self.__invalidate()
+ elif self.__convert_mode == CONV_MODE_ANTHY:
+ self.__lookup_table_visible = True
+ self.do_cursor_down()
+ return True'''
+
+ def __on_key_up(self):
+ if self.__preedit_ja_string.is_empty():
+ return False
+ self.__lookup_table_visible = True
+ self.do_cursor_up()
+ return True
+
+ def __on_key_down(self):
+ if self.__preedit_ja_string.is_empty():
+ return False
+ self.__lookup_table_visible = True
+ self.do_cursor_down()
+ return True
+
+ def __on_key_page_up(self):
+ if self.__preedit_ja_string.is_empty():
+ return False
+ if self.__lookup_table_visible == True:
+ self.do_page_up()
+ return True
+
+ def __on_key_page_down(self):
+ if self.__preedit_ja_string.is_empty():
+ return False
+ if self.__lookup_table_visible == True:
+ self.do_page_down()
+ return True
+
+ '''def __on_key_left(self):
+ if self.__preedit_ja_string.is_empty():
+ return False
+
+ if self.__convert_mode == CONV_MODE_OFF:
+ self.__preedit_ja_string.move_cursor(-1)
+ self.__invalidate()
+ return True
+
+ if self.__convert_mode != CONV_MODE_ANTHY:
+ return True
+
+ if self.__cursor_pos == 0:
+ return True
+ self.__cursor_pos -= 1
+ self.__lookup_table_visible = False
+ self.__fill_lookup_table()
+ self.__invalidate()
+ return True'''
+
+ def __on_key_right(self):
+ if self.__preedit_ja_string.is_empty():
+ return False
+
+ if self.__convert_mode == CONV_MODE_OFF:
+ self.__preedit_ja_string.move_cursor(1)
+ self.__invalidate()
+ return True
+
+ if self.__convert_mode != CONV_MODE_ANTHY:
+ return True
+
+ if self.__cursor_pos + 1 >= len(self.__segments):
+ return True
+
+ self.__cursor_pos += 1
+ self.__lookup_table_visible = False
+ self.__fill_lookup_table()
+ self.__invalidate()
+ return True
+
+ def __on_key_number(self, keyval):
+ if self.__convert_mode != CONV_MODE_ANTHY:
+ return False
+ if not self.__lookup_table_visible:
+ return False
+
+ if keyval == IBus.KEY_0:
+ keyval = IBus.KEY_9 + 1
+ index = keyval - IBus.KEY_1
+
+ return self.__on_candidate_index_in_page(index)
+
+ def __on_key_conv(self, mode):
+ if self.__preedit_ja_string.is_empty():
+ return False
+
+ if self.__convert_mode == CONV_MODE_ANTHY:
+ self.__end_anthy_convert()
+
+ if mode == 0 or mode == 1:
+ if self.__convert_mode == CONV_MODE_HIRAGANA + mode:
+ return True
+ self.__convert_mode = CONV_MODE_HIRAGANA + mode
+ elif mode == 2:
+ if self.__convert_mode == CONV_MODE_HALF_WIDTH_KATAKANA:
+ return True
+ self.__convert_mode = CONV_MODE_HALF_WIDTH_KATAKANA
+ elif mode == 3:
+ if CONV_MODE_WIDE_LATIN_0 <= self.__convert_mode <= CONV_MODE_WIDE_LATIN_3:
+ self.__convert_mode += 1
+ if self.__convert_mode > CONV_MODE_WIDE_LATIN_3:
+ self.__convert_mode = CONV_MODE_WIDE_LATIN_1
+ else:
+ self.__convert_mode = CONV_MODE_WIDE_LATIN_0
+ elif mode == 4:
+ if CONV_MODE_LATIN_0 <= self.__convert_mode <= CONV_MODE_LATIN_3:
+ self.__convert_mode += 1
+ if self.__convert_mode > CONV_MODE_LATIN_3:
+ self.__convert_mode = CONV_MODE_LATIN_1
+ else:
+ self.__convert_mode = CONV_MODE_LATIN_0
+ else:
+ printerr('Unkown convert mode (%d)!' % mode)
+ return False
+ self.__invalidate()
+ return True
+
+ def __on_key_common(self, keyval, state=0):
+
+ # If use-system-layout is FALSE in ibus 1.4.y or lower,
+ # ibus converts the keymap and ibus-anthy needed to use
+ # self.__commit_string
+ # ibus 1.5.y uses XKB directly so Latin mode can return FALSE.
+ if Engine.__input_mode == INPUT_MODE_LATIN:
+ return False
+
+ elif Engine.__input_mode == INPUT_MODE_WIDE_LATIN:
+ # Input Wide Latin chars
+ char = chr(keyval)
+ wide_char = None#symbol_rule.get(char, None)
+ if wide_char == None:
+ wide_char = unichar_half_to_full(char)
+ self.__commit_string(wide_char)
+ return True
+
+ # Input Japanese
+ if Engine.__segment_mode & SEGMENT_IMMEDIATE:
+ # Commit nothing
+ pass
+ elif self.__convert_mode == CONV_MODE_ANTHY:
+ for i, (seg_index, text) in enumerate(self.__segments):
+ self.__context.commit_segment(i, seg_index)
+ self.__commit_string(self.__convert_chars)
+ elif self.__convert_mode != CONV_MODE_OFF:
+ self.__commit_string(self.__convert_chars)
+
+ # 'n' + '\'' == 'nn' in romaji
+ if (keyval >= ord('A') and keyval <= ord('Z')) or \
+ (keyval >= ord('a') and keyval <= ord('z')):
+ shift = (state & IBus.ModifierType.SHIFT_MASK) != 0
+ else:
+ shift = False
+ self.__preedit_ja_string.set_shift(shift)
+ self.__preedit_ja_string.insert(chr(keyval))
+ if Engine.__segment_mode & SEGMENT_IMMEDIATE:
+ self.__begin_anthy_convert()
+ self.__invalidate()
+ return True
+
+#=======================================================================
+ @classmethod
+ def CONFIG_RELOADED(cls, bus):
+ if config.DEBUG:
+ print('RELOADED')
+ if not cls.__prefs:
+ cls.__prefs = AnthyPrefs(bus)
+ cls._init_prefs()
+
+ cls.__keybind = cls._mk_keybind()
+
+ jastring.JaString.SET_PREFS(cls.__prefs)
+
+ @classmethod
+ def CONFIG_VALUE_CHANGED(cls, bus, section, name, variant):
+ if config.DEBUG:
+ print('VALUE_CHAMGED =', section, name, variant)
+
+ if not section.startswith('engine/anthy'):
+ # This value is used for IBus.config.set_value only.
+ return
+
+ # The key was deleted by dconf.
+ # test case: update /desktop/ibus/engine/anthy/thumb/ls
+ # and reset the key with dconf direclty.
+ if variant.get_type_string() == '()':
+ cls.__prefs.undo_item(section, name)
+ return
+
+ value = cls.__prefs.variant_to_value(variant)
+ base_sec = section[len(cls.__prefs._prefix) + 1:]
+ sec = cls._get_shortcut_type()
+ if base_sec == sec:
+ cmd = '_Engine__cmd_' + name
+ old = cls.__prefs.get_value(sec, name)
+ value = value if value != [''] else []
+ for s in set(old).difference(value):
+ cls.__keybind.get(cls._s_to_key(s), []).remove(cmd)
+
+ keys = cls.__prefs.keys(sec)
+ for s in set(value).difference(old):
+ cls.__keybind.setdefault(cls._s_to_key(s), []).append(cmd)
+ cls.__keybind.get(cls._s_to_key(s)).sort(
+ key = lambda a: keys.index(a[13:]))
+ cls.__prefs.set_value(sec, name, value)
+ elif base_sec == 'common':
+ cls.__prefs.set_value(base_sec, name, value)
+ if name == 'shortcut_type':
+ cls.__keybind = cls._mk_keybind()
+ if name == 'latin_with_shift':
+ cls.__latin_with_shift = value
+ jastring.JaString.RESET(cls.__prefs, base_sec, name, value)
+ elif base_sec.startswith('kana_typing_rule'):
+ jastring.JaString.RESET(cls.__prefs, base_sec, name, value)
+
+ @classmethod
+ def _init_prefs(cls):
+ prefs = cls.__prefs
+ value = prefs.get_value('common', 'latin_with_shift')
+ cls.__latin_with_shift = value
+
+ @classmethod
+ def _mk_keybind(cls):
+ keybind = {}
+ sec = cls._get_shortcut_type()
+ for k in cls.__prefs.keys(sec):
+ cmd = '_Engine__cmd_' + k
+ for s in cls.__prefs.get_value(sec, k):
+ keybind.setdefault(cls._s_to_key(s), []).append(cmd)
+ return keybind
+
+ @classmethod
+ def _get_shortcut_type(cls):
+ try:
+ t = 'shortcut/' + cls.__prefs.get_value('common', 'shortcut_type')
+ except:
+ t = 'shortcut/default'
+ return t
+
+ @classmethod
+ def _s_to_key(cls, s):
+ keyval = IBus.keyval_from_name(s.split('+')[-1])
+ s = s.lower()
+ state = ('shift+' in s and IBus.ModifierType.SHIFT_MASK or 0) | (
+ 'ctrl+' in s and IBus.ModifierType.CONTROL_MASK or 0) | (
+ 'alt+' in s and IBus.ModifierType.MOD1_MASK or 0)
+ return cls._mk_key(keyval, state)
+
+ @classmethod
+ def _reset_thumb(cls):
+ if cls.__thumb == None:
+ import thumb
+ cls.__thumb = thumb.ThumbShiftKeyboard(cls.__prefs)
+
+ else:
+ cls.__thumb.reset()
+
+ @staticmethod
+ def _mk_key(keyval, state):
+ if state & (IBus.ModifierType.CONTROL_MASK | IBus.ModifierType.MOD1_MASK):
+ if keyval < 0xff and \
+ chr(keyval) in '!"#$%^\'()*+,-./:;<=>?@[\]^_`{|}~':
+ state |= IBus.ModifierType.SHIFT_MASK
+ elif IBus.KEY_a <= keyval <= IBus.KEY_z:
+ keyval -= (IBus.KEY_a - IBus.KEY_A)
+
+ return repr([int(state), int(keyval)])
+
+ def __process_key_event(self, obj, keyval, keycode, state):
+ try:
+ return self.__process_key_event_internal2(keyval, keycode, state)
+ except:
+ import traceback
+ traceback.print_exc()
+ return False
+
+ def __process_key_event_thumb(self, keyval, keycode, state):
+ if self.__thumb == None:
+ self._reset_thumb()
+
+ def on_timeout(keyval):
+ if self._MM:
+ insert(self.__thumb.get_char(self._MM)[self._SS])
+ else:
+ cmd_exec([0, RS(), LS()][self._SS])
+ self._H = None
+
+ def start(t):
+ self._H = GLib.timeout_add(t, on_timeout, keyval)
+
+ def stop():
+ if self._H:
+ GLib.source_remove(self._H)
+ self._H = None
+ return True
+ return False
+
+ def insert(keyval):
+ try:
+ self._MM = self._SS = 0
+ ret = self.__on_key_common(ord(keyval))
+ if (keyval in ',.、。' and
+ self.__prefs.get_value('common', 'behavior_on_period')):
+ return self.__cmd_convert(keyval, state)
+ return ret
+ except:
+ pass
+
+ def cmd_exec(keyval, state=0):
+ key = self._mk_key(keyval, state)
+ for cmd in self.__keybind.get(key, []):
+ if config.DEBUG:
+ print('cmd =', cmd)
+ try:
+ if getattr(self, cmd)(keyval, state):
+ return True
+ except:
+ printerr('Unknown command = %s' % cmd)
+ return False
+
+ def RS():
+ return self.__thumb.get_rs()
+
+ def LS():
+ return self.__thumb.get_ls()
+
+ def T1():
+ return self.__thumb.get_t1()
+
+ def T2():
+ return self.__thumb.get_t2()
+
+ state = state & (IBus.ModifierType.SHIFT_MASK |
+ IBus.ModifierType.CONTROL_MASK |
+ IBus.ModifierType.MOD1_MASK |
+ IBus.ModifierType.RELEASE_MASK)
+
+ if keyval in KP_Table and self.__prefs.get_value('common',
+ 'ten_key_mode'):
+ keyval = KP_Table[keyval]
+
+ if state & IBus.ModifierType.RELEASE_MASK:
+ if keyval == self._MM:
+ if stop():
+ insert(self.__thumb.get_char(self._MM)[self._SS])
+ self._MM = 0
+ elif (1 if keyval == RS() else 2) == self._SS:
+ if stop():
+ cmd_exec([0, RS(), LS()][self._SS])
+ self._SS = 0
+ if keyval in [RS(), LS()]:
+ self._RSS = 0
+ elif keyval == self._RMM:
+ self._RMM = 0
+ else:
+ if keyval in [LS(), RS()] and state == 0:
+ if self._SS:
+ stop()
+ cmd_exec([0, RS(), LS()][self._SS])
+ self._SS = 1 if keyval == RS() else 2
+ start(T1())
+ elif self._MM:
+ stop()
+ self._RMM = self._MM
+ self._RSS = 1 if keyval == RS() else 2
+ insert(self.__thumb.get_char(self._MM)[1 if keyval == RS() else 2])
+ else:
+ if self._RSS == (1 if keyval == RS() else 2):
+ if self._RMM:
+ insert(self.__thumb.get_char(self._RMM)[self._RSS])
+ else:
+ self._SS = 1 if keyval == RS() else 2
+ start(T1())
+ elif keyval in self.__thumb.get_chars() and state == 0:
+ if self._MM:
+ stop()
+ insert(self.__thumb.get_char(self._MM)[self._SS])
+ start(T2())
+ self._MM = keyval
+ elif self._SS:
+ stop()
+ self._RMM = keyval
+ self._RSS = self._SS
+ insert(self.__thumb.get_char(keyval)[self._SS])
+ else:
+ if self._RMM == keyval:
+ if self._RSS:
+ insert(self.__thumb.get_char(self._RMM)[self._RSS])
+ else:
+ if cmd_exec(keyval, state):
+ return True
+ start(T2())
+ self._MM = keyval
+ else:
+ if self._MM:
+ stop()
+ insert(self.__thumb.get_char(self._MM)[self._SS])
+ elif self._SS:
+ stop()
+ cmd_exec([0, RS(), LS()][self._SS])
+ if cmd_exec(keyval, state):
+ return True
+ elif 0x21 <= keyval <= 0x7e and state & \
+ (IBus.ModifierType.CONTROL_MASK | IBus.ModifierType.MOD1_MASK) == 0:
+ if state & IBus.ModifierType.SHIFT_MASK:
+ insert(self.__thumb.get_shift_char(keyval, chr(keyval)))
+ elif self._SS == 0:
+ insert(chr(keyval))
+ else:
+ if not self.__preedit_ja_string.is_empty():
+ return True
+ return False
+ return True
+
+ def __process_key_event_internal2(self, keyval, keycode, state):
+ if self.__has_input_purpose and \
+ self.__input_purpose == IBus.InputPurpose.PASSWORD:
+ return False
+
+ if Engine.__typing_mode == jastring.TYPING_MODE_THUMB_SHIFT and \
+ Engine.__input_mode not in [INPUT_MODE_LATIN, INPUT_MODE_WIDE_LATIN]:
+ return self.__process_key_event_thumb(keyval, keycode, state)
+
+ is_press = (state & IBus.ModifierType.RELEASE_MASK) == 0
+
+ state = state & (IBus.ModifierType.SHIFT_MASK |
+ IBus.ModifierType.CONTROL_MASK |
+ IBus.ModifierType.MOD1_MASK)
+
+ # ignore key release events
+ if not is_press:
+ return False
+
+ if keyval in KP_Table and self.__prefs.get_value('common',
+ 'ten_key_mode'):
+ keyval = KP_Table[keyval]
+
+ key = self._mk_key(keyval, state)
+ for cmd in self.__keybind.get(key, []):
+ if config.DEBUG:
+ print('cmd =', cmd)
+ try:
+ if getattr(self, cmd)(keyval, state):
+ return True
+ except:
+ printerr('Unknown command = %s' % cmd)
+
+ # If input mode is not LATIN, eat Ctrl+Shift+u
+ hex_mod_mask = IBus.ModifierType.SHIFT_MASK | \
+ IBus.ModifierType.CONTROL_MASK
+ if Engine.__input_mode != INPUT_MODE_LATIN and \
+ keyval == IBus.KEY_U and \
+ state & hex_mod_mask == hex_mod_mask:
+ return True
+
+ if state & (IBus.ModifierType.CONTROL_MASK | IBus.ModifierType.MOD1_MASK):
+ return False
+
+ if (IBus.KEY_exclam <= keyval <= IBus.KEY_asciitilde or
+ keyval == IBus.KEY_yen):
+ if Engine.__typing_mode == jastring.TYPING_MODE_KANA:
+ if keyval == IBus.KEY_0 and state == IBus.ModifierType.SHIFT_MASK:
+ keyval = IBus.KEY_asciitilde
+ elif keyval == IBus.KEY_backslash and keycode in [132-8, 133-8]:
+ keyval = IBus.KEY_yen
+ ret = self.__on_key_common(keyval, state)
+ if (Engine.__input_mode != INPUT_MODE_LATIN and
+ chr(keyval) in ',.' and
+ self.__prefs.get_value('common', 'behavior_on_period')):
+ return self.__cmd_convert(keyval, state)
+ return ret
+ else:
+ if not self.__preedit_ja_string.is_empty():
+ return True
+ return False
+
+ def _chk_mode(self, mode):
+ if '0' in mode and self.__preedit_ja_string.is_empty():
+ return True
+
+ if self.__convert_mode == CONV_MODE_OFF:
+ if '1' in mode and not self.__preedit_ja_string.is_empty():
+ return True
+ elif self.__convert_mode == CONV_MODE_ANTHY:
+ if '2' in mode and not self.__lookup_table_visible:
+ return True
+ elif self.__convert_mode == CONV_MODE_PREDICTION:
+ if '3' in mode and not self.__lookup_table_visible:
+ return True
+ else:
+ if '4' in mode:
+ return True
+
+ if '5' in mode and self.__lookup_table_visible:
+ return True
+
+ return False
+
+ def __get_quoted_id(self, file):
+ id = file
+ has_mbcs = False
+
+ for i in range(0, len(id)):
+ if ord(id[i]) >= 0x7f:
+ has_mbcs = True
+ break
+ if has_mbcs:
+ id = str(binascii.hexlify(id.encode()), 'ascii')
+
+ if id.find('/') >=0:
+ id = id[id.rindex('/') + 1:]
+ if id.find('.') >=0:
+ id = id[:id.rindex('.')]
+
+ if id.startswith('0x'):
+ id = str(binascii.hexlify(id.encode()), 'ascii')
+ has_mbcs = True
+ if has_mbcs:
+ id = '0x' + id
+ return id
+
+ def __get_dict_id_from_file(self, file):
+ return self.__get_quoted_id(file)
+
+ def __link_dict_file_with_id(self, file, id, link_mode):
+ if id == None:
+ return
+ if link_mode == LINK_DICT_EMBEDDED:
+ directory = get_userhome() + '/.anthy/' + IMPORTED_EMBEDDED_DICT_DIR
+ name = IMPORTED_EMBEDDED_DICT_PREFIX + id
+ elif link_mode == LINK_DICT_SINGLE:
+ directory = get_userhome() + '/.anthy'
+ name = IMPORTED_SINGLE_DICT_PREFIX + id
+ else:
+ return
+ if path.exists(directory):
+ if not path.isdir(directory):
+ printerr(directory + ' is not a directory')
+ return
+ else:
+ os.makedirs(directory, 0o700)
+ backup_dir = os.getcwd()
+ os.chdir(directory)
+ if path.lexists(directory + '/' + name):
+ if path.islink(directory + '/' + name):
+ printerr('Removing ' + name)
+ os.unlink(directory + '/' + name)
+ else:
+ alternate = name + str(os.getpid())
+ printerr('Moving ' + name + ' to ' + alternate)
+ os.rename(name, alternate)
+ os.symlink(file, directory + '/' + name)
+ if backup_dir != None:
+ os.chdir(backup_dir)
+
+ def __remove_dict_file_with_id(self, file, id, link_mode):
+ if id == None:
+ return
+ if link_mode == LINK_DICT_EMBEDDED:
+ directory = get_userhome() + '/.anthy/' + IMPORTED_EMBEDDED_DICT_DIR
+ name = IMPORTED_EMBEDDED_DICT_PREFIX + id
+ elif link_mode == LINK_DICT_SINGLE:
+ directory = get_userhome() + '/.anthy'
+ name = IMPORTED_SINGLE_DICT_PREFIX + id
+ else:
+ return
+ if path.exists(directory):
+ if not path.isdir(directory):
+ printerr(directory + ' is not a directory')
+ return
+ backup_dir = os.getcwd()
+ os.chdir(directory)
+ if path.lexists(directory + '/' + name):
+ os.unlink(directory + '/' + name)
+ if backup_dir != None:
+ os.chdir(backup_dir)
+
+ def __link_dict_file(self, file):
+ if not path.exists(file):
+ printerr(file + ' does not exist')
+ return False
+ id = self.__get_dict_id_from_file(file)
+ section = 'dict/file/' + id
+ if section not in self.__prefs.sections():
+ self.__fetch_dict_values(section)
+ if self.__prefs.get_value(section, 'embed'):
+ self.__link_dict_file_with_id(file, id, LINK_DICT_EMBEDDED)
+ if self.__prefs.get_value(section, 'single'):
+ self.__link_dict_file_with_id(file, id, LINK_DICT_SINGLE)
+ return True
+
+ def __remove_dict_file(self, file):
+ id = self.__get_dict_id_from_file(file)
+ section = 'dict/file/' + id
+ if section not in self.__prefs.sections():
+ self.__fetch_dict_values(section)
+ if self.__prefs.get_value(section, 'embed'):
+ self.__remove_dict_file_with_id(file, id, LINK_DICT_EMBEDDED)
+ if self.__prefs.get_value(section, 'single'):
+ self.__remove_dict_file_with_id(file, id, LINK_DICT_SINGLE)
+
+ def __set_dict_files_value(self, base_sec, name, value):
+ if name == 'files':
+ str_list = []
+ for file in value:
+ str_list.append(self.__prefs.str(file))
+ old_files = self.__prefs.get_value(base_sec, name)
+ for file in old_files:
+ if file in str_list:
+ continue
+ self.__remove_dict_file(file)
+ for file in str_list:
+ if file in old_files:
+ continue
+ self.__link_dict_file(file)
+ self.__prefs.set_value(base_sec, name, str_list)
+ else:
+ self.__prefs.set_value(base_sec, name, value)
+
+ def __fetch_dict_values(self, section):
+ self.__prefs.set_new_section(section)
+ self.__prefs.set_new_key(section, 'short_label')
+ self.__prefs.set_no_key_warning(True)
+ self.__prefs.fetch_item(section, 'short_label')
+ self.__prefs.set_new_key(section, 'long_label')
+ self.__prefs.fetch_item(section, 'long_label')
+ self.__prefs.set_new_key(section, 'embed')
+ self.__prefs.fetch_item(section, 'embed')
+ self.__prefs.set_new_key(section, 'single')
+ self.__prefs.fetch_item(section, 'single')
+ self.__prefs.set_new_key(section, 'reverse')
+ self.__prefs.fetch_item(section, 'reverse')
+ self.__prefs.set_no_key_warning(False)
+
+ def __config_value_changed_cb(self, ibus_config, section, name, variant):
+ if config.DEBUG:
+ print('VALUE_CHAMGED =', section, name, variant)
+
+ if not section.startswith('engine/anthy'):
+ # This value is used for IBus.config.set_value only.
+ return
+
+ # The key was deleted by dconf.
+ # test case: update /desktop/ibus/engine/anthy/thumb/ls
+ # and reset the key with dconf direclty.
+ if variant.get_type_string() == '()':
+ self.__prefs.undo_item(section, name)
+ return
+
+ value = self.__prefs.variant_to_value(variant)
+ base_sec = section[len(self.__prefs._prefix) + 1:]
+ sec = self._get_shortcut_type()
+
+ if base_sec == 'thumb':
+ self.__prefs.set_value(base_sec, name, value)
+ self._reset_thumb()
+ elif base_sec == 'dict':
+ self.__set_dict_files_value(base_sec, name, value)
+ self.__set_dict_mode_props(self.__prop_list, True)
+ elif base_sec.startswith('dict/file/'):
+ if base_sec not in self.__prefs.sections():
+ self.__fetch_dict_values(base_sec)
+ self.__prefs.set_value(base_sec, name, value)
+ self.__set_dict_mode_props(self.__prop_list, True)
+ elif base_sec:
+ self.__prefs.set_value(base_sec, name, value)
+ else:
+ self.__prefs.set_value(section, name, value)
+
+ #mod_keys
+ def __set_input_mode(self, mode):
+ self.__input_mode_activate(mode, IBus.PropState.CHECKED)
+ self.__reset()
+ self.__invalidate()
+
+ return True
+
+ def __unset_current_input_mode(self):
+ modes = {
+ INPUT_MODE_HIRAGANA: 'InputMode.Hiragana',
+ INPUT_MODE_KATAKANA: 'InputMode.Katakana',
+ INPUT_MODE_HALF_WIDTH_KATAKANA: 'InputMode.HalfWidthKatakana',
+ INPUT_MODE_LATIN: 'InputMode.Latin',
+ INPUT_MODE_WIDE_LATIN: 'InputMode.WideLatin'
+ }
+ self.__input_mode_activate(modes[Engine.__input_mode],
+ IBus.PropState.UNCHECKED)
+
+ def __cmd_on_off(self, keyval, state):
+ # ibus 1.5 or later needs to send UNCHECKED
+ self.__unset_current_input_mode()
+ if Engine.__input_mode == INPUT_MODE_LATIN:
+ return self.__set_input_mode('InputMode.Hiragana')
+ else:
+ return self.__set_input_mode('InputMode.Latin')
+
+ def __cmd_circle_input_mode(self, keyval, state):
+ modes = {
+ INPUT_MODE_HIRAGANA: 'InputMode.Katakana',
+ INPUT_MODE_KATAKANA: 'InputMode.HalfWidthKatakana',
+ INPUT_MODE_HALF_WIDTH_KATAKANA: 'InputMode.Latin',
+ INPUT_MODE_LATIN: 'InputMode.WideLatin',
+ INPUT_MODE_WIDE_LATIN: 'InputMode.Hiragana'
+ }
+ # ibus 1.5 or later needs to send UNCHECKED
+ self.__unset_current_input_mode()
+ return self.__set_input_mode(modes[Engine.__input_mode])
+
+ def __cmd_circle_kana_mode(self, keyval, state):
+ modes = {
+ INPUT_MODE_HIRAGANA: 'InputMode.Katakana',
+ INPUT_MODE_KATAKANA: 'InputMode.HalfWidthKatakana',
+ INPUT_MODE_HALF_WIDTH_KATAKANA: 'InputMode.Hiragana',
+ INPUT_MODE_LATIN: 'InputMode.Hiragana',
+ INPUT_MODE_WIDE_LATIN: 'InputMode.Hiragana'
+ }
+ # ibus 1.5 or later needs to send UNCHECKED
+ self.__unset_current_input_mode()
+ return self.__set_input_mode(modes[Engine.__input_mode])
+
+ def __cmd_latin_mode(self, keyval, state):
+ # ibus 1.5 or later needs to send UNCHECKED
+ self.__unset_current_input_mode()
+ return self.__set_input_mode('InputMode.Latin')
+
+ def __cmd_wide_latin_mode(self, keyval, state):
+ # ibus 1.5 or later needs to send UNCHECKED
+ self.__unset_current_input_mode()
+ return self.__set_input_mode('InputMode.WideLatin')
+
+ def __cmd_hiragana_mode(self, keyval, state):
+ # ibus 1.5 or later needs to send UNCHECKED
+ self.__unset_current_input_mode()
+ return self.__set_input_mode('InputMode.Hiragana')
+
+ def __cmd_katakana_mode(self, keyval, state):
+ # ibus 1.5 or later needs to send UNCHECKED
+ self.__unset_current_input_mode()
+ return self.__set_input_mode('InputMode.Katakana')
+
+ def __cmd_half_katakana(self, keyval, state):
+ # ibus 1.5 or later needs to send UNCHECKED
+ self.__unset_current_input_mode()
+ return self.__set_input_mode('InputMode.HalfWidthKatakana')
+
+# def __cmd_cancel_pseudo_ascii_mode_key(self, keyval, state):
+# pass
+
+ def __unset_current_typing_mode(self):
+ modes = {
+ jastring.TYPING_MODE_ROMAJI: 'TypingMode.Romaji',
+ jastring.TYPING_MODE_KANA: 'TypingMode.Kana',
+ jastring.TYPING_MODE_THUMB_SHIFT: 'TypingMode.ThumbShift',
+ }
+ self.__typing_mode_activate(modes[Engine.__typing_mode],
+ IBus.PropState.UNCHECKED)
+
+ def __cmd_circle_typing_method(self, keyval, state):
+ if not self._chk_mode('0'):
+ return False
+
+ modes = {
+ jastring.TYPING_MODE_THUMB_SHIFT: 'TypingMode.Romaji',
+ jastring.TYPING_MODE_KANA: 'TypingMode.ThumbShift',
+ jastring.TYPING_MODE_ROMAJI: 'TypingMode.Kana',
+ }
+ # ibus 1.5 or later needs to send UNCHECKED
+ self.__unset_current_typing_mode()
+ self.__typing_mode_activate(modes[Engine.__typing_mode],
+ IBus.PropState.CHECKED)
+ return True
+
+ def __cmd_circle_dict_method(self, keyval, state):
+ if not self._chk_mode('0'):
+ return False
+
+ # ibus 1.5 or later needs to send UNCHECKED
+ prop_name = self.__dict_mode_get_prop_name(Engine.__dict_mode)
+ if prop_name != None:
+ self.__dict_mode_activate(prop_name,
+ IBus.PropState.UNCHECKED)
+
+ single_files = self.__get_single_dict_files()
+ new_mode = Engine.__dict_mode + 1
+ if new_mode > len(single_files):
+ new_mode = 0
+ Engine.__dict_mode = new_mode
+ prop_name = self.__dict_mode_get_prop_name(Engine.__dict_mode)
+ if prop_name == None:
+ return False
+ self.__dict_mode_activate(prop_name,
+ IBus.PropState.CHECKED)
+ return True
+
+ #edit_keys
+ def __cmd_insert_space(self, keyval, state):
+ if Engine.__input_mode == INPUT_MODE_LATIN:
+ return False
+ if (self.__prefs.get_value('common', 'half_width_space') or
+ Engine.__input_mode == INPUT_MODE_HALF_WIDTH_KATAKANA):
+ return self.__cmd_insert_half_space(keyval, state)
+ else:
+ return self.__cmd_insert_wide_space(keyval, state)
+
+ def __cmd_insert_alternate_space(self, keyval, state):
+ if Engine.__input_mode == INPUT_MODE_LATIN:
+ return False
+ if (self.__prefs.get_value('common', 'half_width_space') or
+ Engine.__input_mode == INPUT_MODE_HALF_WIDTH_KATAKANA):
+ return self.__cmd_insert_wide_space(keyval, state)
+ else:
+ return self.__cmd_insert_half_space(keyval, state)
+
+ def __cmd_insert_half_space(self, keyval, state):
+ if not self._chk_mode('0'):
+ return False
+
+ if not self.__preedit_ja_string.is_empty():
+ return False
+ self.__commit_string(chr(IBus.KEY_space))
+ return True
+
+ def __cmd_insert_wide_space(self, keyval, state):
+ if not self._chk_mode('0'):
+ return False
+
+ if not self.__preedit_ja_string.is_empty():
+ return False
+ char = chr(IBus.KEY_space)
+ wide_char = symbol_rule.get(char, None)
+ if wide_char == None:
+ wide_char = unichar_half_to_full(char)
+ self.__commit_string(wide_char)
+ return True
+
+ def __cmd_backspace(self, keyval, state):
+ if not self._chk_mode('12345'):
+ return False
+
+ return self.__on_key_back_space()
+
+ def __cmd_delete(self, keyval, state):
+ if not self._chk_mode('12345'):
+ return False
+
+ return self.__on_key_delete()
+
+ def __cmd_commit(self, keyval, state):
+ if not self._chk_mode('12345'):
+ return False
+
+ return self.__on_key_return()
+
+ def __cmd_convert(self, keyval, state):
+ if not self._chk_mode('14'):
+ return False
+
+ self.__begin_anthy_convert()
+ self.__invalidate()
+
+ return True
+
+ def __cmd_predict(self, keyval, state):
+ if not self._chk_mode('14'):
+ return False
+
+ text, cursor = self.__preedit_ja_string.get_hiragana(True)
+
+ self.__context.set_prediction_string(text)
+ nr_predictions = self.__context.get_nr_predictions()
+
+# for i in range(nr_predictions):
+# print self.__context.get_prediction(i)
+
+ buf = self.__context.get_prediction(0)
+ if not buf:
+ return False
+
+ text = buf
+ self.__segments.append((0, text))
+
+ self.__convert_mode = CONV_MODE_PREDICTION
+ self.__cursor_pos = 0
+ self.__fill_lookup_table()
+ self.__lookup_table_visible = False
+ self.__invalidate()
+
+ return True
+
+ def __cmd_cancel(self, keyval, state):
+ return self.__cmd_cancel_all(keyval, state)
+
+ def __cmd_cancel_all(self, keyval, state):
+ if not self._chk_mode('12345'):
+ return False
+
+ if self.__convert_mode == CONV_MODE_OFF:
+ return self.__on_key_escape()
+ else:
+ self.__end_convert()
+ self.__invalidate()
+ return True
+
+ def __cmd_reconvert(self, keyval, state):
+ if not self.__preedit_ja_string.is_empty():
+ # if user has inputed some chars
+ return False
+
+ # Move importing Gtk into Engine from the header
+ # because ibus-engine-anthy --xml does not requre to open X.
+ try:
+ from gi.repository import Gtk
+ clipboard_get = Gtk.Clipboard.get
+ except ImportError:
+ clipboard_get = lambda a : None
+ except RuntimeError:
+ # Do we support the engine without display?
+ printerr("Gtk couldn't be initialized")
+ printerr('Could not open display')
+ clipboard_get = lambda a : None
+
+ # Use Gtk.Clipboard.request_text() instead of
+ # Gtk.Clipboard.wait_for_text() because DBus is timed out.
+ clipboard = clipboard_get ('PRIMARY')
+ if clipboard:
+ clipboard.request_text (self.__get_clipboard, CLIPBOARD_RECONVERT)
+
+ return True
+
+ def __update_reconvert(self, clipboard_text):
+ if clipboard_text == None:
+ return False
+
+ self.__convert_chars = clipboard_text
+ for i in range(0, len(self.__convert_chars)):
+ keyval = self.__convert_chars[i]
+ self.__preedit_ja_string.insert(chr(ord(keyval)))
+
+ self.__context.set_string(self.__convert_chars)
+ nr_segments = self.__context.get_nr_segments()
+
+ for i in range(0, nr_segments):
+ buf = self.__context.get_segment(i, 0)
+ text = buf
+ self.__segments.append((0, text))
+
+ self.__convert_mode = CONV_MODE_ANTHY
+ self.__cursor_pos = 0
+ self.__fill_lookup_table()
+ self.__lookup_table_visible = False
+ self.__invalidate()
+
+ return True
+
+# def __cmd_do_nothing(self, keyval, state):
+# return True
+
+ #caret_keys
+ def __move_caret(self, i):
+ if not self._chk_mode('1'):
+ return False
+
+ if self.__convert_mode == CONV_MODE_OFF:
+ self.__preedit_ja_string.move_cursor(
+ -len(self.__preedit_ja_string.get_latin()[0]) if i == 0 else
+ i if i in [-1, 1] else
+ len(self.__preedit_ja_string.get_latin()[0]))
+ self.__invalidate()
+ return True
+
+ return False
+
+ def __cmd_move_caret_first(self, keyval, state):
+ return self.__move_caret(0)
+
+ def __cmd_move_caret_last(self, keyval, state):
+ return self.__move_caret(2)
+
+ def __cmd_move_caret_forward(self, keyval, state):
+ return self.__move_caret(1)
+
+ def __cmd_move_caret_backward(self, keyval, state):
+ return self.__move_caret(-1)
+
+ #segments_keys
+ def __select_segment(self, i):
+ if not self._chk_mode('25'):
+ return False
+
+ pos = 0 if i == 0 else \
+ self.__cursor_pos + i if i in [-1, 1] else \
+ len(self.__segments) - 1
+
+ if 0 <= pos < len(self.__segments) and pos != self.__cursor_pos:
+ self.__cursor_pos = pos
+ self.__lookup_table_visible = False
+ self.__fill_lookup_table()
+ self.__invalidate()
+
+ return True
+
+ def __cmd_select_first_segment(self, keyval, state):
+ return self.__select_segment(0)
+
+ def __cmd_select_last_segment(self, keyval, state):
+ return self.__select_segment(2)
+
+ def __cmd_select_next_segment(self, keyval, state):
+ return self.__select_segment(1)
+
+ def __cmd_select_prev_segment(self, keyval, state):
+ return self.__select_segment(-1)
+
+ def __cmd_shrink_segment(self, keyval, state):
+ if not self._chk_mode('25'):
+ return False
+
+ if self.__convert_mode == CONV_MODE_ANTHY:
+ self.__shrink_segment(-1)
+ return True
+
+ def __cmd_expand_segment(self, keyval, state):
+ if not self._chk_mode('25'):
+ return False
+
+ if self.__convert_mode == CONV_MODE_ANTHY:
+ self.__shrink_segment(1)
+ return True
+
+ def __move_cursor_char_length(self, length):
+ if Engine.__input_mode == INPUT_MODE_HIRAGANA:
+ self.__preedit_ja_string.move_cursor_hiragana_length(length)
+ elif Engine.__input_mode == INPUT_MODE_KATAKANA:
+ self.__preedit_ja_string.move_cursor_katakana_length(length)
+ elif Engine.__input_mode == INPUT_MODE_HALF_WIDTH_KATAKANA:
+ self.__preedit_ja_string.move_cursor_half_with_katakana_length(length)
+ else:
+ self.__preedit_ja_string.move_cursor(length)
+
+ def __commit_nth_segment(self, commit_index, keyval, state):
+
+ if commit_index >= len(self.__segments):
+ return False
+
+ if self.__convert_mode == CONV_MODE_ANTHY:
+ for i in range(0, commit_index + 1):
+ (seg_index, text) = self.__segments[i]
+ self.commit_text(IBus.Text.new_from_string(text))
+
+ text, cursor = self.__get_preedit()
+ commit_length = 0
+ for i in range(0, commit_index + 1):
+ buf = self.__context.get_segment(i, NTH_UNCONVERTED_CANDIDATE)
+ commit_length += len(buf)
+ self.__move_cursor_char_length(commit_length - cursor)
+ for i in range(0, commit_length):
+ self.__preedit_ja_string.remove_before()
+ self.__move_cursor_char_length(cursor - commit_length)
+
+ del self.__segments[0:commit_index + 1]
+
+ if len(self.__segments) == 0:
+ self.__reset()
+ else:
+ if self.__cursor_pos > commit_index:
+ self.__cursor_pos -= (commit_index + 1)
+ else:
+ self.__cursor_pos = 0
+ text, cursor = self.__get_preedit()
+ self.__convert_chars = text
+ self.__context.set_string(text)
+
+ self.__lookup_table.clear()
+ self.__lookup_table.set_cursor_visible(False)
+ self.__lookup_table_visible = False
+ self.update_aux_string('', IBus.AttrList(),
+ self.__lookup_table_visible)
+ self.__fill_lookup_table()
+ self.__invalidate()
+ self.__update_input_chars()
+
+ return True
+
+ def __cmd_commit_first_segment(self, keyval, state):
+ return self.__commit_nth_segment(0, keyval, state)
+
+ def __cmd_commit_selected_segment(self, keyval, state):
+ return self.__commit_nth_segment(self.__cursor_pos, keyval, state)
+
+ #candidates_keys
+ def __on_candidate_index_in_page(self, index):
+ if not self._chk_mode('5'):
+ return False
+
+ if index >= self.__lookup_table.get_page_size():
+ return False
+ cursor_pos = self.__lookup_table.get_cursor_pos()
+ cursor_in_page = self.__lookup_table.get_cursor_in_page()
+ real_index = cursor_pos - cursor_in_page + index
+ if real_index >= self.__lookup_table.get_number_of_candidates():
+ return False
+ self.__lookup_table.set_cursor_pos(real_index)
+ index = self.__lookup_table.get_cursor_pos()
+ candidate = self.__lookup_table.get_candidate(index).get_text()
+ self.__segments[self.__cursor_pos] = index, candidate
+ self.__lookup_table_visible = False
+ self.__on_key_right()
+ self.__invalidate()
+ return True
+
+ def __cmd_select_first_candidate(self, keyval, state):
+ return self.__on_candidate_index_in_page(0)
+
+ def __cmd_select_last_candidate(self, keyval, state):
+ return self.__on_candidate_index_in_page(
+ self.__lookup_table.get_page_size() - 1)
+
+ def __cmd_select_next_candidate(self, keyval, state):
+ if not self._chk_mode('235'):
+ return False
+
+ return self.__on_key_down()
+
+ def __cmd_select_prev_candidate(self, keyval, state):
+ if not self._chk_mode('235'):
+ return False
+
+ return self.__on_key_up()
+
+ def __cmd_candidates_page_up(self, keyval, state):
+ if not self._chk_mode('5'):
+ return False
+
+ return self.__on_key_page_up()
+
+ def __cmd_candidates_page_down(self, keyval, state):
+ if not self._chk_mode('5'):
+ return False
+
+ return self.__on_key_page_down()
+
+ #direct_select_keys
+ def __select_keyval(self, keyval):
+ if not self._chk_mode('5'):
+ return False
+
+ return self.__on_key_number(keyval)
+
+ def __cmd_select_candidates_1(self, keyval, state):
+ return self.__select_keyval(keyval)
+
+ def __cmd_select_candidates_2(self, keyval, state):
+ return self.__select_keyval(keyval)
+
+ def __cmd_select_candidates_3(self, keyval, state):
+ return self.__select_keyval(keyval)
+
+ def __cmd_select_candidates_4(self, keyval, state):
+ return self.__select_keyval(keyval)
+
+ def __cmd_select_candidates_5(self, keyval, state):
+ return self.__select_keyval(keyval)
+
+ def __cmd_select_candidates_6(self, keyval, state):
+ return self.__select_keyval(keyval)
+
+ def __cmd_select_candidates_7(self, keyval, state):
+ return self.__select_keyval(keyval)
+
+ def __cmd_select_candidates_8(self, keyval, state):
+ return self.__select_keyval(keyval)
+
+ def __cmd_select_candidates_9(self, keyval, state):
+ return self.__select_keyval(keyval)
+
+ def __cmd_select_candidates_0(self, keyval, state):
+ return self.__select_keyval(keyval)
+
+ #convert_keys
+ def __cmd_convert_to_char_type_forward(self, keyval, state):
+ if self.__convert_mode == CONV_MODE_ANTHY:
+ n = self.__segments[self.__cursor_pos][0]
+ if n == NTH_HIRAGANA_CANDIDATE:
+ return self.__convert_segment_to_kana(NTH_KATAKANA_CANDIDATE)
+ elif n == NTH_KATAKANA_CANDIDATE:
+ return self.__convert_segment_to_kana(NTH_HALFKANA_CANDIDATE)
+ elif n == NTH_HALFKANA_CANDIDATE:
+ return self.__convert_segment_to_latin(-100)
+ elif n == -100:
+ return self.__convert_segment_to_latin(-101)
+ else:
+ return self.__convert_segment_to_kana(NTH_HIRAGANA_CANDIDATE)
+
+ if self.__convert_mode == CONV_MODE_KATAKANA:
+ return self.__cmd_convert_to_half_katakana(keyval, state)
+ elif self.__convert_mode == CONV_MODE_HALF_WIDTH_KATAKANA:
+ return self.__cmd_convert_to_latin(keyval, state)
+ elif CONV_MODE_LATIN_0 <= self.__convert_mode <= CONV_MODE_LATIN_3:
+ return self.__cmd_convert_to_wide_latin(keyval, state)
+ elif (CONV_MODE_WIDE_LATIN_0 <= self.__convert_mode
+ <= CONV_MODE_WIDE_LATIN_3):
+ return self.__cmd_convert_to_hiragana(keyval, state)
+ else:
+ return self.__cmd_convert_to_katakana(keyval, state)
+
+ def __cmd_convert_to_char_type_backward(self, keyval, state):
+ if self.__convert_mode == CONV_MODE_ANTHY:
+ n = self.__segments[self.__cursor_pos][0]
+ if n == NTH_KATAKANA_CANDIDATE:
+ return self.__convert_segment_to_kana(NTH_HIRAGANA_CANDIDATE)
+ elif n == NTH_HALFKANA_CANDIDATE:
+ return self.__convert_segment_to_kana(NTH_KATAKANA_CANDIDATE)
+ elif n == -100:
+ return self.__convert_segment_to_kana(NTH_HALFKANA_CANDIDATE)
+ elif n == -101:
+ return self.__convert_segment_to_latin(-100)
+ else:
+ return self.__convert_segment_to_latin(-101)
+
+ if self.__convert_mode == CONV_MODE_KATAKANA:
+ return self.__cmd_convert_to_hiragana(keyval, state)
+ elif self.__convert_mode == CONV_MODE_HALF_WIDTH_KATAKANA:
+ return self.__cmd_convert_to_katakana(keyval, state)
+ elif CONV_MODE_LATIN_0 <= self.__convert_mode <= CONV_MODE_LATIN_3:
+ return self.__cmd_convert_to_half_katakana(keyval, state)
+ elif (CONV_MODE_WIDE_LATIN_0 <= self.__convert_mode
+ <= CONV_MODE_WIDE_LATIN_3):
+ return self.__cmd_convert_to_latin(keyval, state)
+ else:
+ return self.__cmd_convert_to_wide_latin(keyval, state)
+
+ def __convert_segment_to_kana(self, n):
+ if self.__convert_mode == CONV_MODE_ANTHY and -4 <= n <= -2:
+ buf = self.__context.get_segment(self.__cursor_pos, n)
+ self.__segments[self.__cursor_pos] = n, buf
+ self.__lookup_table_visible = False
+ self.__invalidate()
+ return True
+
+ return False
+
+ def __cmd_convert_to_hiragana(self, keyval, state):
+ if not self._chk_mode('12345'):
+ return False
+
+ if self.__convert_mode == CONV_MODE_ANTHY:
+ return self.__convert_segment_to_kana(NTH_HIRAGANA_CANDIDATE)
+
+ return self.__on_key_conv(0)
+
+ def __cmd_convert_to_katakana(self, keyval, state):
+ if not self._chk_mode('12345'):
+ return False
+
+ if self.__convert_mode == CONV_MODE_ANTHY:
+ return self.__convert_segment_to_kana(NTH_KATAKANA_CANDIDATE)
+
+ return self.__on_key_conv(1)
+
+ def __cmd_convert_to_half(self, keyval, state):
+ if not self._chk_mode('12345'):
+ return False
+
+ if self.__convert_mode == CONV_MODE_ANTHY:
+ i, s = self.__segments[self.__cursor_pos]
+ if i == -101:
+ return self.__convert_segment_to_latin(-100)
+ elif i == -100:
+ return self.__convert_segment_to_latin(-100)
+ return self.__convert_segment_to_kana(NTH_HALFKANA_CANDIDATE)
+
+ elif CONV_MODE_WIDE_LATIN_0 <= self.__convert_mode <= CONV_MODE_WIDE_LATIN_3:
+ return self.__on_key_conv(4)
+ elif CONV_MODE_LATIN_0 <= self.__convert_mode <= CONV_MODE_LATIN_3:
+ return self.__on_key_conv(4)
+ return self.__on_key_conv(2)
+
+ def __cmd_convert_to_half_katakana(self, keyval, state):
+ if not self._chk_mode('12345'):
+ return False
+
+ if self.__convert_mode == CONV_MODE_ANTHY:
+ return self.__convert_segment_to_kana(NTH_HALFKANA_CANDIDATE)
+
+ return self.__on_key_conv(2)
+
+ def __convert_segment_to_latin(self, n):
+ if self.__convert_mode == CONV_MODE_ANTHY and n in [-100, -101]:
+ start = 0
+ for i in range(self.__cursor_pos):
+ start += len(self.__context.get_segment(i, NTH_UNCONVERTED_CANDIDATE))
+ end = start + len(self.__context.get_segment(self.__cursor_pos, NTH_UNCONVERTED_CANDIDATE))
+ i, s = self.__segments[self.__cursor_pos]
+ s2 = self.__preedit_ja_string.get_raw(start, end)
+ if n == -101:
+ s2 = ''.join([unichar_half_to_full(c) for c in s2])
+ if i == n:
+ if s == s2.lower():
+ s2 = s2.upper()
+ elif s == s2.upper():
+ s2 = s2.capitalize()
+ elif s == s2 or s == s2.capitalize():
+ s2 = s2.lower()
+ self.__segments[self.__cursor_pos] = n, s2
+ self.__lookup_table_visible = False
+ self.__invalidate()
+ return True
+
+ return False
+
+ def __cmd_convert_to_wide_latin(self, keyval, state):
+ if not self._chk_mode('12345'):
+ return False
+
+ if self.__convert_mode == CONV_MODE_ANTHY:
+ return self.__convert_segment_to_latin(-101)
+
+ return self.__on_key_conv(3)
+
+ def __cmd_convert_to_latin(self, keyval, state):
+ if not self._chk_mode('12345'):
+ return False
+
+ if self.__convert_mode == CONV_MODE_ANTHY:
+ return self.__convert_segment_to_latin(-100)
+
+ return self.__on_key_conv(4)
+
+ #dictonary_keys
+ def __cmd_dict_admin(self, keyval, state):
+ if not self._chk_mode('0'):
+ return False
+
+ self.__start_dict_admin()
+ return True
+
+ def __cmd_add_word(self, keyval, state):
+ if not self._chk_mode('0'):
+ return False
+
+ self.__start_add_word()
+ return True
+
+ def __cmd_start_setup(self, keyval, state):
+ if not self._chk_mode('0'):
+ return False
+
+ self.__start_setup()
+ return True
+
+ def __start_dict_admin(self):
+ command = self.__prefs.get_value('common', 'dict_admin_command')
+ os.spawnl(os.P_NOWAIT, *command)
+
+ def __start_add_word(self):
+ command = self.__prefs.get_value('common', 'add_word_command')
+ os.spawnl(os.P_NOWAIT, *command)
+
+ def __start_setup(self):
+ if Engine.__setup_pid != 0:
+ pid, state = os.waitpid(Engine.__setup_pid, os.P_NOWAIT)
+ if pid != Engine.__setup_pid:
+ return
+ Engine.__setup_pid = 0
+ setup_cmd = path.join(config.LIBEXECDIR, 'ibus-setup-anthy')
+ Engine.__setup_pid = os.spawnl(os.P_NOWAIT, setup_cmd, 'ibus-setup-anthy')
+
+ def __cmd_hiragana_for_latin_with_shift(self, keyval, state):
+ self.__preedit_ja_string.set_hiragana_katakana(True)
+
diff --git a/engine/python3/factory.py b/engine/python3/factory.py
new file mode 100644
index 0000000..8994793
--- /dev/null
+++ b/engine/python3/factory.py
@@ -0,0 +1,80 @@
+# vim:set et sts=4 sw=4:
+# -*- coding: utf-8 -*-
+#
+# ibus-anthy - The Anthy engine for IBus
+#
+# Copyright (c) 2007-2008 Peng Huang <shawn.p.huang@gmail.com>
+# Copyright (c) 2010-2014 Takao Fujiwara <takao.fujiwara1@gmail.com>
+# Copyright (c) 2007-2014 Red Hat, Inc.
+#
+# 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.
+
+import os
+
+from gi.repository import IBus
+
+import _config as config
+import engine
+
+
+class EngineFactory(IBus.Factory):
+ FACTORY_PATH = '/com/redhat/IBus/engines/Anthy/Factory'
+ ENGINE_PATH = '/com/redhat/IBus/engines/Anthy/Engine'
+ NAME = 'Anthy'
+ LANG = 'ja'
+ ICON = config.PKGDATADIR + '/icons/ibus-anthy.png'
+ AUTHORS = 'Huang Peng <shawn.p.huang@gmail.com>'
+ CREDITS = 'GPLv2'
+
+ def __init__(self, bus):
+ self.__bus = bus
+ engine.Engine.CONFIG_RELOADED(bus)
+ super(EngineFactory, self).__init__(object_path=IBus.PATH_FACTORY,
+ connection=bus.get_connection())
+
+ self.__id = 0
+ self.__config = self.__bus.get_config()
+
+ if self.__config != None:
+ self.__config.connect('value-changed',
+ self.__config_value_changed_cb)
+ else:
+ print('ibus-config is not running or bus address is not correct.',
+ file=sys.stderr)
+
+ bus.get_connection().signal_subscribe('org.freedesktop.DBus',
+ 'org.freedesktop.DBus',
+ 'NameOwnerChanged',
+ '/org/freedesktop/DBus',
+ None,
+ 0,
+ self.__name_owner_changed_cb,
+ bus)
+
+ def do_create_engine(self, engine_name):
+ if engine_name == 'anthy':
+ self.__id += 1
+ return engine.Engine(self.__bus, '%s/%d' % (self.ENGINE_PATH, self.__id))
+
+ return super(EngineFactory, self).do_create_engine(engine_name)
+
+ def __config_value_changed_cb(self, config, section, name, value):
+ engine.Engine.CONFIG_VALUE_CHANGED(self.__bus, section, name, value)
+
+ def __name_owner_changed_cb(self, connection, sender_name, object_path,
+ interface_name, signal_name, parameters,
+ user_data):
+ if signal_name == 'NameOwnerChanged':
+ engine.Engine.CONFIG_RELOADED(self.__bus)
diff --git a/engine/python3/ibus-engine-anthy.in b/engine/python3/ibus-engine-anthy.in
new file mode 100644
index 0000000..c54b10a
--- /dev/null
+++ b/engine/python3/ibus-engine-anthy.in
@@ -0,0 +1,33 @@
+#!/bin/sh
+#
+# vim:set noet ts=4:
+#
+# ibus-anthy - The Anthy engine for IBus
+#
+# Copyright (c) 2007-2008 Peng Huang <shawn.p.huang@gmail.com>
+# Copyright (c) 2010-2013 Takao Fujiwara <takao.fujiwara1@gmail.com>
+# Copyright (c) 2007-2013 Red Hat, Inc.
+#
+# 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.
+
+prefix=@prefix@
+datarootdir=@datarootdir@
+exec_prefix=@exec_prefix@
+libexecdir=@libexecdir@
+export IBUS_PREFIX=@prefix@
+export IBUS_ANTHY_PKGDATADIR=@datarootdir@/@PACKAGE@
+export LIBEXECDIR=$libexecdir
+exec @ENV_IBUS_ENGINE@ @PYTHON@ @datarootdir@/@PACKAGE@/engine/main.py $@
+
diff --git a/engine/python3/jastring.py b/engine/python3/jastring.py
new file mode 100644
index 0000000..255799d
--- /dev/null
+++ b/engine/python3/jastring.py
@@ -0,0 +1,304 @@
+# vim:set et sts=4 sw=4:
+# -*- coding: utf-8 -*-
+#
+# ibus-anthy - The Anthy engine for IBus
+#
+# Copyright (c) 2007-2008 Peng Huang <shawn.p.huang@gmail.com>
+# Copyright (c) 2010-2014 Takao Fujiwara <takao.fujiwara1@gmail.com>
+# Copyright (c) 2007-2014 Red Hat, Inc.
+#
+# 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.
+
+import romaji
+import kana
+import thumb
+
+from segment import unichar_half_to_full
+
+HalfSymbolTable = {}
+for i in range(32, 127):
+ if not chr(i).isalnum():
+ HalfSymbolTable[unichar_half_to_full(chr(i))] = chr(i)
+
+HalfNumberTable = {}
+for i in range(10):
+ HalfNumberTable[unichar_half_to_full(str(i))] = str(i)
+
+PeriodTable = {'。': '.', '、': ',', '。': '.', '、': ','}
+
+SymbolTable = {}
+SymbolTable[0] = {'「': '「', '」': '」', '/': '/'}
+SymbolTable[1] = {'「': '「', '」': '」', '/': '・'}
+SymbolTable[2] = {'「': '[', '」': ']', '/': '/'}
+SymbolTable[3] = {'「': '[', '」': ']', '/': '・'}
+
+TYPING_MODE_ROMAJI, \
+TYPING_MODE_KANA, \
+TYPING_MODE_THUMB_SHIFT = list(range(3))
+
+class JaString:
+ _prefs = None
+ _mode = TYPING_MODE_ROMAJI
+ _shift = False
+ _unshift = False
+
+ def __init__(self, mode=TYPING_MODE_ROMAJI, latin_with_shift=True):
+ self._init_mode(mode)
+ if mode == TYPING_MODE_ROMAJI:
+ romaji.RomajiSegment.SET_LATIN_WITH_SHIFT(latin_with_shift)
+
+ @classmethod
+ def _init_mode(cls, mode):
+ cls._mode = mode
+ cls._shift = False
+ cls._unshift = False
+ cls.__cursor = 0
+ cls.__segments = list()
+ if mode == TYPING_MODE_ROMAJI:
+ romaji.RomajiSegment.INIT_ROMAJI_TYPING_RULE(cls._prefs)
+ elif mode == TYPING_MODE_KANA:
+ kana.KanaSegment.INIT_KANA_TYPING_RULE(cls._prefs)
+ elif mode == TYPING_MODE_THUMB_SHIFT:
+ thumb.ThumbShiftSegment.INIT_THUMB_TYPING_RULE(cls._prefs)
+
+ @classmethod
+ def SET_PREFS(cls, prefs):
+ cls._prefs = prefs
+
+ @classmethod
+ def RESET(cls, prefs, section, name, value):
+ cls._prefs = prefs
+ if section.startswith('kana_typing_rule'):
+ mode = TYPING_MODE_KANA
+ kana.KanaSegment.RESET(prefs, section, name, value)
+ cls._init_mode(mode)
+ if section == 'common' and name == 'latin_with_shift':
+ romaji.RomajiSegment.SET_LATIN_WITH_SHIFT(value)
+
+ def set_shift(self, shift):
+ self._shift = shift
+
+ def set_hiragana_katakana(self, mode):
+ if mode and self._mode == TYPING_MODE_ROMAJI:
+ self._unshift = True
+
+ def insert(self, c):
+ segment_before = None
+ segment_after = None
+ new_segments = None
+
+ if self.__cursor >= 1:
+ segment_before = self.__segments[self.__cursor - 1]
+ if self.__cursor < len(self.__segments):
+ segment_after = self.__segments[self.__cursor]
+ if segment_before and not segment_before.is_finished():
+ if type(segment_before) == romaji.RomajiSegment:
+ new_segments = segment_before.append(c,
+ self._shift,
+ self._unshift)
+ self._unshift = False
+ else:
+ new_segments = segment_before.append(c)
+ elif segment_after and not segment_after.is_finished():
+ if type(segment_after) == romaji.RomajiSegment:
+ new_segments = segment_after.prepend(c,
+ self._shift,
+ self._unshift)
+ self._unshift = False
+ else:
+ new_segments = segment_after.prepend(c)
+ else:
+ if c != '\0' and c != '':
+ if self._mode == TYPING_MODE_ROMAJI:
+ new_segments = [romaji.RomajiSegment(c,
+ '',
+ self._shift,
+ self._unshift)]
+ self._unshift = False
+ elif self._mode == TYPING_MODE_KANA:
+ # kana mode doesn't have shift latin in MS.
+ new_segments = [kana.KanaSegment(c)]
+ elif self._mode == TYPING_MODE_THUMB_SHIFT:
+ new_segments = [thumb.ThumbShiftSegment(c)]
+ if new_segments:
+ self.__segments[self.__cursor:self.__cursor] = new_segments
+ self.__cursor += len(new_segments)
+
+ def remove_before(self):
+ index = self.__cursor - 1
+ if index >= 0:
+ segment = self.__segments[index]
+ segment.pop()
+ if segment.is_empty():
+ del self.__segments[index]
+ self.__cursor = index
+ return True
+
+ return False
+
+ def remove_after(self):
+ index = self.__cursor
+ if index < len(self.__segments):
+ segment = self.__segments[index]
+ segment.pop()
+ if segment.is_empty():
+ del self.__segments[index]
+ return True
+
+ return False
+
+ def get_string(self, type):
+ pass
+
+ def move_cursor(self, delta):
+ self.__cursor += delta
+ if self.__cursor < 0:
+ self.__cursor = 0
+ elif self.__cursor > len(self.__segments):
+ self.__cursor = len(self.__segments)
+
+ # hiragana segments are not char lengths.
+ # e.g. 'ya' is 1 segment and 1 char and 'kya' is 1 segment and 2 chars.
+ def move_cursor_hiragana_length(self, length):
+ delta = length
+ if delta < 0:
+ if self.__cursor >= len(self.__segments):
+ delta = delta + (self.__cursor - len(self.__segments) + 1)
+ self.__cursor = len(self.__segments) - 1
+ while delta < 0:
+ text = str(self.__segments[self.__cursor].to_hiragana())
+ if len(text) > -delta:
+ break
+ delta = delta + len(text)
+ self.__cursor = self.__cursor - 1
+ else:
+ if self.__cursor >= len(self.__segments):
+ self.__cursor = len(self.__segments)
+ return
+ while delta > 0:
+ text = str(self.__segments[self.__cursor].to_hiragana())
+ if len(text) > delta:
+ break
+ delta = delta - len(text)
+ self.__cursor = self.__cursor + 1
+
+ def move_cursor_katakana_length(self, length):
+ delta = length
+ if delta < 0:
+ if self.__cursor >= len(self.__segments):
+ delta = delta + (self.__cursor - len(self.__segments) + 1)
+ self.__cursor = len(self.__segments) - 1
+ while delta < 0:
+ text = str(self.__segments[self.__cursor].to_katanaka())
+ if len(text) > -delta:
+ break
+ delta = delta + len(text)
+ self.__cursor = self.__cursor - 1
+ else:
+ if self.__cursor >= len(self.__segments):
+ self.__cursor = len(self.__segments)
+ return
+ while delta > 0:
+ text = str(self.__segments[self.__cursor].to_katanaka())
+ if len(text) > delta:
+ break
+ delta = delta - len(text)
+ self.__cursor = self.__cursor + 1
+
+ def move_cursor_half_with_katakana_length(self, length):
+ delta = length
+ if delta < 0:
+ if self.__cursor >= len(self.__segments):
+ delta = delta + (self.__cursor - len(self.__segments) + 1)
+ self.__cursor = len(self.__segments) - 1
+ while delta < 0:
+ text = str(self.__segments[self.__cursor].to_half_width_katakana())
+ if len(text) > -delta:
+ break
+ delta = delta + len(text)
+ self.__cursor = self.__cursor - 1
+ else:
+ if self.__cursor >= len(self.__segments):
+ self.__cursor = len(self.__segments)
+ return
+ while delta > 0:
+ text = str(self.__segments[self.__cursor].to_half_width_katakana())
+ if len(text) > delta:
+ break
+ delta = delta - len(text)
+ self.__cursor = self.__cursor + 1
+
+ def _chk_text(self, s):
+ period = self._prefs.get_value('common', 'period_style')
+ symbol = self._prefs.get_value('common', 'symbol_style')
+ half_symbol = self._prefs.get_value('common', 'half_width_symbol')
+ half_number = self._prefs.get_value('common', 'half_width_number')
+ ret = ''
+ for c in s:
+ c = c if not period else PeriodTable.get(c, c)
+ # thumb_left + '2' and '/' are different
+ if self._mode != TYPING_MODE_THUMB_SHIFT:
+ c = c if not symbol else SymbolTable[symbol].get(c, c)
+ c = c if not half_symbol else HalfSymbolTable.get(c, c)
+ c = c if not half_number else HalfNumberTable.get(c, c)
+ ret += c
+ return ret
+
+ def get_hiragana(self, commit=False):
+ conv = lambda s: s.to_hiragana()
+ R = lambda s: s if not (commit and s[-1:] == 'n') else s[:-1] + 'ん'
+ text_before = R(''.join(map(conv, self.__segments[:self.__cursor])))
+ text_after = R(''.join(map(conv, self.__segments[self.__cursor:])))
+ return self._chk_text(text_before + text_after), len(text_before)
+
+ def get_katakana(self, commit=False):
+ conv = lambda s: s.to_katakana()
+ R = lambda s: s if not (commit and s[-1:] == 'n') else s[:-1] + 'ン'
+ text_before = R(''.join(map(conv, self.__segments[:self.__cursor])))
+ text_after = R(''.join(map(conv, self.__segments[self.__cursor:])))
+ return self._chk_text(text_before + text_after), len(text_before)
+
+ def get_half_width_katakana(self, commit=False):
+ conv = lambda s: s.to_half_width_katakana()
+ R = lambda s: s if not (commit and s[-1:] == 'n') else s[:-1] + 'ン'
+ text_before = R(''.join(map(conv, self.__segments[:self.__cursor])))
+ text_after = R(''.join(map(conv, self.__segments[self.__cursor:])))
+ return self._chk_text(text_before + text_after), len(text_before)
+
+ def get_latin(self):
+ conv = lambda s: s.to_latin()
+ text_before = ''.join(map(conv, self.__segments[:self.__cursor]))
+ text_after = ''.join(map(conv, self.__segments[self.__cursor:]))
+ return text_before + text_after, len(text_before)
+
+ def get_wide_latin(self):
+ conv = lambda s: s.to_wide_latin()
+ text_before = ''.join(map(conv, self.__segments[:self.__cursor]))
+ text_after = ''.join(map(conv, self.__segments[self.__cursor:]))
+ return text_before + text_after, len(text_before)
+
+ def is_empty(self):
+ return all([s.is_empty() for s in self.__segments])
+
+ def get_raw(self, start, end):
+ i = 0
+ r = ''
+ for s in self.__segments:
+ if i >= end:
+ break
+ elif start <= i:
+ r += s.to_latin()
+ i += len(s.to_hiragana())
+ return r
diff --git a/engine/python3/kana.py b/engine/python3/kana.py
new file mode 100644
index 0000000..10e1b96
--- /dev/null
+++ b/engine/python3/kana.py
@@ -0,0 +1,170 @@
+# vim:set et sts=4 sw=4:
+# -*- coding: utf-8 -*-
+#
+# ibus-anthy - The Anthy engine for IBus
+#
+# Copyright (c) 2007-2008 Peng Huang <shawn.p.huang@gmail.com>
+# Copyright (c) 2010-2014 Takao Fujiwara <takao.fujiwara1@gmail.com>
+# Copyright (c) 2007-2014 Red Hat, Inc.
+#
+# 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.
+
+import sys
+
+from tables import *
+import segment
+
+_UNFINISHED_HIRAGANA = set('かきくけこさしすせそたちつてとはひふへほ')
+
+class KanaSegment(segment.Segment):
+ _prefs = None
+ _kana_typing_rule_section = None
+ _kana_voiced_consonant_rule = None
+
+ def __init__(self, enchars='', jachars=''):
+ if not jachars:
+ jachars = self.__get_kana_typing_rule(enchars, '')
+ super(KanaSegment, self).__init__(enchars, jachars)
+
+ @classmethod
+ def INIT_KANA_TYPING_RULE(cls, prefs):
+ cls._prefs = prefs
+ if prefs == None:
+ cls._kana_typing_rule_section = None
+ return
+ if cls._kana_typing_rule_section == None:
+ cls._init_kana_typing_method()
+ if cls._kana_voiced_consonant_rule == None and \
+ cls._kana_typing_rule_section != None:
+ cls._init_kana_voiced_consonant_rule()
+
+ @classmethod
+ def _init_kana_typing_method(cls, method=None):
+ prefs = cls._prefs
+ if method == None:
+ method = prefs.get_value('kana_typing_rule', 'method')
+ if method == None:
+ method = 'jp'
+ cls._kana_typing_rule_section = 'kana_typing_rule/' + method
+ if cls._kana_typing_rule_section not in prefs.sections():
+ cls._kana_typing_rule_section = None
+
+ @classmethod
+ def _init_kana_voiced_consonant_rule(cls):
+ prefs = cls._prefs
+ # Create kana_voiced_consonant_rule dynamically.
+ # E.g. 't' + '@' on jp kbd becomes Hiragana GA
+ # 't' + '[' on us kbd becomes Hiragana GA
+ # If the customized table provides U+309b with other chars,
+ # it needs to be detected dynamically.
+ cls._kana_voiced_consonant_rule = {}
+ section = cls._kana_typing_rule_section
+ for gkey in prefs.keys(section):
+ value = prefs.get_value(section, gkey)
+ key = prefs.typing_from_config_key(gkey)
+ if key == '':
+ continue
+ if value == chr(0x309b):
+ for no_voiced, voiced in \
+ list(kana_voiced_consonant_no_rule.items()):
+ rule = no_voiced + key
+ cls._kana_voiced_consonant_rule[rule] = voiced
+ if value == chr(0x309c):
+ for no_voiced, voiced in \
+ list(kana_semi_voiced_consonant_no_rule.items()):
+ rule = no_voiced + key
+ cls._kana_voiced_consonant_rule[rule] = voiced
+
+ @classmethod
+ def RESET(cls, prefs, section, name, value):
+ cls._prefs = prefs
+ if section == 'kana_typing_rule' and name == 'method' and \
+ value != None:
+ cls._kana_typing_rule_section = None
+ cls._kana_voiced_consonant_rule = None
+ cls._init_kana_typing_method(value)
+ elif section.startswith('kana_typing_rule/'):
+ # Probably it's better to restart ibus by manual
+ # instead of saving the emitted values from config.
+ cls._kana_voiced_consonant_rule = None
+
+ def __get_kana_typing_rule(self, enchars, retval=None):
+ prefs = self._prefs
+ value = None
+ section = self._kana_typing_rule_section
+ if section != None:
+ # Need to send Unicode to typing_to_config_key instead of UTF-8
+ # not to separate U+A5
+ gkey = prefs.typing_to_config_key(enchars)
+ if gkey == '':
+ return None
+ enchars = gkey
+ if enchars in prefs.keys(section):
+ value = prefs.str(prefs.str(prefs.get_value(section, enchars)))
+ else:
+ prefs.set_no_key_warning(True)
+ value = prefs.get_value_direct(section, enchars)
+ prefs.set_no_key_warning(False)
+ if value != None:
+ value = prefs.str(prefs.str(value))
+ if value == '':
+ value = None
+ if value == None:
+ value = retval
+ else:
+ value = kana_typing_rule_static.get(enchars, retval)
+ return value
+
+ def is_finished(self):
+ return not (self._jachars in _UNFINISHED_HIRAGANA)
+
+ def append(self, enchar):
+ if enchar == '\0' or enchar == '':
+ return []
+ if self._jachars:
+ text = self._jachars + enchar
+ if self._kana_voiced_consonant_rule != None:
+ jachars = self._kana_voiced_consonant_rule.get(text, None)
+ if jachars:
+ self._enchars = self._enchars + enchar
+ self._jachars = jachars
+ return []
+ return [KanaSegment(enchar)]
+ self._enchars = self._enchars + enchar
+ self._jachars = self.__get_kana_typing_rule(self._enchars, '')
+ return []
+
+ def prepend(self, enchar):
+ if enchar == '\0' or enchar == '':
+ return []
+ if self._enchars == '':
+ self._enchars = enchar
+ self._jachars = self.__get_kana_typing_rule(self._enchars, '')
+ return []
+ return [KanaSegment(enchar)]
+
+ def pop(self, index=-1):
+ if index == -1:
+ index = len(self._enchars) - 1
+ if index < 0 or index >= len(self._enchars):
+ raise IndexError('Out of bound')
+ if self.is_finished():
+ self._enchars = ''
+ self._jachars = ''
+ else:
+ enchars = list(self._enchars)
+ del enchars[index]
+ self._enchars = ''.join(enchars)
+ self._jachars = self.__get_kana_typing_rule(self._enchars, '')
diff --git a/engine/python3/main.py b/engine/python3/main.py
new file mode 100644
index 0000000..eb6fe5f
--- /dev/null
+++ b/engine/python3/main.py
@@ -0,0 +1,188 @@
+# vim:set et sts=4 sw=4:
+# -*- coding: utf-8 -*-
+#
+# ibus-anthy - The Anthy engine for IBus
+#
+# Copyright (c) 2007-2008 Peng Huang <shawn.p.huang@gmail.com>
+# Copyright (c) 2010-2014 Takao Fujiwara <takao.fujiwara1@gmail.com>
+# Copyright (c) 2007-2014 Red Hat, Inc.
+#
+# 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.
+
+import os
+from os import path
+import sys
+import getopt
+import locale
+import xml.dom.minidom
+
+from gi.repository import GLib
+
+# set_prgname before importing factory to show the name in warning
+# messages when import modules are failed. E.g. Gtk.
+GLib.set_prgname('ibus-engine-anthy')
+
+from gi.repository import IBus
+
+import _config as config
+import factory
+
+class IMApp:
+ def __init__(self, exec_by_ibus):
+ command_line = config.LIBEXECDIR + '/ibus-engine-anthy --ibus'
+ self.__component = IBus.Component(name='org.freedesktop.IBus.Anthy',
+ description='Anthy Component',
+ version='0.1.0',
+ license='GPL',
+ author='Peng Huang <shawn.p.huang@gmail.com>',
+ homepage='http://code.google.com/p/ibus/',
+ command_line=command_line,
+ textdomain='ibus-anthy')
+ engine = IBus.EngineDesc(name='anthy',
+ longname='Anthy',
+ description='Anthy Input Method',
+ language='ja',
+ license='GPL',
+ author='Peng Huang <shawn.p.huang@gmail.com>',
+ icon='ibus-anthy',
+ layout=config.LAYOUT,
+ symbol=config.SYMBOL_CHAR,
+ rank=99)
+ self.__component.add_engine(engine)
+ self.__mainloop = GLib.MainLoop()
+ self.__bus = IBus.Bus()
+ self.__bus.connect('disconnected', self.__bus_disconnected_cb)
+ self.__factory = factory.EngineFactory(self.__bus)
+ if exec_by_ibus:
+ self.__bus.request_name('org.freedesktop.IBus.Anthy', 0)
+ else:
+ self.__bus.register_component(self.__component)
+
+ def run(self):
+ self.__mainloop.run()
+
+ def __bus_disconnected_cb(self, bus):
+ self.__mainloop.quit()
+
+
+def launch_engine(exec_by_ibus):
+ IMApp(exec_by_ibus).run()
+
+def get_userhome():
+ if 'HOME' not in os.environ:
+ import pwd
+ userhome = pwd.getpwuid(os.getuid()).pw_dir
+ else:
+ userhome = os.environ['HOME']
+ userhome = userhome.rstrip('/')
+ return userhome
+
+def resync_engine_file():
+ user_config = path.join(get_userhome(), '.config',
+ 'ibus-anthy', 'engines.xml')
+ system_config = path.join(config.PKGDATADIR, 'engine', 'default.xml')
+ if not path.exists(user_config):
+ return
+ if not path.exists(system_config):
+ os.unlink(user_config)
+ return
+
+ # path.getmtime depends on the build time rather than install time.
+ def __get_engine_file_version(engine_file):
+ version_str = ''
+ dom = xml.dom.minidom.parse(engine_file)
+ elements = dom.getElementsByTagName('version')
+ nodes = []
+ if len(elements) > 0:
+ nodes = elements[0].childNodes
+ if len(nodes) > 0:
+ version_str = nodes[0].data
+ if version_str != '':
+ version_str = version_str.strip()
+ return version_str
+
+ user_config_version = __get_engine_file_version(user_config)
+ system_config_version = __get_engine_file_version(system_config)
+ if system_config_version > user_config_version:
+ import shutil
+ shutil.copyfile(system_config, user_config)
+
+def print_xml():
+ user_config = os.path.join(get_userhome(), '.config',
+ 'ibus-anthy', 'engines.xml')
+ system_config = os.path.join(config.PKGDATADIR, 'engine', 'default.xml')
+ xml = None
+ for f in [user_config, system_config]:
+ if os.path.exists(f):
+ xml = f
+ break
+ if xml == None:
+ print('Not exist: %s' % system_config, file=sys.stderr)
+ return
+ file = open(xml, 'r')
+ print(file.read())
+ file.close()
+
+def print_help(out, v = 0):
+ print('-i, --ibus executed by ibus.', file=out)
+ print('-h, --help show this message.', file=out)
+ print('-d, --daemonize daemonize ibus.', file=out)
+ print('-x, --xml print engine xml.', file=out)
+ sys.exit(v)
+
+def main():
+ try:
+ locale.setlocale(locale.LC_ALL, '')
+ except:
+ pass
+
+ exec_by_ibus = False
+ daemonize = False
+ xml = False
+
+ shortopt = 'ihdx'
+ longopt = ['ibus', 'help', 'daemonize', 'xml']
+
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], shortopt, longopt)
+ except getopt.GetoptError as err:
+ print_help(sys.stderr, 1)
+
+ for o, a in opts:
+ if o in ('-h', '--help'):
+ print_help(sys.stdout)
+ elif o in ('-d', '--daemonize'):
+ daemonize = True
+ elif o in ('-i', '--ibus'):
+ exec_by_ibus = True
+ elif o in ('-x', '--xml'):
+ xml = True
+ else:
+ print('Unknown argument: %s' % o, file=sys.stderr)
+ print_help(sys.stderr, 1)
+
+ if daemonize:
+ if os.fork():
+ sys.exit()
+
+ if xml:
+ resync_engine_file()
+ print_xml()
+ return
+
+ launch_engine(exec_by_ibus)
+
+if __name__ == '__main__':
+ main()
diff --git a/engine/python3/romaji.py b/engine/python3/romaji.py
new file mode 100644
index 0000000..d495120
--- /dev/null
+++ b/engine/python3/romaji.py
@@ -0,0 +1,263 @@
+# vim:set et sts=4 sw=4:
+# -*- coding: utf-8 -*-
+#
+# ibus-anthy - The Anthy engine for IBus
+#
+# Copyright (c) 2007-2008 Peng Huang <shawn.p.huang@gmail.com>
+# Copyright (c) 2010-2014 Takao Fujiwara <takao.fujiwara1@gmail.com>
+# Copyright (c) 2007-2014 Red Hat, Inc.
+#
+# 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.
+
+import sys
+
+from tables import *
+import segment
+
+def romaji_correction_rule_get(k, d):
+ return ('ん', k[1:2]) if k[0:1] == 'n' and not k[1:2] in "aiueony'" else d
+
+class RomajiSegment(segment.Segment):
+ _prefs = None
+ _romaji_typing_rule_section = None
+ _latin_with_shift = True
+ _shift_mode = False
+
+ def __init__(self, enchars='', jachars='', shift=False, unshift=False):
+ if self._latin_with_shift:
+ # If Shift key is pressed, Latin mode.
+ # If Hiragana_Katakana key is pressed, Hiragana mode.
+ if shift:
+ self._shift_mode = True
+ if unshift:
+ self._shift_mode = False
+
+ enchars_orig = enchars
+ # Even if the chars are capital with CapsLock, Hiragana
+ # should be converted. E.g. 'SA'
+ enchars = enchars.lower()
+
+ if not jachars and not shift:
+ jachars = self.__get_romaji_typing_rule(enchars, None)
+ if jachars == None:
+ jachars = symbol_rule.get(enchars, '')
+ super(RomajiSegment, self).__init__(enchars_orig, jachars)
+
+ @classmethod
+ def INIT_ROMAJI_TYPING_RULE(cls, prefs):
+ cls._prefs = prefs
+ if prefs == None:
+ cls._romaji_typing_rule_section = None
+ return
+ method = prefs.get_value('romaji_typing_rule', 'method')
+ if method == None:
+ method = 'default'
+ cls._romaji_typing_rule_section = 'romaji_typing_rule/' + method
+ if cls._romaji_typing_rule_section not in prefs.sections():
+ cls._romaji_typing_rule_section = None
+
+ @classmethod
+ def SET_LATIN_WITH_SHIFT(cls, latin_with_shift):
+ # Do not use IBus.Config in every conversion for the performance.
+ cls._latin_with_shift = latin_with_shift
+
+ def __get_romaji_typing_rule(self, enchars, retval=None):
+ prefs = self._prefs
+ value = None
+ section = self._romaji_typing_rule_section
+ if section != None:
+ # Need to send Unicode to typing_to_config_key instead of UTF-8
+ # not to separate U+A5
+ gkey = prefs.typing_to_config_key(enchars)
+ if gkey == '':
+ return None
+ if gkey in prefs.keys(section):
+ value = prefs.get_value(section, gkey)
+ else:
+ prefs.set_no_key_warning(True)
+ value = prefs.get_value_direct(section, gkey)
+ prefs.set_no_key_warning(False)
+ if value == '':
+ value = None
+ if value == None:
+ value = retval
+ else:
+ value = romaji_typing_rule_static.get(enchars, retval)
+ return value
+
+ def is_finished(self):
+ return self._jachars != ''
+
+ def append(self, enchar, shift=False, unshift=False):
+ if self.is_finished():
+ if enchar == '' and enchar == '\0':
+ return []
+ return [RomajiSegment(enchar)]
+
+ text_orig = self._enchars + enchar
+ text = text_orig.lower()
+
+ if self._latin_with_shift:
+ # If Shift key is pressed, Latin mode.
+ # If Hiragana_Katakana key is pressed, Hiragana mode.
+ if shift:
+ self._shift_mode = True
+ if unshift:
+ self._shift_mode = False
+ if self._shift_mode:
+ self._enchars = text_orig
+ return []
+
+ if shift:
+ self._enchars = text_orig
+ return []
+
+ jachars = self.__get_romaji_typing_rule(text, None)
+ if jachars == None:
+ jachars = symbol_rule.get(text, None)
+ if jachars:
+ self._enchars = text_orig
+ self._jachars = jachars
+ return []
+
+ jachars, c = romaji_double_consonat_typing_rule.get(text, (None, None))
+ if jachars:
+ self._enchars = text_orig[0]
+ self._jachars = jachars
+ return [RomajiSegment(c)]
+
+# jachars, c = romaji_correction_rule.get(text, (None, None))
+ jachars, c = romaji_correction_rule_get(text, (None, None))
+ if jachars:
+ self._enchars = text_orig[0]
+ self._jachars = jachars
+ return [RomajiSegment(c)]
+
+ for i in range(-min(4, len(text)), 0):
+ enchars = text[i:]
+
+ jachars = self.__get_romaji_typing_rule(enchars, None)
+ if jachars == None:
+ jachars = symbol_rule.get(enchars, None)
+ if jachars:
+ jasegment = RomajiSegment(enchars, jachars)
+ self._enchars = text_orig[:i]
+ return [jasegment]
+
+ jachars, c = romaji_double_consonat_typing_rule.get(enchars, (None, None))
+ if jachars:
+ jasegment = RomajiSegment(enchars[:-len(c)], jachars)
+ self._enchars = text_orig[:i]
+ if c:
+ return [jasegment, RomajiSegment(c)]
+ return [jasegment]
+
+# jachars, c = romaji_correction_rule.get(enchars, (None, None))
+ jachars, c = romaji_correction_rule_get(enchars, (None, None))
+ if jachars:
+ jasegment = RomajiSegment(enchars[:-len(c)], jachars)
+ self._enchars = text_orig[:i]
+ if c:
+ return [jasegment, RomajiSegment(c)]
+ return [jasegment]
+
+ self._enchars = text_orig
+ return []
+
+ def prepend(self, enchar, shift=False, unshift=False):
+ if enchar == '' or enchar == '\0':
+ return []
+
+ if self.is_finished():
+ return [RomajiSegment(enchar)]
+
+ text_orig = enchar + self._enchars
+ text = text_orig.lower()
+
+ if self._latin_with_shift:
+ if shift:
+ self._shift_mode = True
+ if unshift:
+ self._shift_mode = False
+ if self._shift_mode:
+ self._enchars = text_orig
+ return []
+
+ if shift:
+ self._enchars = text_orig
+ return []
+
+ jachars = self.__get_romaji_typing_rule(text, None)
+ if jachars == None:
+ jachars = symbol_rule.get(text, None)
+ if jachars:
+ self._enchars = text_orig
+ self._jachars = jachars
+ return []
+
+ jachars, c = romaji_double_consonat_typing_rule.get(text, (None, None))
+ if jachars:
+ self._enchars = c
+ return [RomajiSegment(text_orig[0], jachars)]
+
+# jachars, c = romaji_correction_rule.get(text, (None, None))
+ jachars, c = romaji_correction_rule_get(text, (None, None))
+ if jachars:
+ self._enchars = c
+ return [RomajiSegment(text_orig[0], jachars)]
+
+ for i in range(min(4, len(text)), 0, -1):
+ enchars = text[:i]
+
+ jachars = self.__get_romaji_typing_rule(enchars, None)
+ if jachars == None:
+ jachars = symbol_rule.get(enchars, None)
+ if jachars:
+ jasegment = RomajiSegment(enchars, jachars)
+ self._enchars = text_orig[i:]
+ return [jasegment]
+
+ jachars, c = romaji_double_consonat_typing_rule.get(enchars, (None, None))
+ if jachars:
+ self._enchars = c + text_orig[i:]
+ return [RomajiSegment(enchars[:-len(c)], jachars)]
+
+# jachars, c = romaji_correction_rule.get(enchars, (None, None))
+ jachars, c = romaji_correction_rule_get(enchars, (None, None))
+ if jachars:
+ self._enchars = c + text_orig[i:]
+ return [RomajiSegment(enchars[:-len(c)], jachars)]
+
+ self._enchars = text_orig
+ return []
+
+ def pop(self, index=-1):
+ if index == -1:
+ index = len(self._enchars) - 1
+ if index < 0 or index >= len(self._enchars):
+ raise IndexError('Out of bound')
+ if self.is_finished():
+ self._enchars = ''
+ self._jachars = ''
+ else:
+ enchars = list(self._enchars)
+ del enchars[index]
+ self._enchars = ''.join(enchars)
+ jachars = self.__get_romaji_typing_rule(self._enchars, None)
+ if jachars == None:
+ jachars = symbol_rule.get(self._enchars, '')
+ self._jachars = jachars
+
+
diff --git a/engine/python3/segment.py b/engine/python3/segment.py
new file mode 100644
index 0000000..b7450ec
--- /dev/null
+++ b/engine/python3/segment.py
@@ -0,0 +1,95 @@
+# vim:set et sts=4 sw=4:
+# -*- coding: utf-8 -*-
+#
+# ibus-anthy - The Anthy engine for IBus
+#
+# Copyright (c) 2007-2008 Peng Huang <shawn.p.huang@gmail.com>
+# Copyright (c) 2010-2014 Takao Fujiwara <takao.fujiwara1@gmail.com>
+# Copyright (c) 2007-2014 Red Hat, Inc.
+#
+# 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.
+
+from tables import *
+
+_half_full_table = [
+ (0x0020, 0x3000, 1),
+ (0x0021, 0xFF01, 0x5E),
+]
+
+def _h_to_f(c):
+ code = ord (c)
+ for half, full, size in _half_full_table:
+ if code >= half and code < half + size:
+ return chr(full + code - half)
+ return c
+
+def unichar_half_to_full(c):
+ tdl = {'"': '\u201d', "'": '\u2019', '`': '\u2018'}
+ return tdl[c] if c in tdl else _h_to_f(c)
+
+class Segment(object):
+ def __init__(self, enchars='', jachars=''):
+ self._enchars = enchars
+ self._jachars = jachars
+
+ def append(self, enchar):
+ raise NotImplementedError('append() is not implemented')
+
+ def prepend(self, enchar):
+ raise NotImplementedError('prepend() is not implemented')
+
+ def pop(self, index=-1):
+ raise NotImplementedError('pop() is not implemented')
+
+ def is_finished(self):
+ raise NotImplementedError('is_finised() is not implemented')
+
+ def set_enchars(self, enchars):
+ self.enchars = enchars
+
+ def get_enchars(self):
+ return self._enchars
+
+ def set_jachars(self, jachars):
+ self._jachars = jachars
+
+ def get_jachars(self):
+ return self._jachars
+
+ def to_hiragana(self):
+ if self._jachars:
+ return self._jachars
+ return self._enchars
+
+ def to_katakana(self):
+ if self._jachars:
+ return ''.join([hiragana_katakana_table.get(c, (c, c, c))[0] for c in self._jachars])
+ return self._enchars
+
+ def to_half_width_katakana(self):
+ if self._jachars:
+ return ''.join([hiragana_katakana_table.get(c, (c, c, c))[1] for c in self._jachars])
+ return self._enchars
+
+ def to_latin(self):
+ return self._enchars
+
+ def to_wide_latin(self):
+ return ''.join(map(unichar_half_to_full, self._enchars))
+
+ def is_empty(self):
+ if self._enchars or self._jachars:
+ return False
+ return True
diff --git a/engine/python3/tables.py b/engine/python3/tables.py
new file mode 100644
index 0000000..b2c4cac
--- /dev/null
+++ b/engine/python3/tables.py
@@ -0,0 +1,731 @@
+# vim:set et sts=4 sw=4:
+# -*- coding: utf-8 -*-
+#
+# ibus-anthy - The Anthy engine for IBus
+#
+# Copyright (c) 2007-2008 Peng Huang <shawn.p.huang@gmail.com>
+# Copyright (c) 2010-2014 Takao Fujiwara <takao.fujiwara1@gmail.com>
+# Copyright (c) 2007-2014 Red Hat, Inc.
+#
+# 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.
+
+# string, result, cont
+romaji_typing_rule_static = {
+ '-' : 'ー',
+ 'a' : 'あ',
+ 'i' : 'い',
+ 'u' : 'う',
+ 'e' : 'え',
+ 'o' : 'お',
+ 'xa' : 'ぁ',
+ 'xi' : 'ぃ',
+ 'xu' : 'ぅ',
+ 'xe' : 'ぇ',
+ 'xo' : 'ぉ',
+ 'la' : 'ぁ',
+ 'li' : 'ぃ',
+ 'lu' : 'ぅ',
+ 'le' : 'ぇ',
+ 'lo' : 'ぉ',
+ 'wha' : 'うぁ',
+ 'whi' : 'うぃ',
+ 'whe' : 'うぇ',
+ 'who' : 'うぉ',
+ 'va' : 'ヴぁ',
+ 'vi' : 'ヴぃ',
+ 'vu' : 'ヴ',
+ 've' : 'ヴぇ',
+ 'vo' : 'ヴぉ',
+ 'ka' : 'か',
+ 'ki' : 'き',
+ 'ku' : 'く',
+ 'ke' : 'け',
+ 'ko' : 'こ',
+ 'lka' : 'ヵ',
+ 'lke' : 'ヶ',
+# u'xka' : u'ゕ',
+ 'xka' : 'ヵ',
+# u'xke' : u'ゖ',
+ 'xke' : 'ヶ',
+ 'ga' : 'が',
+ 'gi' : 'ぎ',
+ 'gu' : 'ぐ',
+ 'ge' : 'げ',
+ 'go' : 'ご',
+ 'kya' : 'きゃ',
+ 'kyi' : 'きぃ',
+ 'kyu' : 'きゅ',
+ 'kye' : 'きぇ',
+ 'kyo' : 'きょ',
+ 'kwa' : 'くぁ',
+ 'gya' : 'ぎゃ',
+ 'gyi' : 'ぎぃ',
+ 'gyu' : 'ぎゅ',
+ 'gye' : 'ぎぇ',
+ 'gyo' : 'ぎょ',
+ 'gwa' : 'ぐぁ',
+ 'sa' : 'さ',
+ 'si' : 'し',
+ 'su' : 'す',
+ 'se' : 'せ',
+ 'so' : 'そ',
+ 'za' : 'ざ',
+ 'zi' : 'じ',
+ 'zu' : 'ず',
+ 'ze' : 'ぜ',
+ 'zo' : 'ぞ',
+ 'sya' : 'しゃ',
+ 'syi' : 'しぃ',
+ 'syu' : 'しゅ',
+ 'sye' : 'しぇ',
+ 'syo' : 'しょ',
+ 'sha' : 'しゃ',
+ 'shi' : 'し',
+ 'shu' : 'しゅ',
+ 'she' : 'しぇ',
+ 'sho' : 'しょ',
+ 'zya' : 'じゃ',
+ 'zyi' : 'じぃ',
+ 'zyu' : 'じゅ',
+ 'zye' : 'じぇ',
+ 'zyo' : 'じょ',
+ 'ja' : 'じゃ',
+ 'jya' : 'じゃ',
+ 'ji' : 'じ',
+ 'jyi' : 'じぃ',
+ 'ju' : 'じゅ',
+ 'jyu' : 'じゅ',
+ 'je' : 'じぇ',
+ 'jye' : 'じぇ',
+ 'jo' : 'じょ',
+ 'jyo' : 'じょ',
+ 'ta' : 'た',
+ 'ti' : 'ち',
+ 'tu' : 'つ',
+ 'tsu' : 'つ',
+ 'te' : 'て',
+ 'to' : 'と',
+ 'da' : 'だ',
+ 'di' : 'ぢ',
+ 'du' : 'づ',
+ 'de' : 'で',
+ 'do' : 'ど',
+ 'xtu' : 'っ',
+ 'xtsu' : 'っ',
+ 'ltu' : 'っ',
+ 'ltsu' : 'っ',
+ 'tya' : 'ちゃ',
+ 'tyi' : 'ちぃ',
+ 'tyu' : 'ちゅ',
+ 'tye' : 'ちぇ',
+ 'tyo' : 'ちょ',
+ 'cya' : 'ちゃ',
+ 'cyi' : 'ちぃ',
+ 'cyu' : 'ちゅ',
+ 'cye' : 'ちぇ',
+ 'cyo' : 'ちょ',
+ 'cha' : 'ちゃ',
+ 'chi' : 'ち',
+ 'chu' : 'ちゅ',
+ 'che' : 'ちぇ',
+ 'cho' : 'ちょ',
+ 'dya' : 'ぢゃ',
+ 'dyi' : 'ぢぃ',
+ 'dyu' : 'ぢゅ',
+ 'dye' : 'ぢぇ',
+ 'dyo' : 'ぢょ',
+ 'tsa' : 'つぁ',
+ 'tsi' : 'つぃ',
+ 'tse' : 'つぇ',
+ 'tso' : 'つぉ',
+ 'tha' : 'てゃ',
+ 'thi' : 'てぃ',
+ 'thu' : 'てゅ',
+ 'the' : 'てぇ',
+ 'tho' : 'てょ',
+ 'twu' : 'とぅ',
+ 'dha' : 'でゃ',
+ 'dhi' : 'でぃ',
+ 'dhu' : 'でゅ',
+ 'dhe' : 'でぇ',
+ 'dho' : 'でょ',
+ 'dwu' : 'どぅ',
+ 'na' : 'な',
+ 'ni' : 'に',
+ 'nu' : 'ぬ',
+ 'ne' : 'ね',
+ 'no' : 'の',
+ 'nya' : 'にゃ',
+ 'nyi' : 'にぃ',
+ 'nyu' : 'にゅ',
+ 'nye' : 'にぇ',
+ 'nyo' : 'にょ',
+ 'ha' : 'は',
+ 'hi' : 'ひ',
+ 'hu' : 'ふ',
+ 'he' : 'へ',
+ 'ho' : 'ほ',
+ 'ba' : 'ば',
+ 'bi' : 'び',
+ 'bu' : 'ぶ',
+ 'be' : 'べ',
+ 'bo' : 'ぼ',
+ 'pa' : 'ぱ',
+ 'pi' : 'ぴ',
+ 'pu' : 'ぷ',
+ 'pe' : 'ぺ',
+ 'po' : 'ぽ',
+ 'hya' : 'ひゃ',
+ 'hyi' : 'ひぃ',
+ 'hyu' : 'ひゅ',
+ 'hye' : 'ひぇ',
+ 'hyo' : 'ひょ',
+ 'bya' : 'びゃ',
+ 'byi' : 'びぃ',
+ 'byu' : 'びゅ',
+ 'bye' : 'びぇ',
+ 'byo' : 'びょ',
+ 'pya' : 'ぴゃ',
+ 'pyi' : 'ぴぃ',
+ 'pyu' : 'ぴゅ',
+ 'pye' : 'ぴぇ',
+ 'pyo' : 'ぴょ',
+ 'fa' : 'ふぁ',
+ 'fi' : 'ふぃ',
+ 'fu' : 'ふ',
+ 'fe' : 'ふぇ',
+ 'fo' : 'ふぉ',
+ 'fya' : 'ふゃ',
+ 'fyi' : 'ふぃ',
+ 'fyu' : 'ふゅ',
+ 'fye' : 'ふぇ',
+ 'fyo' : 'ふょ',
+ 'ma' : 'ま',
+ 'mi' : 'み',
+ 'mu' : 'む',
+ 'me' : 'め',
+ 'mo' : 'も',
+ 'mya' : 'みゃ',
+ 'myi' : 'みぃ',
+ 'myu' : 'みゅ',
+ 'mye' : 'みぇ',
+ 'myo' : 'みょ',
+ 'ya' : 'や',
+ 'yi' : 'い',
+ 'yu' : 'ゆ',
+ 'ye' : 'いぇ',
+ 'yo' : 'よ',
+ 'lya' : 'ゃ',
+ 'lyi' : 'ぃ',
+ 'lyu' : 'ゅ',
+ 'lye' : 'ぇ',
+ 'lyo' : 'ょ',
+ 'xya' : 'ゃ',
+ 'xyi' : 'ぃ',
+ 'xyu' : 'ゅ',
+ 'xye' : 'ぇ',
+ 'xyo' : 'ょ',
+ 'ra' : 'ら',
+ 'ri' : 'り',
+ 'ru' : 'る',
+ 're' : 'れ',
+ 'ro' : 'ろ',
+ 'rya' : 'りゃ',
+ 'ryi' : 'りぃ',
+ 'ryu' : 'りゅ',
+ 'rye' : 'りぇ',
+ 'ryo' : 'りょ',
+ 'wa' : 'わ',
+ 'wi' : 'うぃ',
+ 'wu' : 'う',
+ 'we' : 'うぇ',
+ 'wo' : 'を',
+ 'lwa' : 'ゎ',
+ 'xwa' : 'ゎ',
+ 'n\'' : 'ん',
+ 'nn' : 'ん',
+ 'wyi' : 'ゐ',
+ 'wye' : 'ゑ',
+}
+
+symbol_rule = {
+ # symbols
+ ' ' : ' ',
+ ',' : '、',
+ '.' : '。',
+ '!' : '!',
+ '"' : '\u201d',
+ '#' : '#',
+ '$' : '$',
+ '%' : '%',
+ '&' : '&',
+ '\'' : '\u2019',
+ '(' : '(',
+ ')' : ')',
+ '~' : '\uff5e',
+ '-' : 'ー',
+ '=' : '=',
+ '^' : '^',
+ '\\' : '\',
+ '|' : '|',
+ '`' : '\u2018',
+ '@' : '@',
+ '{' : '{',
+ '[' : '「',
+ '+' : '+',
+ ';' : ';',
+ '*' : '*',
+ ':' : ':',
+ '}' : '}',
+ ']' : '」',
+ '<' : '<',
+ '>' : '>',
+ '?' : '?',
+ '/' : '/',
+ '_' : '_',
+ '¥' : '¥',
+
+ # numbers
+ '0': '0',
+ '1': '1',
+ '2': '2',
+ '3': '3',
+ '4': '4',
+ '5': '5',
+ '6': '6',
+ '7': '7',
+ '8': '8',
+ '9': '9',
+}
+
+# this is only used with romaji_typing_rule
+romaji_double_consonat_typing_rule = {
+ # double consonant rule
+ 'bb' : ('っ', 'b'),
+ 'cc' : ('っ', 'c'),
+ 'dd' : ('っ', 'd'),
+ 'ff' : ('っ', 'f'),
+ 'gg' : ('っ', 'g'),
+ 'hh' : ('っ', 'h'),
+ 'jj' : ('っ', 'j'),
+ 'kk' : ('っ', 'k'),
+ 'mm' : ('っ', 'm'),
+ 'pp' : ('っ', 'p'),
+ 'rr' : ('っ', 'r'),
+ 'ss' : ('っ', 's'),
+ 'tt' : ('っ', 't'),
+ 'vv' : ('っ', 'v'),
+ 'ww' : ('っ', 'w'),
+ 'xx' : ('っ', 'x'),
+ 'yy' : ('っ', 'y'),
+ 'zz' : ('っ', 'z'),
+}
+
+# this is only used with romaji_typing_rule
+romaji_correction_rule = {
+ 'nb' : ('ん', 'b'),
+ 'nc' : ('ん', 'c'),
+ 'nd' : ('ん', 'd'),
+ 'nf' : ('ん', 'f'),
+ 'ng' : ('ん', 'g'),
+ 'nh' : ('ん', 'h'),
+ 'nj' : ('ん', 'j'),
+ 'nk' : ('ん', 'k'),
+ 'nl' : ('ん', 'l'),
+ 'nm' : ('ん', 'm'),
+ 'np' : ('ん', 'p'),
+ 'nr' : ('ん', 'r'),
+ 'ns' : ('ん', 's'),
+ 'nt' : ('ん', 't'),
+ 'nv' : ('ん', 'v'),
+ 'nw' : ('ん', 'w'),
+ 'nx' : ('ん', 'x'),
+ 'nz' : ('ん', 'z'),
+ 'n\0' : ('ん', ''),
+ 'n,' : ('ん', ','),
+ 'n.' : ('ん', '.'),
+}
+
+# EUC-JP and SJIS do not have the chars
+romaji_utf8_rule = {
+ 'う゛' : ['ゔ'],
+}
+
+# Hiragana normalization is needed for the personal dict.
+romaji_normalize_rule = {
+ 'ヴ' : ['う゛'],
+}
+
+# a port of 101kana.sty from scim-anthy
+kana_typing_rule_static = {
+ # no modifiers keys
+ '1' : 'ぬ',
+ '2' : 'ふ',
+ '3' : 'あ',
+ '4' : 'う',
+ '5' : 'え',
+ '6' : 'お',
+ '7' : 'や',
+ '8' : 'ゆ',
+ '9' : 'よ',
+ '0' : 'わ',
+ '-' : 'ほ',
+ '^' : 'へ',
+
+ 'q' : 'た',
+ 'w' : 'て',
+ 'e' : 'い',
+ 'r' : 'す',
+ 't' : 'か',
+ 'y' : 'ん',
+ 'u' : 'な',
+ 'i' : 'に',
+ 'o' : 'ら',
+ 'p' : 'せ',
+ '@' : '゛',
+ '[' : '゜',
+
+ 'a' : 'ち',
+ 's' : 'と',
+ 'd' : 'し',
+ 'f' : 'は',
+ 'g' : 'き',
+ 'h' : 'く',
+ 'j' : 'ま',
+ 'k' : 'の',
+ 'l' : 'り',
+ ';' : 'れ',
+ ':' : 'け',
+ ']' : 'む',
+
+ 'z' : 'つ',
+ 'x' : 'さ',
+ 'c' : 'そ',
+ 'v' : 'ひ',
+ 'b' : 'こ',
+ 'n' : 'み',
+ 'm' : 'も',
+ ',' : 'ね',
+ '.' : 'る',
+ '/' : 'め',
+ # u'\\' : u'ー',
+ '\\' : 'ろ',
+
+ # shift modifiered keys
+ '!' : 'ぬ',
+ '"' : 'ふ',
+ '#' : 'ぁ',
+ '$' : 'ぅ',
+ '%' : 'ぇ',
+ '&' : 'ぉ',
+ '\'' : 'ゃ',
+ '(' : 'ゅ',
+ ')' : 'ょ',
+ '~' : 'を',
+ '=' : 'ほ',
+ '|' : 'ー',
+
+ 'Q' : 'た',
+ 'W' : 'て',
+ 'E' : 'ぃ',
+ 'R' : 'す',
+ 'T' : 'ヵ',
+ 'Y' : 'ん',
+ 'U' : 'な',
+ 'I' : 'に',
+ 'O' : 'ら',
+ 'P' : 'せ',
+ '`' : '゛',
+
+ '{' : '「',
+
+ 'A' : 'ち',
+ 'S' : 'と',
+ 'D' : 'し',
+ 'F' : 'ゎ',
+ 'G' : 'き',
+ 'H' : 'く',
+ 'J' : 'ま',
+ 'K' : 'の',
+ 'L' : 'り',
+ '+' : 'れ',
+ '*' : 'ヶ',
+
+ '}' : '」',
+
+ 'Z' : 'っ',
+ 'X' : 'さ',
+ 'C' : 'そ',
+ 'V' : 'ゐ',
+ 'B' : 'こ',
+ 'M' : 'も',
+ 'N' : 'み',
+ '<' : '、',
+ '>' : '。',
+
+ '?' : '・',
+ '_' : 'ろ',
+
+ '¥' : 'ー',
+}
+
+kana_voiced_consonant_no_rule = {
+ 'か' : 'が',
+ 'き' : 'ぎ',
+ 'く' : 'ぐ',
+ 'け' : 'げ',
+ 'こ' : 'ご',
+ 'さ' : 'ざ',
+ 'し' : 'じ',
+ 'す' : 'ず',
+ 'せ' : 'ぜ',
+ 'そ' : 'ぞ',
+ 'た' : 'だ',
+ 'ち' : 'ぢ',
+ 'つ' : 'づ',
+ 'て' : 'で',
+ 'と' : 'ど',
+ 'は' : 'ば',
+ 'ひ' : 'び',
+ 'ふ' : 'ぶ',
+ 'へ' : 'べ',
+ 'ほ' : 'ぼ',
+}
+
+kana_semi_voiced_consonant_no_rule = {
+ 'は' : 'ぱ',
+ 'ひ' : 'ぴ',
+ 'ふ' : 'ぷ',
+ 'へ' : 'ぺ',
+ 'ほ' : 'ぽ',
+}
+
+# Create the table dynamically with kana_voiced_consonant_no_rule
+#
+#kana_voiced_consonant_rule = {
+# u'か@' : u'が',
+# u'き@' : u'ぎ',
+# u'く@' : u'ぐ',
+# u'け@' : u'げ',
+# u'こ@' : u'ご',
+# u'さ@' : u'ざ',
+# u'し@' : u'じ',
+# u'す@' : u'ず',
+# u'せ@' : u'ぜ',
+# u'そ@' : u'ぞ',
+# u'た@' : u'だ',
+# u'ち@' : u'ぢ',
+# u'つ@' : u'づ',
+# u'て@' : u'で',
+# u'と@' : u'ど',
+# u'は@' : u'ば',
+# u'ひ@' : u'び',
+# u'ふ@' : u'ぶ',
+# u'へ@' : u'べ',
+# u'ほ@' : u'ぼ',
+# u'か`' : u'が',
+# u'き`' : u'ぎ',
+# u'く`' : u'ぐ',
+# u'け`' : u'げ',
+# u'こ`' : u'ご',
+# u'さ`' : u'ざ',
+# u'し`' : u'じ',
+# u'す`' : u'ず',
+# u'せ`' : u'ぜ',
+# u'そ`' : u'ぞ',
+# u'た`' : u'だ',
+# u'ち`' : u'ぢ',
+# u'つ`' : u'づ',
+# u'て`' : u'で',
+# u'と`' : u'ど',
+# u'は`' : u'ば',
+# u'ひ`' : u'び',
+# u'ふ`' : u'ぶ',
+# u'へ`' : u'べ',
+# u'ほ`' : u'ぼ',
+# u'は[' : u'ぱ',
+# u'ひ[' : u'ぴ',
+# u'ふ[' : u'ぷ',
+# u'へ[' : u'ぺ',
+# u'ほ[' : u'ぽ',
+#}
+#
+#kana_voiced_consonant_us_rule = {
+# u'か[' : u'が',
+# u'き[' : u'ぎ',
+# u'く[' : u'ぐ',
+# u'け[' : u'げ',
+# u'こ[' : u'ご',
+# u'さ[' : u'ざ',
+# u'し[' : u'じ',
+# u'す[' : u'ず',
+# u'せ[' : u'ぜ',
+# u'そ[' : u'ぞ',
+# u'た[' : u'だ',
+# u'ち[' : u'ぢ',
+# u'つ[' : u'づ',
+# u'て[' : u'で',
+# u'と[' : u'ど',
+# u'は[' : u'ば',
+# u'ひ[' : u'び',
+# u'ふ[' : u'ぶ',
+# u'へ[' : u'べ',
+# u'ほ[' : u'ぼ',
+# u'は]' : u'ぱ',
+# u'ひ]' : u'ぴ',
+# u'ふ]' : u'ぷ',
+# u'へ]' : u'ぺ',
+# u'ほ]' : u'ぽ',
+#}
+
+#hiragana, katakana, half_katakana
+hiragana_katakana_table = {
+ 'あ' : ('ア', 'ア'),
+ 'い' : ('イ', 'イ'),
+ 'う' : ('ウ', 'ウ'),
+ 'え' : ('エ', 'エ'),
+ 'お' : ('オ', 'オ'),
+ 'か' : ('カ', 'カ'),
+ 'き' : ('キ', 'キ'),
+ 'く' : ('ク', 'ク'),
+ 'け' : ('ケ', 'ケ'),
+ 'こ' : ('コ', 'コ'),
+ 'が' : ('ガ', 'ガ'),
+ 'ぎ' : ('ギ', 'ギ'),
+ 'ぐ' : ('グ', 'グ'),
+ 'げ' : ('ゲ', 'ゲ'),
+ 'ご' : ('ゴ', 'ゴ'),
+ 'さ' : ('サ', 'サ'),
+ 'し' : ('シ', 'シ'),
+ 'す' : ('ス', 'ス'),
+ 'せ' : ('セ', 'セ'),
+ 'そ' : ('ソ', 'ソ'),
+ 'ざ' : ('ザ', 'ザ'),
+ 'じ' : ('ジ', 'ジ'),
+ 'ず' : ('ズ', 'ズ'),
+ 'ぜ' : ('ゼ', 'ゼ'),
+ 'ぞ' : ('ゾ', 'ゾ'),
+ 'た' : ('タ', 'タ'),
+ 'ち' : ('チ', 'チ'),
+ 'つ' : ('ツ', 'ツ'),
+ 'て' : ('テ', 'テ'),
+ 'と' : ('ト', 'ト'),
+ 'だ' : ('ダ', 'ダ'),
+ 'ぢ' : ('ヂ', 'ヂ'),
+ 'づ' : ('ヅ', 'ヅ'),
+ 'で' : ('デ', 'デ'),
+ 'ど' : ('ド', 'ド'),
+ 'な' : ('ナ', 'ナ'),
+ 'に' : ('ニ', 'ニ'),
+ 'ぬ' : ('ヌ', 'ヌ'),
+ 'ね' : ('ネ', 'ネ'),
+ 'の' : ('ノ', 'ノ'),
+ 'は' : ('ハ', 'ハ'),
+ 'ひ' : ('ヒ', 'ヒ'),
+ 'ふ' : ('フ', 'フ'),
+ 'へ' : ('ヘ', 'ヘ'),
+ 'ほ' : ('ホ', 'ホ'),
+ 'ば' : ('バ', 'バ'),
+ 'び' : ('ビ', 'ビ'),
+ 'ぶ' : ('ブ', 'ブ'),
+ 'べ' : ('ベ', 'ベ'),
+ 'ぼ' : ('ボ', 'ボ'),
+ 'ぱ' : ('パ', 'パ'),
+ 'ぴ' : ('ピ', 'ピ'),
+ 'ぷ' : ('プ', 'プ'),
+ 'ぺ' : ('ペ', 'ペ'),
+ 'ぽ' : ('ポ', 'ポ'),
+ 'ま' : ('マ', 'マ'),
+ 'み' : ('ミ', 'ミ'),
+ 'む' : ('ム', 'ム'),
+ 'め' : ('メ', 'メ'),
+ 'も' : ('モ', 'モ'),
+ 'や' : ('ヤ', 'ヤ'),
+ 'ゆ' : ('ユ', 'ユ'),
+ 'よ' : ('ヨ', 'ヨ'),
+ 'ら' : ('ラ', 'ラ'),
+ 'り' : ('リ', 'リ'),
+ 'る' : ('ル', 'ル'),
+ 'れ' : ('レ', 'レ'),
+ 'ろ' : ('ロ', 'ロ'),
+ 'わ' : ('ワ', 'ワ'),
+ 'を' : ('ヲ', 'ヲ'),
+ 'ん' : ('ン', 'ン'),
+ 'ぁ' : ('ァ', 'ァ'),
+ 'ぃ' : ('ィ', 'ィ'),
+ 'ぅ' : ('ゥ', 'ゥ'),
+ 'ぇ' : ('ェ', 'ェ'),
+ 'ぉ' : ('ォ', 'ォ'),
+ 'っ' : ('ッ', 'ッ'),
+ 'ゃ' : ('ャ', 'ャ'),
+ 'ゅ' : ('ュ', 'ュ'),
+ 'ょ' : ('ョ', 'ョ'),
+ 'ヵ' : ('ヵ', 'カ'),
+ 'ヶ' : ('ヶ', 'ケ'),
+ 'ゎ' : ('ヮ', 'ワ'),
+ 'ゐ' : ('ヰ', 'ィ'),
+ 'ゑ' : ('ヱ', 'ェ'),
+ 'ヴ' : ('ヴ', 'ヴ'),
+
+ # symbols
+ 'ー' : ('ー', 'ー'),
+ '、' : ('、', '、'),
+ '。' : ('。', '。'),
+ '!' : ('!', '!'),
+ '\u201d' : ('\u201d', '"'),
+ '#' : ('#', '#'),
+ '$' : ('$', '$'),
+ '%' : ('%', '%'),
+ '&' : ('&', '&'),
+ '\u2019' : ('\u2019', '\''),
+ '(' : ('(', '('),
+ ')' : (')', ')'),
+ '\uff5e' : ('\uff5e', '~'),
+ '=' : ('=', '='),
+ '^' : ('^', '^'),
+ '\' : ('\', '\\'),
+ '|' : ('|', '|'),
+ '\u2018' : ('\u2018', '`'),
+ '@' : ('@', '@'),
+ '゛' : ('゛', '゙'),
+ '{' : ('{', '{'),
+ '゜' : ('゜', '゚'),
+ '「' : ('「', '「'),
+ '+' : ('+', '+'),
+ ';' : (';', ';'),
+ '*' : ('*', '*'),
+ ':' : (':', ':'),
+ '}' : ('}', '}'),
+ '」' : ('」', '」'),
+ '<' : ('<', '<'),
+ '>' : ('>', '>'),
+ '?' : ('?', '?'),
+ '・' : ('・', '・'),
+ '/' : ('/', '/'),
+ '_' : ('_', '_'),
+ '¥' : ('¥', '¥'),
+
+ # numbers
+ '0': ('0', '0'),
+ '1': ('1', '1'),
+ '2': ('2', '2'),
+ '3': ('3', '3'),
+ '4': ('4', '4'),
+ '5': ('5', '5'),
+ '6': ('6', '6'),
+ '7': ('7', '7'),
+ '8': ('8', '8'),
+ '9': ('9', '9'),
+}
diff --git a/engine/python3/test.py b/engine/python3/test.py
new file mode 100644
index 0000000..cd67997
--- /dev/null
+++ b/engine/python3/test.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+import anthy
+import sys
+
+ctx = anthy.anthy_context ()
+ctx._set_encoding (2)
+if len(sys.argv) >= 2:
+ ctx.set_string (sys.argv[1])
+else:
+ ctx.set_string ("かまぁく")
+conv_stat = anthy.anthy_conv_stat ()
+seg_stat = anthy.anthy_segment_stat ()
+ctx.get_stat (conv_stat)
+for i in range (0, conv_stat.nr_segment):
+ ctx.get_segment_stat (i, seg_stat)
+ buf = " "
+ i = ctx.get_segment (i, 0, buf, 10)
+ print buf[:i]
+# anthy.anthy_release_context (ctx)
+ctx = None
diff --git a/engine/python3/thumb.py b/engine/python3/thumb.py
new file mode 100644
index 0000000..93a3967
--- /dev/null
+++ b/engine/python3/thumb.py
@@ -0,0 +1,657 @@
+# -*- coding: utf-8 -*-
+# vim:set et sts=4 sw=4:
+#
+# ibus-anthy - The Anthy engine for IBus
+#
+# Copyright (c) 2007-2008 Peng Huang <shawn.p.huang@gmail.com>
+# Copyright (c) 2009 Hideaki ABE <abe.sendai@gmail.com>
+# Copyright (c) 2010-2014 Takao Fujiwara <takao.fujiwara1@gmail.com>
+# Copyright (c) 2007-2014 Red Hat, Inc.
+#
+# 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.
+
+__all__ = (
+ 'ThumbShiftKeyboard',
+ 'ThumbShiftSegment',
+ )
+
+from gi.repository import GLib
+from gi.repository import IBus
+
+import segment
+
+_THUMB_BASIC_METHOD = 'base'
+
+_table_static = {
+ 'q': ['。', '', 'ぁ'],
+ 'w': ['か', 'が', 'え'],
+ 'e': ['た', 'だ', 'り'],
+ 'r': ['こ', 'ご', 'ゃ'],
+ 't': ['さ', 'ざ', 'れ'],
+
+ 'y': ['ら', 'よ', 'ぱ'],
+ 'u': ['ち', 'に', 'ぢ'],
+ 'i': ['く', 'る', 'ぐ'],
+ 'o': ['つ', 'ま', 'づ'],
+ 'p': [',', 'ぇ', 'ぴ'],
+ '@': ['、', '', ''],
+ '[': ['゛', '゜', ''],
+
+ 'a': ['う', '', 'を'],
+ 's': ['し', 'じ', 'あ'],
+ 'd': ['て', 'で', 'な'],
+ 'f': ['け', 'げ', 'ゅ'],
+ 'g': ['せ', 'ぜ', 'も'],
+
+ 'h': ['は', 'み', 'ば'],
+ 'j': ['と', 'お', 'ど'],
+ 'k': ['き', 'の', 'ぎ'],
+ 'l': ['い', 'ょ', 'ぽ'],
+ ';': ['ん', 'っ', ''],
+
+ 'z': ['.', '', 'ぅ'],
+ 'x': ['ひ', 'び', 'ー'],
+ 'c': ['す', 'ず', 'ろ'],
+ 'v': ['ふ', 'ぶ', 'や'],
+ 'b': ['へ', 'べ', 'ぃ'],
+
+ 'n': ['め', 'ぬ', 'ぷ'],
+ 'm': ['そ', 'ゆ', 'ぞ'],
+ ',': ['ね', 'む', 'ぺ'],
+ '.': ['ほ', 'わ', 'ぼ'],
+ '/': ['・', 'ぉ', ''],
+
+ '1': ['1', '', '?'],
+ '2': ['2', '', '/'],
+ '4': ['4', '', '「'],
+ '5': ['5', '', '」'],
+
+ '6': ['6', '[', ''],
+ '7': ['7', ']', ''],
+ '8': ['8', '(', ''],
+ '9': ['9', ')', ''],
+ '\\': ['¥', '', ''],
+}
+
+_nicola_j_table_static = {
+ ':': [':', '', ''],
+ '@': ['、', '', ''],
+ '[': ['゛', '゜', ''],
+ ']': ['」', '', ''],
+ '8': ['8', '(', ''],
+ '9': ['9', ')', ''],
+ '0': ['0', '', ''],
+}
+
+_nicola_a_table_static = {
+ ':': [':', '', ''],
+ '@': ['@', '', ''],
+ '[': ['、', '', ''],
+ ']': ['゛', '゜', ''],
+ '8': ['8', '', ''],
+ '9': ['9', '(', ''],
+ '0': ['0', ')', ''],
+}
+
+_nicola_f_table_static = {
+ ':': ['、', '', ''],
+ '@': ['@', '', ''],
+ '[': ['゛', '゜', ''],
+ ']': ['」', '', ''],
+ '8': ['8', '(', ''],
+ '9': ['9', ')', ''],
+ '0': ['0', '', ''],
+}
+
+_kb231_j_fmv_table_static = {
+ '3': ['3', '', '~'],
+ '0': ['0', '『', ''],
+ '-': ['-', '』', ''],
+ '=': ['=', '', ''],
+}
+
+_kb231_a_fmv_table_static = {
+ '3': ['3', '', '~'],
+ '0': ['0', ')', ''],
+ '-': ['-', '『', ''],
+ '=': ['=', '』', ''],
+}
+
+_kb231_f_fmv_table_static = {
+ '3': ['3', '', '~'],
+ '0': ['0', '『', ''],
+ '-': ['-', '』', ''],
+ '=': ['=', '', ''],
+}
+
+_kb611_j_fmv_table_static = {
+ '`': ['‘', '', ''],
+ '^': ['々', '£', ''],
+ ':': [':', '', ''],
+ '@': ['、', '¢', ''],
+ '[': ['゛', '゜', ''],
+ # keysyms are same and keycodes depend on the platforms.
+ #'¥': [u'¥', u'¬', u''],
+ '\\': ['¥', '¦', ''],
+}
+
+_kb611_a_fmv_table_static = {
+ '`': ['々', '', '£'],
+ ':': [':', '', ''],
+ '@': ['@', '', ''],
+ '[': ['、', '¢', ''],
+ #'¥': [u'¥', u'¬', u''],
+ '\\': ['¥', '¦', ''],
+}
+
+_kb611_f_fmv_table_static = {
+ '`': ['‘', '', ''],
+ '^': ['々', '£', ''],
+ ':': ['、', '¢', ''],
+ '@': ['@', '', ''],
+ '[': ['゛', '゜', ''],
+ #'¥': [u'¥', u'¬', u''],
+ '\\': ['¥', '¦', ''],
+}
+
+_shift_table = {
+ 'H': 'ぱ',
+ 'X': 'ぴ',
+ 'V': 'ぷ',
+ 'B': 'ぺ',
+ '>': 'ぽ',
+}
+
+table_static = {}
+r_table_static = {}
+
+for k in list(_table_static.keys()):
+ table_static[ord(k)] = _table_static[k]
+ for c in _table_static[k]:
+ r_table_static[c] = k
+
+kana_voiced_consonant_rule = {
+ 'か゛' : 'が',
+ 'き゛' : 'ぎ',
+ 'く゛' : 'ぐ',
+ 'け゛' : 'げ',
+ 'こ゛' : 'ご',
+ 'さ゛' : 'ざ',
+ 'し゛' : 'じ',
+ 'す゛' : 'ず',
+ 'せ゛' : 'ぜ',
+ 'そ゛' : 'ぞ',
+ 'た゛' : 'だ',
+ 'ち゛' : 'ぢ',
+ 'つ゛' : 'づ',
+ 'て゛' : 'で',
+ 'と゛' : 'ど',
+ 'は゛' : 'ば',
+ 'ひ゛' : 'び',
+ 'ふ゛' : 'ぶ',
+ 'へ゛' : 'べ',
+ 'ほ゛' : 'ぼ',
+ 'は゜' : 'ぱ',
+ 'ひ゜' : 'ぴ',
+ 'ふ゜' : 'ぷ',
+ 'へ゜' : 'ぺ',
+ 'ほ゜' : 'ぽ',
+}
+
+_UNFINISHED_HIRAGANA = set('かきくけこさしすせそたちつてとはひふへほ')
+
+class ThumbShiftKeyboard:
+ def __init__(self, prefs=None):
+ self.__prefs = prefs
+ self.__table = table_static
+ self.__r_table = r_table_static
+ self.__shift_table = {}
+ self.__ls = 0
+ self.__rs = 0
+ self.__t1 = 0
+ self.__t2 = 0
+ self.__layout = 0
+ self.__fmv_extension = 2
+ self.__handakuten = False
+ self.__thumb_typing_rule_section_base = None
+ self.__thumb_typing_rule_section = None
+ self.__init_thumb_typing_rule()
+ self.__init_layout_table()
+ if self.__prefs != None:
+ self.reset()
+ self.__reset_shift_table(False)
+
+ def __init_thumb_typing_rule(self):
+ prefs = self.__prefs
+ if prefs == None:
+ self.__thumb_typing_rule_section = None
+ return
+ method = prefs.get_value('thumb_typing_rule', 'method')
+ if method == None:
+ method = _THUMB_BASIC_METHOD
+ self.__thumb_typing_rule_section_base = 'thumb_typing_rule'
+ self.__thumb_typing_rule_section = \
+ self.__thumb_typing_rule_section_base + '/' + method
+ if self.__thumb_typing_rule_section not in prefs.sections():
+ self.__thumb_typing_rule_section = None
+
+ def __init_layout_table(self):
+ if self.__table != {}:
+ self.__table.clear()
+ if self.__r_table != {}:
+ self.__r_table.clear()
+ section_base = self.__thumb_typing_rule_section_base
+ section = self.__thumb_typing_rule_section
+ if section != None:
+ prefs = self.__prefs
+ for k in prefs.keys(section):
+ value = prefs.get_value(section, k)
+ ch = prefs.typing_from_config_key(k)
+ if ch == '':
+ continue
+ self.__set_bus_table(ch, value)
+ for k in prefs.get_value(section_base, 'newkeys'):
+ value = prefs.get_value_direct(section, k)
+ ch = prefs.typing_from_config_key(k)
+ if ch == '':
+ continue
+ self.__set_bus_table(ch, value)
+ else:
+ for k in list(_table.keys()):
+ self.__table[ord(k)] = _table_static[k]
+ for c in _table_static[k]:
+ self.__r_table[c] = k
+
+ def __set_bus_table(self, key, value):
+ prefs = self.__prefs
+ if value == None or len(value) != 3:
+ return
+ if value[0] == '' and \
+ value[1] == '' and value[2] == '':
+ return
+ self.__table[ord(key)] = value
+ for c in value:
+ self.__r_table[c] = key
+
+ def __reset_layout_table(self, init,
+ j_table_label, j_table,
+ a_table_label, a_table,
+ f_table_label, f_table):
+ if init:
+ self.__init_layout_table()
+ method = None
+ sub_table = None
+ if self.__layout == 0:
+ method = j_table_label
+ sub_table = j_table
+ elif self.__layout == 1:
+ method = a_table_label
+ sub_table = a_table
+ elif self.__layout == 2:
+ method = f_table_label
+ sub_table = f_table
+ if method == None or sub_table == None:
+ return
+ section_base = self.__thumb_typing_rule_section_base
+ section = self.__thumb_typing_rule_section
+ sub_section = section_base + '/' + method
+ if section != None:
+ prefs = self.__prefs
+ for k in prefs.keys(sub_section):
+ value = prefs.get_value(sub_section, k)
+ ch = prefs.typing_from_config_key(k)
+ if ch == '':
+ continue
+ self.__set_bus_table(ch, value)
+ for k in prefs.get_value(section_base, method + '_newkeys'):
+ value = prefs.get_value_direct(sub_section, k)
+ ch = prefs.typing_from_config_key(k)
+ if ch == '':
+ continue
+ self.__set_bus_table(ch, value)
+ else:
+ for k in list(sub_table.keys()):
+ self.__table[ord(str(k))] = sub_table[k]
+ for c in sub_table[k]:
+ self.__r_table[c] = k
+
+ def __reset_extension_table(self, init):
+ self.__reset_layout_table(init,
+ 'nicola_j_table',
+ _nicola_j_table_static,
+ 'nicola_a_table',
+ _nicola_a_table_static,
+ 'nicola_f_table',
+ _nicola_f_table_static)
+ if self.__fmv_extension == 0:
+ return
+ if self.__fmv_extension >= 1:
+ self.__reset_layout_table(False,
+ 'kb231_j_fmv_table',
+ _kb231_j_fmv_table_static,
+ 'kb231_a_fmv_table',
+ _kb231_a_fmv_table_static,
+ 'kb231_f_fmv_table',
+ _kb231_f_fmv_table_static)
+ if self.__fmv_extension >= 2:
+ self.__reset_layout_table(False,
+ 'kb611_j_fmv_table',
+ _kb611_j_fmv_table_static,
+ 'kb611_a_fmv_table',
+ _kb611_a_fmv_table_static,
+ 'kb611_f_fmv_table',
+ _kb611_f_fmv_table_static)
+
+ def __reset_shift_table(self, init):
+ self.__reset_extension_table(init)
+ if self.__handakuten:
+ for k in list(_shift_table.keys()):
+ self.__shift_table[ord(k)] = _shift_table[k]
+ self.__r_table[_shift_table[k]] = k
+ elif self.__shift_table != {}:
+ for k in list(_shift_table.keys()):
+ if ord(k) in self.__shift_table:
+ del self.__shift_table[ord(k)]
+ if _shift_table[k] in self.__r_table:
+ del self.__r_table[_shift_table[k]]
+
+ def __s_to_key_raw(self, s):
+ keyval = IBus.keyval_from_name(s.split('+')[-1])
+ s = s.lower()
+ state = ('shift+' in s and IBus.ModifierType.SHIFT_MASK or 0) | (
+ 'ctrl+' in s and IBus.ModifierType.CONTROL_MASK or 0) | (
+ 'alt+' in s and IBus.ModifierType.MOD1_MASK or 0)
+ return (keyval, state)
+
+ def __get_xkb_layout(self):
+ # Until Gdk.property_get is fixed
+ '''
+ # Move importing Gdk into ThumbShiftKeyboard from the header
+ # because ibus-engine-anthy --xml does not requre to open X.
+ try:
+ from gi.repository import Gdk
+ get_default_root_window = Gdk.get_default_root_window
+ property_get = Gdk.property_get
+ intern = Gdk.Atom.intern
+ except ImportError:
+ get_default_root_window = lambda : None
+ property_get = lambda : None
+ intern = lambda : None
+ except RuntimeError:
+ # Do we support the engine without display?
+ print >> sys.stderr, "Gdk couldn't be initialized"
+ print >> sys.stderr, 'Could not open display'
+ get_default_root_window = lambda : None
+ property_get = lambda : None
+ intern = lambda : None
+
+ root_window = get_default_root_window()
+ if not root_window:
+ return 0
+ xkb_rules_names = intern('_XKB_RULES_NAMES', False)
+ xa_string = intern('STRING', False)
+ try:
+ prop = property_get(root_window,
+ xkb_rules_names, xa_string,
+ 0, 1024, 0)[3]
+ layout_list = prop.split('\0')
+ except TypeError:
+ import sys
+ print >> sys.stderr, \
+ 'This problem is fixed in the latest gobject-introspection'
+ print >> sys.stderr, \
+ 'https://bugzilla.gnome.org/show_bug.cgi?id=670509'
+ return 0
+ layout = 0
+ for data in layout_list:
+ if data == 'jp':
+ layout = 0
+ elif data == 'us':
+ layout = 1
+ elif data.find('japan:nicola_f_bs') >= 0:
+ layout = 2
+ elif data.find('japan:') >= 0:
+ layout = 0
+ return layout
+ '''
+
+ layout = 0
+ argv = ['setxkbmap', '-query']
+ (ret, std_out, std_error, exit_status) = \
+ GLib.spawn_sync(None, argv, None,
+ GLib.SpawnFlags.SEARCH_PATH_FROM_ENVP,
+ None, None)
+ if not ret:
+ print(std_error, file=sys.stderr)
+ return layout
+ for line in std_out.split('\n'):
+ if line.startswith('layout:'):
+ data = line.split()[1]
+ if data == 'jp':
+ layout = 0
+ elif data == 'us':
+ layout = 1
+ elif line.startswith('options:'):
+ data = line.split()[1]
+ if data.find('japan:nicola_f_bs') >= 0:
+ layout = 2
+ elif data.find('japan:') >= 0:
+ layout = 0
+ return 0
+
+ def __reset_layout_and_handakuten(self):
+ mode = self.__prefs.get_value('thumb', 'keyboard_layout_mode')
+ layout = 0
+ if mode == 1:
+ layout = self.__get_xkb_layout()
+ else:
+ layout = self.__prefs.get_value('thumb', 'keyboard_layout')
+ self.set_layout(layout)
+
+ fmv_extension = self.__prefs.get_value('thumb', 'fmv_extension')
+ self.set_fmv_extension(fmv_extension)
+ handakuten = self.__prefs.get_value('thumb', 'handakuten')
+ self.set_handakuten(handakuten)
+
+ def reset(self):
+ s = self.__prefs.get_value('thumb', 'ls')
+ ls, state = self.__s_to_key_raw(s)
+ if ls == 0xffffff:
+ ls = IBus.KEY_Muhenkan
+ self.set_ls(ls)
+
+ s = self.__prefs.get_value('thumb', 'rs')
+ rs, state = self.__s_to_key_raw(s)
+ if rs == 0xffffff:
+ rs = IBus.KEY_Henkan
+ self.set_rs(rs)
+
+ t1 = self.__prefs.get_value('thumb', 't1')
+ t2 = self.__prefs.get_value('thumb', 't2')
+ self.set_t1(t1)
+ self.set_t2(t2)
+
+ GLib.idle_add(self.__reset_layout_and_handakuten,
+ priority = GLib.PRIORITY_LOW)
+
+ def get_ls(self):
+ return self.__ls
+
+ def set_ls(self, ls):
+ self.__ls = ls
+
+ def get_rs(self):
+ return self.__rs
+
+ def set_rs(self, rs):
+ self.__rs = rs
+
+ def get_t1(self):
+ return self.__t1
+
+ def set_t1(self, t1):
+ self.__t1 = t1
+
+ def get_t2(self):
+ return self.__t2
+
+ def set_t2(self, t2):
+ self.__t2 = t2
+
+ def get_layout(self):
+ return self.__layout
+
+ def set_layout(self, layout):
+ if self.__layout == layout:
+ return
+ self.__layout = layout
+ self.__reset_shift_table(True)
+
+ def get_fmv_extension (self):
+ return self.__fmv_extension
+
+ def set_fmv_extension (self, fmv_extension):
+ if self.__fmv_extension == fmv_extension:
+ return
+ self.__fmv_extension = fmv_extension
+ self.__reset_shift_table(True)
+
+ def get_handakuten(self):
+ return self.__handakuten
+
+ def set_handakuten(self, handakuten):
+ if self.__handakuten == handakuten:
+ return
+ self.__handakuten = handakuten
+ self.__reset_shift_table(True)
+
+ def get_char(self, key, fallback=None):
+ return self.__table.get(key, fallback)
+
+ def get_chars(self):
+ return list(self.__table.keys())
+
+ def get_r_char(self, key, fallback=None):
+ return self.__r_table.get(key, fallback)
+
+ def get_r_chars(self):
+ return list(self.__r_table.keys())
+
+ def get_shift_char(self, key, fallback=None):
+ return self.__shift_table.get(key, fallback)
+
+ def get_shift_chars(self):
+ return list(self.__shift_table.keys())
+
+
+class ThumbShiftSegment(segment.Segment):
+ _prefs = None
+ _thumb_typing_rule_section_base = None
+ _thumb_typing_rule_section = None
+ _r_table = {}
+
+ def __init__(self, enchars='', jachars=''):
+ if not jachars:
+ if '!' <= enchars <= '~':
+ jachars = segment.unichar_half_to_full(enchars)
+ else:
+ jachars = enchars
+ enchars = self._r_table.get(jachars, '')
+ super(ThumbShiftSegment, self).__init__(enchars, jachars)
+
+ @classmethod
+ def INIT_THUMB_TYPING_RULE(cls, prefs):
+ cls._prefs = prefs
+ if prefs == None:
+ cls._thumb_typing_rule_section = None
+ return
+ method = prefs.get_value('thumb_typing_rule', 'method')
+ if method == None:
+ method = _THUMB_BASIC_METHOD
+ cls._thumb_typing_rule_section_base = 'thumb_typing_rule'
+ cls._thumb_typing_rule_section = \
+ cls._thumb_typing_rule_section_base + '/' + method
+ if cls._thumb_typing_rule_section not in prefs.sections():
+ cls._thumb_typing_rule_section = None
+ cls._init_layout_table()
+
+ @classmethod
+ def _init_layout_table(cls):
+ if cls._r_table != {}:
+ cls._r_table.clear()
+ section_base = cls._thumb_typing_rule_section_base
+ section = cls._thumb_typing_rule_section
+ if section != None:
+ prefs = cls._prefs
+ for k in prefs.keys(section):
+ value = prefs.get_value(section, k)
+ ch = prefs.typing_from_config_key(k)
+ if ch == '':
+ continue
+ cls._set_bus_table(ch, value)
+ for k in prefs.get_value(section_base, 'newkeys'):
+ value = prefs.get_value_direct(section, k)
+ ch = prefs.typing_from_config_key(k)
+ if ch == '':
+ continue
+ cls._set_bus_table(ch, value)
+ else:
+ for k in list(_table.keys()):
+ for c in _table_static[k]:
+ cls._r_table[c] = k
+
+ @classmethod
+ def _set_bus_table(cls, key, value):
+ prefs = cls._prefs
+ if value == None or len(value) != 3:
+ return
+ if value[0] == '' and \
+ value[1] == '' and value[2] == '':
+ return
+ for c in value:
+ cls._r_table[c] = key
+
+ def is_finished(self):
+ return not (self._jachars in _UNFINISHED_HIRAGANA)
+
+ def append(self, enchar):
+ if enchar == '\0' or enchar == '':
+ return []
+ text = self._jachars + enchar
+ jachars = kana_voiced_consonant_rule.get(text, None)
+ if jachars:
+ self._enchars = self._enchars + self._r_table.get(enchar, '')
+ self._jachars = jachars
+ return []
+ return [ThumbShiftSegment(enchar)]
+
+ def prepend(self, enchar):
+ if enchar == '\0' or enchar == '':
+ return []
+ if self._jachars == '':
+ if 0x21 <= enchars <= 0x7e:
+ self._enchars = enchar
+ self._jachars = segment.unichar_half_to_full(enchars)
+ else:
+ self._enchars = self._r_table.get(enchar, '')
+ self._jachars = enchar
+ return []
+ return [ThumbShiftSegment(enchar)]
+
+ def pop(self, index=-1):
+ self._enchars = ''
+ self._jachars = ''
+ return
+