summaryrefslogtreecommitdiff
path: root/engine/python3/thumb.py
diff options
context:
space:
mode:
Diffstat (limited to 'engine/python3/thumb.py')
-rw-r--r--engine/python3/thumb.py657
1 files changed, 657 insertions, 0 deletions
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
+