diff options
Diffstat (limited to 'engine/python3/thumb.py')
-rw-r--r-- | engine/python3/thumb.py | 657 |
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 + |