diff -ruN google-mozc-git/src/BUILD.fcitx5.bazel fcitx-mozc-git/src/BUILD.fcitx5.bazel --- google-mozc-git/src/BUILD.fcitx5.bazel 1970-01-01 02:00:00.000000000 +0200 +++ fcitx-mozc-git/src/BUILD.fcitx5.bazel 2022-01-31 13:12:52.548863897 +0200 @@ -0,0 +1,28 @@ +package( + default_visibility = ["//visibility:public"], +) + +# This rule is created from pkg-config +# +# packages="fcitx" +# copts, hdrs, indludes: pkg-config --cflags $packages +# linkopts: pkg-config --libs-only-l $packages + +cc_library( + name = "fcitx5", + hdrs = glob([ + "include/Fcitx5/**", + ]), + copts = ["-pthread"], + includes = [ + "include/Fcitx5/Core", + "include/Fcitx5/Config", + "include/Fcitx5/Utils", + "include/Fcitx5/Module", + ], + linkopts = [ + "-lFcitx5Core", + "-lFcitx5Config", + "-lFcitx5Utils", + ], +) diff -ruN google-mozc-git/src/unix/fcitx5/BUILD fcitx-mozc-git/src/unix/fcitx5/BUILD --- google-mozc-git/src/unix/fcitx5/BUILD 1970-01-01 02:00:00.000000000 +0200 +++ fcitx-mozc-git/src/unix/fcitx5/BUILD 2022-01-31 13:12:52.978869317 +0200 @@ -0,0 +1,101 @@ +load( + "//:build_defs.bzl", + "cc_binary_mozc", + "cc_library_mozc", +) + +package(default_visibility = ["//:__subpackages__"]) + +cc_library_mozc( + name = "mozc_connection", + srcs = ["mozc_connection.cc"], + hdrs = ["mozc_connection.h"], + deps = [ + ":fcitx_key_util", + ":surrounding_text_util", + "//base:port", + "//base:util", + "//client:client", + "//session:ime_switch_util", + "//protocol:commands_cc_proto", + ] +) + +cc_library_mozc( + name = "mozc_engine", + srcs = [ + "mozc_engine.cc", + "mozc_response_parser.cc", + "mozc_state.cc" + ], + hdrs = [ + "mozc_engine.h", + "mozc_response_parser.h", + "mozc_state.h" + ], + local_defines = [ + 'FCITX_GETTEXT_DOMAIN=\\"fcitx5-mozc\\"', + ], + deps = [ + ":mozc_connection", + ":fcitx_key_util", + ":surrounding_text_util", + "//base:base", + "//base:init_mozc", + "//base:port", + "//base:process", + "//base:run_level", + "//base:util", + "//protocol:commands_cc_proto", + "//client:client_interface", + "@fcitx5//:fcitx5", + ], +) + +cc_library_mozc( + name = "fcitx_key_util", + srcs = [ + "fcitx_key_event_handler.cc", + "fcitx_key_translator.cc", + ], + hdrs = [ + "fcitx_key_event_handler.h", + "fcitx_key_translator.h", + ], + deps = [ + "//base:logging", + "//base:port", + "//protocol:config_cc_proto", + "//protocol:commands_cc_proto", + "@fcitx5//:fcitx5", + ], +) + +cc_library_mozc( + name = "surrounding_text_util", + srcs = [ + "surrounding_text_util.cc", + ], + hdrs = [ + "surrounding_text_util.h", + ], + deps = [ + "//base:util", + "//base:logging", + "//base:port", + "@fcitx5//:fcitx5", + ], +) + +cc_binary_mozc( + name = "fcitx5-mozc.so", + srcs = [ + "mozc_engine_factory.cc" + ], + deps = [ + ":mozc_engine", + ], + linkstatic = 1, + linkshared = 1, +) + diff -ruN google-mozc-git/src/unix/fcitx5/fcitx5.gyp fcitx-mozc-git/src/unix/fcitx5/fcitx5.gyp --- google-mozc-git/src/unix/fcitx5/fcitx5.gyp 1970-01-01 02:00:00.000000000 +0200 +++ fcitx-mozc-git/src/unix/fcitx5/fcitx5.gyp 2022-01-31 13:12:52.978869317 +0200 @@ -0,0 +1,118 @@ +# +# Copyright (c) 2010-2017 fcitx Project http://github.com/fcitx/ +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of authors nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + +{ + 'variables': { + 'use_fcitx5%': 'YES', + 'relative_dir': 'unix/fcitx5', + 'gen_out_dir': '<(SHARED_INTERMEDIATE_DIR)/<(relative_dir)', + 'fcitx_dependencies': [ + '../../base/base.gyp:base', + '../../client/client.gyp:client', + '../../ipc/ipc.gyp:ipc', + '../../session/session_base.gyp:ime_switch_util', + '../../protocol/protocol.gyp:commands_proto', + ], + }, + 'conditions': [['use_fcitx5=="YES"', { + 'targets': [ + { + # Meta target to set up build environment for fcitx5. Required 'cflags' + # and 'link_settings' will be automatically injected into any target + # which directly or indirectly depends on this target. + 'target_name': 'fcitx5_build_environment', + 'type': 'none', + 'variables': { + 'target_libs': [ + 'Fcitx5Core', + 'Fcitx5Config', + 'Fcitx5Utils', + 'Fcitx5Module', + ], + }, + 'all_dependent_settings': { + 'cflags': [ + ' +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "unix/fcitx5/fcitx_key_event_handler.h" + +#include + +#include "base/logging.h" +#include "base/singleton.h" + +namespace fcitx { + +namespace { +// TODO(hsumita): Removes this class, and moves |data_| into member +// variables of KeyEventhandler. +class AdditionalModifiersData { + public: + AdditionalModifiersData() { + data_[mozc::commands::KeyEvent::LEFT_ALT] = mozc::commands::KeyEvent::ALT; + data_[mozc::commands::KeyEvent::RIGHT_ALT] = mozc::commands::KeyEvent::ALT; + data_[mozc::commands::KeyEvent::LEFT_CTRL] = mozc::commands::KeyEvent::CTRL; + data_[mozc::commands::KeyEvent::RIGHT_CTRL] = + mozc::commands::KeyEvent::CTRL; + data_[mozc::commands::KeyEvent::LEFT_SHIFT] = + mozc::commands::KeyEvent::SHIFT; + data_[mozc::commands::KeyEvent::RIGHT_SHIFT] = + mozc::commands::KeyEvent::SHIFT; + } + const std::map &data() { + return data_; + } + + private: + std::map data_; +}; + +// TODO(hsumita): Moves this function into member functions of +// KeyEventHandler. +void AddAdditionalModifiers( + std::set *modifier_keys_set) { + DCHECK(modifier_keys_set); + + const std::map &data = + mozc::Singleton::get()->data(); + + // Adds MODIFIER if there are (LEFT|RIGHT)_MODIFIER like LEFT_SHIFT. + for (std::set::const_iterator it = + modifier_keys_set->begin(); + it != modifier_keys_set->end(); ++it) { + std::map::const_iterator + item = data.find(*it); + if (item != data.end()) { + modifier_keys_set->insert(item->second); + } + } +} + +bool IsModifierToBeSentOnKeyUp(const mozc::commands::KeyEvent &key_event) { + if (key_event.modifier_keys_size() == 0) { + return false; + } + + if (key_event.modifier_keys_size() == 1 && + key_event.modifier_keys(0) == mozc::commands::KeyEvent::CAPS) { + return false; + } + + return true; +} +} // namespace + +KeyEventHandler::KeyEventHandler() : key_translator_(new KeyTranslator) { + Clear(); +} + +bool KeyEventHandler::GetKeyEvent( + KeySym keyval, uint32 keycode, KeyStates modifiers, + mozc::config::Config::PreeditMethod preedit_method, bool layout_is_jp, + bool is_key_up, mozc::commands::KeyEvent *key) { + DCHECK(key); + key->Clear(); + + if (!key_translator_->Translate(keyval, keycode, modifiers, preedit_method, + layout_is_jp, key)) { + LOG(ERROR) << "Translate failed"; + return false; + } + + return ProcessModifiers(is_key_up, keyval, key); +} + +void KeyEventHandler::Clear() { + is_non_modifier_key_pressed_ = false; + currently_pressed_modifiers_.clear(); + modifiers_to_be_sent_.clear(); +} + +bool KeyEventHandler::ProcessModifiers(bool is_key_up, uint32 keyval, + mozc::commands::KeyEvent *key_event) { + // Manage modifier key event. + // Modifier key event is sent on key up if non-modifier key has not been + // pressed since key down of modifier keys and no modifier keys are pressed + // anymore. + // Following examples are expected behaviors. + // + // E.g.) Shift key is special. If Shift + printable key is pressed, key event + // does NOT have shift modifiers. It is handled by KeyTranslator class. + // + // Shift down | None + // "a" down | A + // "a" up | None + // Shift up | None + // + // E.g.) Usual key is sent on key down. Modifier keys are not sent if usual + // key is sent. + // + // Ctrl down | None + // "a" down | Ctrl+a + // "a" up | None + // Ctrl up | None + // + // E.g.) Modifier key is sent on key up. + // + // Shift down | None + // Shift up | Shift + // + // E.g.) Multiple modifier keys are sent on the last key up. + // + // Shift down | None + // Control down | None + // Shift up | None + // Control up | Control+Shift + // + // Essentialy we cannot handle modifier key evnet perfectly because + // - We cannot get current keyboard status with ibus. If some modifiers + // are pressed or released without focusing the target window, we + // cannot handle it. + // E.g.) + // + // Ctrl down | None + // (focuses out, Ctrl up, focuses in) + // Shift down | None + // Shift up | None (But we should send Shift key) + // To avoid a inconsistent state as much as possible, we clear states + // when key event without modifier keys is sent. + + const bool is_modifier_only = + !(key_event->has_key_code() || key_event->has_special_key()); + + // We may get only up/down key event when a user moves a focus. + // This code handles such situation as much as possible. + // This code has a bug. If we send Shift + 'a', KeyTranslator removes a shift + // modifier and converts 'a' to 'A'. This codes does NOT consider these + // situation since we don't have enough data to handle it. + // TODO(hsumita): Moves the logic about a handling of Shift or Caps keys from + // KeyTranslator to MozcEngine. + if (key_event->modifier_keys_size() == 0) { + Clear(); + } + + if (!currently_pressed_modifiers_.empty() && !is_modifier_only) { + is_non_modifier_key_pressed_ = true; + } + if (is_non_modifier_key_pressed_) { + modifiers_to_be_sent_.clear(); + } + + if (is_key_up) { + currently_pressed_modifiers_.erase(keyval); + if (!is_modifier_only) { + return false; + } + if (!currently_pressed_modifiers_.empty() || + modifiers_to_be_sent_.empty()) { + is_non_modifier_key_pressed_ = false; + return false; + } + if (is_non_modifier_key_pressed_) { + return false; + } + DCHECK(!is_non_modifier_key_pressed_); + + // Modifier key event fires + key_event->mutable_modifier_keys()->Clear(); + for (std::set::const_iterator it = + modifiers_to_be_sent_.begin(); + it != modifiers_to_be_sent_.end(); ++it) { + key_event->add_modifier_keys(*it); + } + modifiers_to_be_sent_.clear(); + } else if (is_modifier_only) { + // TODO(hsumita): Supports a key sequence below. + // - Ctrl down + // - a down + // - Alt down + // We should add Alt key to |currently_pressed_modifiers|, but current + // implementation does NOT do it. + if (currently_pressed_modifiers_.empty() || + !modifiers_to_be_sent_.empty()) { + for (size_t i = 0; i < key_event->modifier_keys_size(); ++i) { + modifiers_to_be_sent_.insert(key_event->modifier_keys(i)); + } + AddAdditionalModifiers(&modifiers_to_be_sent_); + } + currently_pressed_modifiers_.insert(keyval); + return false; + } + + // Clear modifier data just in case if |key| has no modifier keys. + if (!IsModifierToBeSentOnKeyUp(*key_event)) { + Clear(); + } + + return true; +} + +} // namespace fcitx diff -ruN google-mozc-git/src/unix/fcitx5/fcitx_key_event_handler.h fcitx-mozc-git/src/unix/fcitx5/fcitx_key_event_handler.h --- google-mozc-git/src/unix/fcitx5/fcitx_key_event_handler.h 1970-01-01 02:00:00.000000000 +0200 +++ fcitx-mozc-git/src/unix/fcitx5/fcitx_key_event_handler.h 2022-01-31 13:12:52.982202692 +0200 @@ -0,0 +1,79 @@ +// Copyright 2010-2012, Google Inc. +// Copyright 2012-2017, Weng Xuetian +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef UNIX_FCITX5_FCITX_KEY_EVENT_HANDLER_H_ +#define UNIX_FCITX5_FCITX_KEY_EVENT_HANDLER_H_ + +#include + +#include +#include + +#include "base/port.h" +#include "protocol/commands.pb.h" +#include "protocol/config.pb.h" +#include "unix/fcitx5/fcitx_key_translator.h" + +namespace fcitx { + +class KeyEventHandler { + public: + KeyEventHandler(); + + // Converts a key event came from fcitx to commands::KeyEvent. This is a + // stateful method. It stores modifier keys states since ibus doesn't send + // an enough information about the modifier keys. + bool GetKeyEvent(KeySym keyval, uint32 keycode, KeyStates modifiers, + mozc::config::Config::PreeditMethod preedit_method, + bool layout_is_jp, bool is_key_up, + mozc::commands::KeyEvent *key); + + // Clears states. + void Clear(); + + private: + // Manages modifier keys. Returns false if it should not be sent to server. + bool ProcessModifiers(bool is_key_up, uint32 keyval, + mozc::commands::KeyEvent *key_event); + + std::unique_ptr key_translator_; + // Non modifier key is pressed or not after all keys are released. + bool is_non_modifier_key_pressed_; + // Currently pressed modifier keys. It is set of keyval. + std::set currently_pressed_modifiers_; + // Pending modifier keys. + std::set modifiers_to_be_sent_; + + DISALLOW_COPY_AND_ASSIGN(KeyEventHandler); +}; + +} // namespace fcitx + +#endif // UNIX_FCITX5_FCITX_KEY_EVENT_HANDLER_H_ diff -ruN google-mozc-git/src/unix/fcitx5/fcitx_key_translator.cc fcitx-mozc-git/src/unix/fcitx5/fcitx_key_translator.cc --- google-mozc-git/src/unix/fcitx5/fcitx_key_translator.cc 1970-01-01 02:00:00.000000000 +0200 +++ fcitx-mozc-git/src/unix/fcitx5/fcitx_key_translator.cc 2022-01-31 13:12:52.982202692 +0200 @@ -0,0 +1,526 @@ +// Copyright 2010-2012, Google Inc. +// Copyright 2012-2017, Weng Xuetian +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "unix/fcitx5/fcitx_key_translator.h" + +#include "base/logging.h" + +namespace fcitx { + +namespace { + +const struct { + uint32 from; + mozc::commands::KeyEvent::SpecialKey to; +} special_key_map[] = { + {FcitxKey_VoidSymbol, mozc::commands::KeyEvent::NO_SPECIALKEY}, + {FcitxKey_space, mozc::commands::KeyEvent::SPACE}, + {FcitxKey_Return, mozc::commands::KeyEvent::ENTER}, + {FcitxKey_Left, mozc::commands::KeyEvent::LEFT}, + {FcitxKey_Right, mozc::commands::KeyEvent::RIGHT}, + {FcitxKey_Up, mozc::commands::KeyEvent::UP}, + {FcitxKey_Down, mozc::commands::KeyEvent::DOWN}, + {FcitxKey_Escape, mozc::commands::KeyEvent::ESCAPE}, + {FcitxKey_Delete, mozc::commands::KeyEvent::DEL}, + {FcitxKey_BackSpace, mozc::commands::KeyEvent::BACKSPACE}, + {FcitxKey_Insert, mozc::commands::KeyEvent::INSERT}, + {FcitxKey_Henkan, mozc::commands::KeyEvent::HENKAN}, + {FcitxKey_Muhenkan, mozc::commands::KeyEvent::MUHENKAN}, + {FcitxKey_Hiragana, mozc::commands::KeyEvent::KANA}, + {FcitxKey_Hiragana_Katakana, mozc::commands::KeyEvent::KANA}, + {FcitxKey_Katakana, mozc::commands::KeyEvent::KATAKANA}, + {FcitxKey_Zenkaku, mozc::commands::KeyEvent::HANKAKU}, + {FcitxKey_Hankaku, mozc::commands::KeyEvent::HANKAKU}, + {FcitxKey_Zenkaku_Hankaku, mozc::commands::KeyEvent::HANKAKU}, + {FcitxKey_Eisu_toggle, mozc::commands::KeyEvent::EISU}, + {FcitxKey_Home, mozc::commands::KeyEvent::HOME}, + {FcitxKey_End, mozc::commands::KeyEvent::END}, + {FcitxKey_Tab, mozc::commands::KeyEvent::TAB}, + {FcitxKey_F1, mozc::commands::KeyEvent::F1}, + {FcitxKey_F2, mozc::commands::KeyEvent::F2}, + {FcitxKey_F3, mozc::commands::KeyEvent::F3}, + {FcitxKey_F4, mozc::commands::KeyEvent::F4}, + {FcitxKey_F5, mozc::commands::KeyEvent::F5}, + {FcitxKey_F6, mozc::commands::KeyEvent::F6}, + {FcitxKey_F7, mozc::commands::KeyEvent::F7}, + {FcitxKey_F8, mozc::commands::KeyEvent::F8}, + {FcitxKey_F9, mozc::commands::KeyEvent::F9}, + {FcitxKey_F10, mozc::commands::KeyEvent::F10}, + {FcitxKey_F11, mozc::commands::KeyEvent::F11}, + {FcitxKey_F12, mozc::commands::KeyEvent::F12}, + {FcitxKey_F13, mozc::commands::KeyEvent::F13}, + {FcitxKey_F14, mozc::commands::KeyEvent::F14}, + {FcitxKey_F15, mozc::commands::KeyEvent::F15}, + {FcitxKey_F16, mozc::commands::KeyEvent::F16}, + {FcitxKey_F17, mozc::commands::KeyEvent::F17}, + {FcitxKey_F18, mozc::commands::KeyEvent::F18}, + {FcitxKey_F19, mozc::commands::KeyEvent::F19}, + {FcitxKey_F20, mozc::commands::KeyEvent::F20}, + {FcitxKey_F21, mozc::commands::KeyEvent::F21}, + {FcitxKey_F22, mozc::commands::KeyEvent::F22}, + {FcitxKey_F23, mozc::commands::KeyEvent::F23}, + {FcitxKey_F24, mozc::commands::KeyEvent::F24}, + {FcitxKey_Page_Up, mozc::commands::KeyEvent::PAGE_UP}, + {FcitxKey_Page_Down, mozc::commands::KeyEvent::PAGE_DOWN}, + + // Keypad (10-key). + {FcitxKey_KP_0, mozc::commands::KeyEvent::NUMPAD0}, + {FcitxKey_KP_1, mozc::commands::KeyEvent::NUMPAD1}, + {FcitxKey_KP_2, mozc::commands::KeyEvent::NUMPAD2}, + {FcitxKey_KP_3, mozc::commands::KeyEvent::NUMPAD3}, + {FcitxKey_KP_4, mozc::commands::KeyEvent::NUMPAD4}, + {FcitxKey_KP_5, mozc::commands::KeyEvent::NUMPAD5}, + {FcitxKey_KP_6, mozc::commands::KeyEvent::NUMPAD6}, + {FcitxKey_KP_7, mozc::commands::KeyEvent::NUMPAD7}, + {FcitxKey_KP_8, mozc::commands::KeyEvent::NUMPAD8}, + {FcitxKey_KP_9, mozc::commands::KeyEvent::NUMPAD9}, + {FcitxKey_KP_Equal, mozc::commands::KeyEvent::EQUALS}, // [=] + {FcitxKey_KP_Multiply, mozc::commands::KeyEvent::MULTIPLY}, // [*] + {FcitxKey_KP_Add, mozc::commands::KeyEvent::ADD}, // [+] + {FcitxKey_KP_Separator, mozc::commands::KeyEvent::SEPARATOR}, // enter + {FcitxKey_KP_Subtract, mozc::commands::KeyEvent::SUBTRACT}, // [-] + {FcitxKey_KP_Decimal, mozc::commands::KeyEvent::DECIMAL}, // [.] + {FcitxKey_KP_Divide, mozc::commands::KeyEvent::DIVIDE}, // [/] + {FcitxKey_KP_Space, mozc::commands::KeyEvent::SPACE}, + {FcitxKey_KP_Tab, mozc::commands::KeyEvent::TAB}, + {FcitxKey_KP_Enter, mozc::commands::KeyEvent::ENTER}, + {FcitxKey_KP_Home, mozc::commands::KeyEvent::HOME}, + {FcitxKey_KP_Left, mozc::commands::KeyEvent::LEFT}, + {FcitxKey_KP_Up, mozc::commands::KeyEvent::UP}, + {FcitxKey_KP_Right, mozc::commands::KeyEvent::RIGHT}, + {FcitxKey_KP_Down, mozc::commands::KeyEvent::DOWN}, + {FcitxKey_KP_Page_Up, mozc::commands::KeyEvent::PAGE_UP}, + {FcitxKey_KP_Page_Down, mozc::commands::KeyEvent::PAGE_DOWN}, + {FcitxKey_KP_End, mozc::commands::KeyEvent::END}, + {FcitxKey_KP_Delete, mozc::commands::KeyEvent::DEL}, + {FcitxKey_KP_Insert, mozc::commands::KeyEvent::INSERT}, + {FcitxKey_Caps_Lock, mozc::commands::KeyEvent::CAPS_LOCK}, + + // Shift+TAB. + {FcitxKey_ISO_Left_Tab, mozc::commands::KeyEvent::TAB}, + + // TODO(mazda): Handle following keys? + // - FcitxKey_Kana_Lock? FcitxKey_KEY_Kana_Shift? +}; + +const struct { + uint32 from; + mozc::commands::KeyEvent::ModifierKey to; +} modifier_key_map[] = { + {FcitxKey_Shift_L, mozc::commands::KeyEvent::LEFT_SHIFT}, + {FcitxKey_Shift_R, mozc::commands::KeyEvent::RIGHT_SHIFT}, + {FcitxKey_Control_L, mozc::commands::KeyEvent::LEFT_CTRL}, + {FcitxKey_Control_R, mozc::commands::KeyEvent::RIGHT_CTRL}, + {FcitxKey_Alt_L, mozc::commands::KeyEvent::LEFT_ALT}, + {FcitxKey_Alt_R, mozc::commands::KeyEvent::RIGHT_ALT}, + {static_cast(KeyState::CapsLock), mozc::commands::KeyEvent::CAPS}, +}; + +const struct { + uint32 from; + mozc::commands::KeyEvent::ModifierKey to; +} modifier_mask_map[] = { + {static_cast(KeyState::Shift), mozc::commands::KeyEvent::SHIFT}, + {static_cast(KeyState::Ctrl), mozc::commands::KeyEvent::CTRL}, + {static_cast(KeyState::Alt), mozc::commands::KeyEvent::ALT}, +}; + +// TODO(team): Add kana_map_dv to support Dvoraklayout. +const struct { + uint32 code; + const char *no_shift; + const char *shift; +} kana_map_jp[] = + { + {'1', "\xe3\x81\xac", "\xe3\x81\xac"}, // "ぬ", "ぬ" + {'!', "\xe3\x81\xac", "\xe3\x81\xac"}, // "ぬ", "ぬ" + {'2', "\xe3\x81\xb5", "\xe3\x81\xb5"}, // "ふ", "ふ" + {'\"', "\xe3\x81\xb5", "\xe3\x81\xb5"}, // "ふ", "ふ" + {'3', "\xe3\x81\x82", "\xe3\x81\x81"}, // "あ", "ぁ" + {'#', "\xe3\x81\x82", "\xe3\x81\x81"}, // "あ", "ぁ" + {'4', "\xe3\x81\x86", "\xe3\x81\x85"}, // "う", "ぅ" + {'$', "\xe3\x81\x86", "\xe3\x81\x85"}, // "う", "ぅ" + {'5', "\xe3\x81\x88", "\xe3\x81\x87"}, // "え", "ぇ" + {'%', "\xe3\x81\x88", "\xe3\x81\x87"}, // "え", "ぇ" + {'6', "\xe3\x81\x8a", "\xe3\x81\x89"}, // "お", "ぉ" + {'&', "\xe3\x81\x8a", "\xe3\x81\x89"}, // "お", "ぉ" + {'7', "\xe3\x82\x84", "\xe3\x82\x83"}, // "や", "ゃ" + {'\'', "\xe3\x82\x84", "\xe3\x82\x83"}, // "や", "ゃ" + {'8', "\xe3\x82\x86", "\xe3\x82\x85"}, // "ゆ", "ゅ" + {'(', "\xe3\x82\x86", "\xe3\x82\x85"}, // "ゆ", "ゅ" + {'9', "\xe3\x82\x88", "\xe3\x82\x87"}, // "よ", "ょ" + {')', "\xe3\x82\x88", "\xe3\x82\x87"}, // "よ", "ょ" + {'0', "\xe3\x82\x8f", "\xe3\x82\x92"}, // "わ", "を" + {'-', "\xe3\x81\xbb", "\xe3\x81\xbb"}, // "ほ", "ほ" + {'=', "\xe3\x81\xbb", "\xe3\x81\xbb"}, // "ほ", "ほ" + {'^', "\xe3\x81\xb8", "\xe3\x82\x92"}, // "へ", "を" + {'~', "\xe3\x81\xb8", "\xe3\x82\x92"}, // "へ", "を" + {'|', "\xe3\x83\xbc", "\xe3\x83\xbc"}, // "ー", "ー" + {'q', "\xe3\x81\x9f", "\xe3\x81\x9f"}, // "た", "た" + {'Q', "\xe3\x81\x9f", "\xe3\x81\x9f"}, // "た", "た" + {'w', "\xe3\x81\xa6", "\xe3\x81\xa6"}, // "て", "て" + {'W', "\xe3\x81\xa6", "\xe3\x81\xa6"}, // "て", "て" + {'e', "\xe3\x81\x84", "\xe3\x81\x83"}, // "い", "ぃ" + {'E', "\xe3\x81\x84", "\xe3\x81\x83"}, // "い", "ぃ" + {'r', "\xe3\x81\x99", "\xe3\x81\x99"}, // "す", "す" + {'R', "\xe3\x81\x99", "\xe3\x81\x99"}, // "す", "す" + {'t', "\xe3\x81\x8b", "\xe3\x81\x8b"}, // "か", "か" + {'T', "\xe3\x81\x8b", "\xe3\x81\x8b"}, // "か", "か" + {'y', "\xe3\x82\x93", "\xe3\x82\x93"}, // "ん", "ん" + {'Y', "\xe3\x82\x93", "\xe3\x82\x93"}, // "ん", "ん" + {'u', "\xe3\x81\xaa", "\xe3\x81\xaa"}, // "な", "な" + {'U', "\xe3\x81\xaa", "\xe3\x81\xaa"}, // "な", "な" + {'i', "\xe3\x81\xab", "\xe3\x81\xab"}, // "に", "に" + {'I', "\xe3\x81\xab", "\xe3\x81\xab"}, // "に", "に" + {'o', "\xe3\x82\x89", "\xe3\x82\x89"}, // "ら", "ら" + {'O', "\xe3\x82\x89", "\xe3\x82\x89"}, // "ら", "ら" + {'p', "\xe3\x81\x9b", "\xe3\x81\x9b"}, // "せ", "せ" + {'P', "\xe3\x81\x9b", "\xe3\x81\x9b"}, // "せ", "せ" + {'@', "\xe3\x82\x9b", "\xe3\x82\x9b"}, // "゛", "゛" + {'`', "\xe3\x82\x9b", "\xe3\x82\x9b"}, // "゛", "゛" + {'[', "\xe3\x82\x9c", "\xe3\x80\x8c"}, // "゜", "「" + {'{', "\xe3\x82\x9c", "\xe3\x80\x8c"}, // "゜", "「" + {'a', "\xe3\x81\xa1", "\xe3\x81\xa1"}, // "ち", "ち" + {'A', "\xe3\x81\xa1", "\xe3\x81\xa1"}, // "ち", "ち" + {'s', "\xe3\x81\xa8", "\xe3\x81\xa8"}, // "と", "と" + {'S', "\xe3\x81\xa8", "\xe3\x81\xa8"}, // "と", "と" + {'d', "\xe3\x81\x97", "\xe3\x81\x97"}, // "し", "し" + {'D', "\xe3\x81\x97", "\xe3\x81\x97"}, // "し", "し" + {'f', "\xe3\x81\xaf", "\xe3\x81\xaf"}, // "は", "は" + {'F', "\xe3\x81\xaf", "\xe3\x81\xaf"}, // "は", "は" + {'g', "\xe3\x81\x8d", "\xe3\x81\x8d"}, // "き", "き" + {'G', "\xe3\x81\x8d", "\xe3\x81\x8d"}, // "き", "き" + {'h', "\xe3\x81\x8f", "\xe3\x81\x8f"}, // "く", "く" + {'H', "\xe3\x81\x8f", "\xe3\x81\x8f"}, // "く", "く" + {'j', "\xe3\x81\xbe", "\xe3\x81\xbe"}, // "ま", "ま" + {'J', "\xe3\x81\xbe", "\xe3\x81\xbe"}, // "ま", "ま" + {'k', "\xe3\x81\xae", "\xe3\x81\xae"}, // "の", "の" + {'K', "\xe3\x81\xae", "\xe3\x81\xae"}, // "の", "の" + {'l', "\xe3\x82\x8a", "\xe3\x82\x8a"}, // "り", "り" + {'L', "\xe3\x82\x8a", "\xe3\x82\x8a"}, // "り", "り" + {';', "\xe3\x82\x8c", "\xe3\x82\x8c"}, // "れ", "れ" + {'+', "\xe3\x82\x8c", "\xe3\x82\x8c"}, // "れ", "れ" + {':', "\xe3\x81\x91", "\xe3\x81\x91"}, // "け", "け" + {'*', "\xe3\x81\x91", "\xe3\x81\x91"}, // "け", "け" + {']', "\xe3\x82\x80", "\xe3\x80\x8d"}, // "む", "」" + {'}', "\xe3\x82\x80", "\xe3\x80\x8d"}, // "む", "」" + {'z', "\xe3\x81\xa4", "\xe3\x81\xa3"}, // "つ", "っ" + {'Z', "\xe3\x81\xa4", "\xe3\x81\xa3"}, // "つ", "っ" + {'x', "\xe3\x81\x95", "\xe3\x81\x95"}, // "さ", "さ" + {'X', "\xe3\x81\x95", "\xe3\x81\x95"}, // "さ", "さ" + {'c', "\xe3\x81\x9d", "\xe3\x81\x9d"}, // "そ", "そ" + {'C', "\xe3\x81\x9d", "\xe3\x81\x9d"}, // "そ", "そ" + {'v', "\xe3\x81\xb2", "\xe3\x81\xb2"}, // "ひ", "ひ" + {'V', "\xe3\x81\xb2", "\xe3\x81\xb2"}, // "ひ", "ひ" + {'b', "\xe3\x81\x93", "\xe3\x81\x93"}, // "こ", "こ" + {'B', "\xe3\x81\x93", "\xe3\x81\x93"}, // "こ", "こ" + {'n', "\xe3\x81\xbf", "\xe3\x81\xbf"}, // "み", "み" + {'N', "\xe3\x81\xbf", "\xe3\x81\xbf"}, // "み", "み" + {'m', "\xe3\x82\x82", "\xe3\x82\x82"}, // "も", "も" + {'M', "\xe3\x82\x82", "\xe3\x82\x82"}, // "も", "も" + {',', "\xe3\x81\xad", "\xe3\x80\x81"}, // "ね", "、" + {'<', "\xe3\x81\xad", "\xe3\x80\x81"}, // "ね", "、" + {'.', "\xe3\x82\x8b", "\xe3\x80\x82"}, // "る", "。" + {'>', "\xe3\x82\x8b", "\xe3\x80\x82"}, // "る", "。" + {'/', "\xe3\x82\x81", "\xe3\x83\xbb"}, // "め", "・" + {'?', "\xe3\x82\x81", "\xe3\x83\xbb"}, // "め", "・" + {'_', "\xe3\x82\x8d", "\xe3\x82\x8d"}, // "ろ", "ろ" + // A backslash is handled in a special way because it is input by + // two different keys (the one next to Backslash and the one next + // to Right Shift). + {'\\', "", ""}, +}, + kana_map_us[] = { + {'`', "\xe3\x82\x8d", "\xe3\x82\x8d"}, // "ろ", "ろ" + {'~', "\xe3\x82\x8d", "\xe3\x82\x8d"}, // "ろ", "ろ" + {'1', "\xe3\x81\xac", "\xe3\x81\xac"}, // "ぬ", "ぬ" + {'!', "\xe3\x81\xac", "\xe3\x81\xac"}, // "ぬ", "ぬ" + {'2', "\xe3\x81\xb5", "\xe3\x81\xb5"}, // "ふ", "ふ" + {'@', "\xe3\x81\xb5", "\xe3\x81\xb5"}, // "ふ", "ふ" + {'3', "\xe3\x81\x82", "\xe3\x81\x81"}, // "あ", "ぁ" + {'#', "\xe3\x81\x82", "\xe3\x81\x81"}, // "あ", "ぁ" + {'4', "\xe3\x81\x86", "\xe3\x81\x85"}, // "う", "ぅ" + {'$', "\xe3\x81\x86", "\xe3\x81\x85"}, // "う", "ぅ" + {'5', "\xe3\x81\x88", "\xe3\x81\x87"}, // "え", "ぇ" + {'%', "\xe3\x81\x88", "\xe3\x81\x87"}, // "え", "ぇ" + {'6', "\xe3\x81\x8a", "\xe3\x81\x89"}, // "お", "ぉ" + {'^', "\xe3\x81\x8a", "\xe3\x81\x89"}, // "お", "ぉ" + {'7', "\xe3\x82\x84", "\xe3\x82\x83"}, // "や", "ゃ" + {'&', "\xe3\x82\x84", "\xe3\x82\x83"}, // "や", "ゃ" + {'8', "\xe3\x82\x86", "\xe3\x82\x85"}, // "ゆ", "ゅ" + {'*', "\xe3\x82\x86", "\xe3\x82\x85"}, // "ゆ", "ゅ" + {'9', "\xe3\x82\x88", "\xe3\x82\x87"}, // "よ", "ょ" + {'(', "\xe3\x82\x88", "\xe3\x82\x87"}, // "よ", "ょ" + {'0', "\xe3\x82\x8f", "\xe3\x82\x92"}, // "わ", "を" + {')', "\xe3\x82\x8f", "\xe3\x82\x92"}, // "わ", "を" + {'-', "\xe3\x81\xbb", "\xe3\x83\xbc"}, // "ほ", "ー" + {'_', "\xe3\x81\xbb", "\xe3\x83\xbc"}, // "ほ", "ー" + {'=', "\xe3\x81\xb8", "\xe3\x81\xb8"}, // "へ", "へ" + {'+', "\xe3\x81\xb8", "\xe3\x81\xb8"}, // "へ", "へ" + {'q', "\xe3\x81\x9f", "\xe3\x81\x9f"}, // "た", "た" + {'Q', "\xe3\x81\x9f", "\xe3\x81\x9f"}, // "た", "た" + {'w', "\xe3\x81\xa6", "\xe3\x81\xa6"}, // "て", "て" + {'W', "\xe3\x81\xa6", "\xe3\x81\xa6"}, // "て", "て" + {'e', "\xe3\x81\x84", "\xe3\x81\x83"}, // "い", "ぃ" + {'E', "\xe3\x81\x84", "\xe3\x81\x83"}, // "い", "ぃ" + {'r', "\xe3\x81\x99", "\xe3\x81\x99"}, // "す", "す" + {'R', "\xe3\x81\x99", "\xe3\x81\x99"}, // "す", "す" + {'t', "\xe3\x81\x8b", "\xe3\x81\x8b"}, // "か", "か" + {'T', "\xe3\x81\x8b", "\xe3\x81\x8b"}, // "か", "か" + {'y', "\xe3\x82\x93", "\xe3\x82\x93"}, // "ん", "ん" + {'Y', "\xe3\x82\x93", "\xe3\x82\x93"}, // "ん", "ん" + {'u', "\xe3\x81\xaa", "\xe3\x81\xaa"}, // "な", "な" + {'U', "\xe3\x81\xaa", "\xe3\x81\xaa"}, // "な", "な" + {'i', "\xe3\x81\xab", "\xe3\x81\xab"}, // "に", "に" + {'I', "\xe3\x81\xab", "\xe3\x81\xab"}, // "に", "に" + {'o', "\xe3\x82\x89", "\xe3\x82\x89"}, // "ら", "ら" + {'O', "\xe3\x82\x89", "\xe3\x82\x89"}, // "ら", "ら" + {'p', "\xe3\x81\x9b", "\xe3\x81\x9b"}, // "せ", "せ" + {'P', "\xe3\x81\x9b", "\xe3\x81\x9b"}, // "せ", "せ" + {'[', "\xe3\x82\x9b", "\xe3\x82\x9b"}, // "゛", "゛" + {'{', "\xe3\x82\x9b", "\xe3\x82\x9b"}, // "゛", "゛" + {']', "\xe3\x82\x9c", "\xe3\x80\x8c"}, // "゜", "「" + {'}', "\xe3\x82\x9c", "\xe3\x80\x8c"}, // "゜", "「" + {'\\', "\xe3\x82\x80", "\xe3\x80\x8d"}, // "む", "」" + {'|', "\xe3\x82\x80", "\xe3\x80\x8d"}, // "む", "」" + {'a', "\xe3\x81\xa1", "\xe3\x81\xa1"}, // "ち", "ち" + {'A', "\xe3\x81\xa1", "\xe3\x81\xa1"}, // "ち", "ち" + {'s', "\xe3\x81\xa8", "\xe3\x81\xa8"}, // "と", "と" + {'S', "\xe3\x81\xa8", "\xe3\x81\xa8"}, // "と", "と" + {'d', "\xe3\x81\x97", "\xe3\x81\x97"}, // "し", "し" + {'D', "\xe3\x81\x97", "\xe3\x81\x97"}, // "し", "し" + {'f', "\xe3\x81\xaf", "\xe3\x81\xaf"}, // "は", "は" + {'F', "\xe3\x81\xaf", "\xe3\x81\xaf"}, // "は", "は" + {'g', "\xe3\x81\x8d", "\xe3\x81\x8d"}, // "き", "き" + {'G', "\xe3\x81\x8d", "\xe3\x81\x8d"}, // "き", "き" + {'h', "\xe3\x81\x8f", "\xe3\x81\x8f"}, // "く", "く" + {'H', "\xe3\x81\x8f", "\xe3\x81\x8f"}, // "く", "く" + {'j', "\xe3\x81\xbe", "\xe3\x81\xbe"}, // "ま", "ま" + {'J', "\xe3\x81\xbe", "\xe3\x81\xbe"}, // "ま", "ま" + {'k', "\xe3\x81\xae", "\xe3\x81\xae"}, // "の", "の" + {'K', "\xe3\x81\xae", "\xe3\x81\xae"}, // "の", "の" + {'l', "\xe3\x82\x8a", "\xe3\x82\x8a"}, // "り", "り" + {'L', "\xe3\x82\x8a", "\xe3\x82\x8a"}, // "り", "り" + {';', "\xe3\x82\x8c", "\xe3\x82\x8c"}, // "れ", "れ" + {':', "\xe3\x82\x8c", "\xe3\x82\x8c"}, // "れ", "れ" + {'\'', "\xe3\x81\x91", "\xe3\x81\x91"}, // "け", "け" + {'\"', "\xe3\x81\x91", "\xe3\x81\x91"}, // "け", "け" + {'z', "\xe3\x81\xa4", "\xe3\x81\xa3"}, // "つ", "っ" + {'Z', "\xe3\x81\xa4", "\xe3\x81\xa3"}, // "つ", "っ" + {'x', "\xe3\x81\x95", "\xe3\x81\x95"}, // "さ", "さ" + {'X', "\xe3\x81\x95", "\xe3\x81\x95"}, // "さ", "さ" + {'c', "\xe3\x81\x9d", "\xe3\x81\x9d"}, // "そ", "そ" + {'C', "\xe3\x81\x9d", "\xe3\x81\x9d"}, // "そ", "そ" + {'v', "\xe3\x81\xb2", "\xe3\x81\xb2"}, // "ひ", "ひ" + {'V', "\xe3\x81\xb2", "\xe3\x81\xb2"}, // "ひ", "ひ" + {'b', "\xe3\x81\x93", "\xe3\x81\x93"}, // "こ", "こ" + {'B', "\xe3\x81\x93", "\xe3\x81\x93"}, // "こ", "こ" + {'n', "\xe3\x81\xbf", "\xe3\x81\xbf"}, // "み", "み" + {'N', "\xe3\x81\xbf", "\xe3\x81\xbf"}, // "み", "み" + {'m', "\xe3\x82\x82", "\xe3\x82\x82"}, // "も", "も" + {'M', "\xe3\x82\x82", "\xe3\x82\x82"}, // "も", "も" + {',', "\xe3\x81\xad", "\xe3\x80\x81"}, // "ね", "、" + {'<', "\xe3\x81\xad", "\xe3\x80\x81"}, // "ね", "、" + {'.', "\xe3\x82\x8b", "\xe3\x80\x82"}, // "る", "。" + {'>', "\xe3\x82\x8b", "\xe3\x80\x82"}, // "る", "。" + {'/', "\xe3\x82\x81", "\xe3\x83\xbb"}, // "め", "・" + {'?', "\xe3\x82\x81", "\xe3\x83\xbb"}, // "め", "・" +}; + +} // namespace + +KeyTranslator::KeyTranslator() { Init(); } + +KeyTranslator::~KeyTranslator() {} + +// TODO(nona): Fix 'Shift-0' behavior b/4338394 +bool KeyTranslator::Translate(KeySym keyval, uint32 keycode, + KeyStates modifiers, + mozc::config::Config::PreeditMethod method, + bool layout_is_jp, + mozc::commands::KeyEvent *out_event) const { + DCHECK(out_event) << "out_event is NULL"; + out_event->Clear(); + + /* this is key we cannot handle, don't process it */ + if (modifiers & KeyState::Super) return false; + + // Due to historical reasons, many linux ditributions set Hiragana_Katakana + // key as Hiragana key (which is Katkana key with shift modifier). So, we + // translate Hiragana_Katanaka key as Hiragana key by mapping table, and + // Shift + Hiragana_Katakana key as Katakana key by functionally. + // TODO(nona): Fix process modifier to handle right shift + if (IsHiraganaKatakanaKeyWithShift(keyval, keycode, modifiers)) { + modifiers.unset(KeyState::Shift); + keyval = FcitxKey_Katakana; + } + std::string kana_key_string; + if ((method == mozc::config::Config::KANA) && + IsKanaAvailable(keyval, keycode, modifiers, layout_is_jp, + &kana_key_string)) { + out_event->set_key_code(keyval); + out_event->set_key_string(kana_key_string); + } else if (IsAscii(keyval, keycode, modifiers)) { + if (modifiers & KeyState::CapsLock) { + out_event->add_modifier_keys(mozc::commands::KeyEvent::CAPS); + } + out_event->set_key_code(keyval); + } else if (IsModifierKey(keyval, keycode, modifiers)) { + ModifierKeyMap::const_iterator i = modifier_key_map_.find(keyval); + DCHECK(i != modifier_key_map_.end()); + out_event->add_modifier_keys(i->second); + } else if (IsSpecialKey(keyval, keycode, modifiers)) { + SpecialKeyMap::const_iterator i = special_key_map_.find(keyval); + DCHECK(i != special_key_map_.end()); + out_event->set_special_key(i->second); + } else { + VLOG(1) << "Unknown keyval: " << keyval; + return false; + } + + for (ModifierKeyMap::const_iterator i = modifier_mask_map_.begin(); + i != modifier_mask_map_.end(); ++i) { + // Do not set a SHIFT modifier when |keyval| is a printable key by following + // the Mozc's rule. + if ((i->second == mozc::commands::KeyEvent::SHIFT) && + IsPrintable(keyval, keycode, modifiers)) { + continue; + } + + if (i->first & modifiers) { + out_event->add_modifier_keys(i->second); + } + } + + return true; +} + +void KeyTranslator::Init() { + for (int i = 0; i < arraysize(special_key_map); ++i) { + CHECK(special_key_map_ + .insert(std::make_pair(special_key_map[i].from, + special_key_map[i].to)) + .second); + } + for (int i = 0; i < arraysize(modifier_key_map); ++i) { + CHECK(modifier_key_map_ + .insert(std::make_pair(modifier_key_map[i].from, + modifier_key_map[i].to)) + .second); + } + for (int i = 0; i < arraysize(modifier_mask_map); ++i) { + CHECK(modifier_mask_map_ + .insert(std::make_pair(modifier_mask_map[i].from, + modifier_mask_map[i].to)) + .second); + } + for (int i = 0; i < arraysize(kana_map_jp); ++i) { + CHECK(kana_map_jp_ + .insert(std::make_pair(kana_map_jp[i].code, + std::make_pair(kana_map_jp[i].no_shift, + kana_map_jp[i].shift))) + .second); + } + for (int i = 0; i < arraysize(kana_map_us); ++i) { + CHECK(kana_map_us_ + .insert(std::make_pair(kana_map_us[i].code, + std::make_pair(kana_map_us[i].no_shift, + kana_map_us[i].shift))) + .second); + } +} + +bool KeyTranslator::IsModifierKey(KeySym keyval, uint32 keycode, + KeyStates modifiers) const { + return modifier_key_map_.find(keyval) != modifier_key_map_.end(); +} + +bool KeyTranslator::IsSpecialKey(KeySym keyval, uint32 keycode, + KeyStates modifiers) const { + return special_key_map_.find(keyval) != special_key_map_.end(); +} + +bool KeyTranslator::IsHiraganaKatakanaKeyWithShift(KeySym keyval, + uint32 keycode, + KeyStates modifiers) { + return ((modifiers & KeyState::Shift) && + (keyval == FcitxKey_Hiragana_Katakana)); +} + +bool KeyTranslator::IsKanaAvailable(KeySym keyval, uint32 keycode, + KeyStates modifiers, bool layout_is_jp, + std::string *out) const { + if ((modifiers & KeyState::Ctrl) || (modifiers & KeyState::Alt)) { + return false; + } + const auto &kana_map = layout_is_jp ? kana_map_jp_ : kana_map_us_; + KanaMap::const_iterator iter = kana_map.find(keyval); + if (iter == kana_map.end()) { + return false; + } + + if (out) { + // When a Japanese keyboard is in use, the yen-sign key and the backslash + // key generate the same |keyval|. In this case, we have to check |keycode| + // to return an appropriate string. See the following IBus issue for + // details: http://code.google.com/p/ibus/issues/detail?id=52 + if (keyval == '\\' && layout_is_jp) { + if (keycode == 132 || keycode == 133) { + *out = "\xe3\x83\xbc"; // "ー" + } else { + *out = "\xe3\x82\x8d"; // "ろ" + } + } else { + *out = (modifiers & KeyState::Shift) ? iter->second.second + : iter->second.first; + } + } + return true; +} + +// TODO(nona): resolve S-'0' problem (b/4338394). +// TODO(nona): Current printable detection is weak. To enhance accuracy, use xkb +// key map +bool KeyTranslator::IsPrintable(KeySym keyval, uint32 keycode, + KeyStates modifiers) { + if ((modifiers & KeyState::Ctrl) || (modifiers & KeyState::Alt)) { + return false; + } + return IsAscii(keyval, keycode, modifiers); +} + +bool KeyTranslator::IsAscii(KeySym keyval, uint32 keycode, + KeyStates modifiers) { + return (keyval > FcitxKey_space && + // Note: Space key (0x20) is a special key in Mozc. + keyval <= FcitxKey_asciitilde); // 0x7e. +} + +} // namespace fcitx diff -ruN google-mozc-git/src/unix/fcitx5/fcitx_key_translator.h fcitx-mozc-git/src/unix/fcitx5/fcitx_key_translator.h --- google-mozc-git/src/unix/fcitx5/fcitx_key_translator.h 1970-01-01 02:00:00.000000000 +0200 +++ fcitx-mozc-git/src/unix/fcitx5/fcitx_key_translator.h 2022-01-31 13:12:52.982202692 +0200 @@ -0,0 +1,103 @@ +// Copyright 2010-2012, Google Inc. +// Copyright 2012-2017, Weng Xuetian +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef UNIX_FCITX5_FCITX_KEY_TRANSLATOR_H_ +#define UNIX_FCITX5_FCITX_KEY_TRANSLATOR_H_ + +#include + +#include +#include +#include + +#include "base/port.h" +#include "protocol/commands.pb.h" + +namespace fcitx { + +// This class is responsible for converting fcitx's key to IPC input for +// mozc_server. +class KeyTranslator { + public: + KeyTranslator(); + virtual ~KeyTranslator(); + + // Converts fcitx key into Mozc key code and stores them on out_translated. + bool Translate(KeySym keyval, uint32 keycode, KeyStates modifiers, + mozc::config::Config::PreeditMethod method, bool layout_is_jp, + mozc::commands::KeyEvent *out_event) const; + + private: + typedef std::map SpecialKeyMap; + typedef std::map + ModifierKeyMap; + typedef std::map> KanaMap; + + // Returns true iff key is modifier key such as SHIFT, ALT, or CAPSLOCK. + bool IsModifierKey(KeySym keyval, uint32 keycode, KeyStates modifiers) const; + + // Returns true iff key is special key such as ENTER, ESC, or PAGE_UP. + bool IsSpecialKey(KeySym keyval, uint32 keycode, KeyStates modifiers) const; + + // Returns true iff |keyval| is a key with a kana assigned. + bool IsKanaAvailable(KeySym keyval, uint32 keycode, KeyStates modifiers, + bool layout_is_jp, std::string *out) const; + + // Returns true iff key is ASCII such as '0', 'A', or '!'. + static bool IsAscii(KeySym keyval, uint32 keycode, KeyStates modifiers); + + // Returns true iff key is printable. + static bool IsPrintable(KeySym keyval, uint32 keycode, KeyStates modifiers); + + // Returns true iff key is HiraganaKatakana with shift modifier. + static bool IsHiraganaKatakanaKeyWithShift(KeySym keyval, uint32 keycode, + KeyStates modifiers); + + // Initializes private fields. + void Init(); + + // Stores a mapping from ibus keys to Mozc's special keys. + SpecialKeyMap special_key_map_; + // Stores a mapping from ibus modifier keys to Mozc's modifier keys. + ModifierKeyMap modifier_key_map_; + // Stores a mapping from ibus modifier masks to Mozc's modifier keys. + ModifierKeyMap modifier_mask_map_; + // Stores a mapping from ASCII to Kana character. For example, ASCII character + // '4' is mapped to Japanese 'Hiragana Letter U' (without Shift modifier) and + // 'Hiragana Letter Small U' (with Shift modifier). + KanaMap kana_map_jp_; // mapping for JP keyboard. + KanaMap kana_map_us_; // mapping for US keyboard. + + DISALLOW_COPY_AND_ASSIGN(KeyTranslator); +}; + +} // namespace fcitx + +#endif // MOZC_UNIX_FCITX_FCITX_KEY_TRANSLATOR_H_ diff -ruN google-mozc-git/src/unix/fcitx5/Messages.sh fcitx-mozc-git/src/unix/fcitx5/Messages.sh --- google-mozc-git/src/unix/fcitx5/Messages.sh 1970-01-01 02:00:00.000000000 +0200 +++ fcitx-mozc-git/src/unix/fcitx5/Messages.sh 2022-01-31 13:12:52.978869317 +0200 @@ -0,0 +1,3 @@ +#!/bin/bash + +gen_pot cxx:desktop:appdata fcitx5-mozc po . diff -ruN google-mozc-git/src/unix/fcitx5/mozc-addon.conf fcitx-mozc-git/src/unix/fcitx5/mozc-addon.conf --- google-mozc-git/src/unix/fcitx5/mozc-addon.conf 1970-01-01 02:00:00.000000000 +0200 +++ fcitx-mozc-git/src/unix/fcitx5/mozc-addon.conf 2022-01-31 13:12:52.982202692 +0200 @@ -0,0 +1,10 @@ +[Addon] +Name=Mozc +Category=InputMethod +Library=fcitx5-mozc +Type=SharedLibrary +OnDemand=True +Configurable=True + +[Addon/OptionalDependencies] +0=clipboard diff -ruN google-mozc-git/src/unix/fcitx5/mozc.conf fcitx-mozc-git/src/unix/fcitx5/mozc.conf --- google-mozc-git/src/unix/fcitx5/mozc.conf 1970-01-01 02:00:00.000000000 +0200 +++ fcitx-mozc-git/src/unix/fcitx5/mozc.conf 2022-01-31 13:12:52.982202692 +0200 @@ -0,0 +1,7 @@ +[InputMethod] +Name=Mozc +Icon=fcitx-mozc +Label=あ +LangCode=ja +Addon=mozc +Configurable=True diff -ruN google-mozc-git/src/unix/fcitx5/mozc_connection.cc fcitx-mozc-git/src/unix/fcitx5/mozc_connection.cc --- google-mozc-git/src/unix/fcitx5/mozc_connection.cc 1970-01-01 02:00:00.000000000 +0200 +++ fcitx-mozc-git/src/unix/fcitx5/mozc_connection.cc 2022-01-31 13:12:52.982202692 +0200 @@ -0,0 +1,69 @@ +// Copyright 2010-2012, Google Inc. +// Copyright 2012~2013, Weng Xuetian +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "unix/fcitx5/mozc_connection.h" + +#include + +#include "base/logging.h" +#include "base/util.h" +#include "client/client.h" +#include "ipc/ipc.h" +#include "protocol/commands.pb.h" +#include "session/ime_switch_util.h" + +namespace fcitx { + +mozc::client::ClientInterface *CreateAndConfigureClient() { + mozc::client::ClientInterface *client = + mozc::client::ClientFactory::NewClient(); + // Currently client capability is fixed. + mozc::commands::Capability capability; + capability.set_text_deletion( + mozc::commands::Capability::DELETE_PRECEDING_TEXT); + client->set_client_capability(capability); + return client; +} + +MozcConnection::MozcConnection() + : client_factory_(mozc::IPCClientFactory::GetIPCClientFactory()) { + VLOG(1) << "MozcConnection is created"; +} + +MozcConnection::~MozcConnection() { VLOG(1) << "MozcConnection is destroyed"; } + +mozc::client::ClientInterface *MozcConnection::CreateClient() { + mozc::client::ClientInterface *client = CreateAndConfigureClient(); + client->SetServerLauncher(new mozc::client::ServerLauncher); + client->SetIPCClientFactory(client_factory_); + return client; +} + +} // namespace fcitx diff -ruN google-mozc-git/src/unix/fcitx5/mozc_connection.h fcitx-mozc-git/src/unix/fcitx5/mozc_connection.h --- google-mozc-git/src/unix/fcitx5/mozc_connection.h 1970-01-01 02:00:00.000000000 +0200 +++ fcitx-mozc-git/src/unix/fcitx5/mozc_connection.h 2022-01-31 13:12:52.982202692 +0200 @@ -0,0 +1,72 @@ +// Copyright 2010-2012, Google Inc. +// Copyright 2012~2013, Weng Xuetian +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef MOZC_UNIX_FCITX5_MOZC_CONNECTION_H_ +#define MOZC_UNIX_FCITX5_MOZC_CONNECTION_H_ + +#include +#include + +#include "base/port.h" +#include "protocol/commands.pb.h" +#include "unix/fcitx5/fcitx_key_event_handler.h" + +namespace mozc { + +class IPCClientInterface; +class IPCClientFactoryInterface; + +namespace client { +class ClientInterface; +class ServerLauncherInterface; +} // namespace client + +} // namespace mozc + +namespace fcitx { + +class MozcConnection { + public: + static const int kNoSession; + + MozcConnection(); + virtual ~MozcConnection(); + + mozc::client::ClientInterface *CreateClient(); + + private: + mozc::IPCClientFactoryInterface *client_factory_; + + DISALLOW_COPY_AND_ASSIGN(MozcConnection); +}; + +} // namespace fcitx + +#endif // MOZC_UNIX_FCITX5_MOZC_CONNECTION_H_ diff -ruN google-mozc-git/src/unix/fcitx5/mozc_engine.cc fcitx-mozc-git/src/unix/fcitx5/mozc_engine.cc --- google-mozc-git/src/unix/fcitx5/mozc_engine.cc 1970-01-01 02:00:00.000000000 +0200 +++ fcitx-mozc-git/src/unix/fcitx5/mozc_engine.cc 2022-01-31 13:12:52.982202692 +0200 @@ -0,0 +1,284 @@ +/* + * Copyright (C) 2017~2017 by CSSlayer + * wengxt@gmail.com + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, + * see . + */ + +#include "unix/fcitx5/mozc_engine.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "base/clock.h" +#include "base/init_mozc.h" +#include "base/process.h" +#include "unix/fcitx5/mozc_connection.h" +#include "unix/fcitx5/mozc_response_parser.h" + +namespace fcitx { + +const struct CompositionModeInfo { + const char *name; + const char *icon; + const char *label; + const char *description; + mozc::commands::CompositionMode mode; +} kPropCompositionModes[] = { + { + "mozc-mode-direct", + "fcitx-mozc-direct", + "A", + N_("Direct"), + mozc::commands::DIRECT, + }, + { + "mozc-mode-hiragana", + "fcitx-mozc-hiragana", + "\xe3\x81\x82", // Hiragana letter A in UTF-8. + N_("Hiragana"), + mozc::commands::HIRAGANA, + }, + { + "mozc-mode-katakana_full", + "fcitx-mozc-katakana-full", + "\xe3\x82\xa2", // Katakana letter A. + N_("Full Katakana"), + mozc::commands::FULL_KATAKANA, + }, + { + + "mozc-mode-alpha_half", + "fcitx-mozc-alpha-half", + "A", + N_("Half ASCII"), + mozc::commands::HALF_ASCII, + }, + { + + "mozc-mode-alpha_full", + "fcitx-mozc-alpha-full", + "\xef\xbc\xa1", // Full width ASCII letter A. + N_("Full ASCII"), + mozc::commands::FULL_ASCII, + }, + { + "mozc-mode-katakana_half", + "fcitx-mozc-katakana-half", + "\xef\xbd\xb1", // Half width Katakana letter A. + N_("Half Katakana"), + mozc::commands::HALF_KATAKANA, + }, +}; +const size_t kNumCompositionModes = arraysize(kPropCompositionModes); + +std::string MozcModeAction::shortText(InputContext *) const { + return _("Composition Mode"); +} + +std::string MozcModeAction::longText(InputContext *ic) const { + auto mozc_state = engine_->mozcState(ic); + return _(kPropCompositionModes[mozc_state->GetCompositionMode()].description); +} + +std::string MozcModeAction::icon(InputContext *ic) const { + auto mozc_state = engine_->mozcState(ic); + return kPropCompositionModes[mozc_state->GetCompositionMode()].icon; +} + +MozcModeSubAction::MozcModeSubAction(MozcEngine *engine, + mozc::commands::CompositionMode mode) + : engine_(engine), mode_(mode) { + setShortText(_(kPropCompositionModes[mode].description)); + setLongText(_(kPropCompositionModes[mode].description)); + setIcon(kPropCompositionModes[mode].icon); + setCheckable(true); +} + +bool MozcModeSubAction::isChecked(InputContext *ic) const { + auto mozc_state = engine_->mozcState(ic); + return mozc_state->GetCompositionMode() == mode_; +} + +void MozcModeSubAction::activate(InputContext *ic) { + auto mozc_state = engine_->mozcState(ic); + mozc_state->SendCompositionMode(mode_); +} + +// This array must correspond with the CompositionMode enum in the +// mozc/session/command.proto file. +static_assert(mozc::commands::NUM_OF_COMPOSITIONS == kNumCompositionModes, + "number of modes must match"); + +Instance *Init(Instance *instance) { + int argc = 1; + char argv0[] = "fcitx_mozc"; + char *_argv[] = {argv0}; + char **argv = _argv; + mozc::InitMozc(argv[0], &argc, &argv); + return instance; +} + +MozcEngine::MozcEngine(Instance *instance) + : instance_(Init(instance)), + connection_(std::make_unique()), + client_(connection_->CreateClient()), + factory_([this](InputContext &ic) { + return new MozcState(&ic, connection_->CreateClient(), this); + }), + modeAction_(this) { + for (auto command : + {mozc::commands::DIRECT, mozc::commands::HIRAGANA, + mozc::commands::FULL_KATAKANA, mozc::commands::FULL_ASCII, + mozc::commands::HALF_ASCII, mozc::commands::HALF_KATAKANA}) { + modeActions_.push_back(std::make_unique(this, command)); + } + instance_->inputContextManager().registerProperty("mozcState", &factory_); + instance_->userInterfaceManager().registerAction("mozc-mode", &modeAction_); + instance_->userInterfaceManager().registerAction("mozc-tool", &toolAction_); + toolAction_.setShortText(_("Tool")); + toolAction_.setLongText(_("Tool")); + toolAction_.setIcon("fcitx-mozc-tool"); + + int i = 0; + for (auto &modeAction : modeActions_) { + instance_->userInterfaceManager().registerAction( + kPropCompositionModes[i].name, modeAction.get()); + modeMenu_.addAction(modeAction.get()); + i++; + } + + instance_->userInterfaceManager().registerAction("mozc-tool-config", + &configToolAction_); + configToolAction_.setShortText(_("Configuration Tool")); + configToolAction_.setIcon("fcitx-mozc-tool"); + configToolAction_.connect([](InputContext *) { + mozc::Process::SpawnMozcProcess("mozc_tool", "--mode=config_dialog"); + }); + + instance_->userInterfaceManager().registerAction("mozc-tool-dict", + &dictionaryToolAction_); + dictionaryToolAction_.setShortText(_("Dictionary Tool")); + dictionaryToolAction_.setIcon("fcitx-mozc-dictionary"); + dictionaryToolAction_.connect([](InputContext *) { + mozc::Process::SpawnMozcProcess("mozc_tool", "--mode=dictionary_tool"); + }); + + instance_->userInterfaceManager().registerAction("mozc-tool-add", + &addWordAction_); + addWordAction_.setShortText(_("Add Word")); + addWordAction_.connect([](InputContext *) { + mozc::Process::SpawnMozcProcess("mozc_tool", "--mode=word_register_dialog"); + }); + + instance_->userInterfaceManager().registerAction("mozc-tool-about", + &aboutAction_); + aboutAction_.setShortText(_("About Mozc")); + aboutAction_.connect([](InputContext *) { + mozc::Process::SpawnMozcProcess("mozc_tool", "--mode=about_dialog"); + }); + + toolMenu_.addAction(&configToolAction_); + toolMenu_.addAction(&dictionaryToolAction_); + toolMenu_.addAction(&addWordAction_); + toolMenu_.addAction(&aboutAction_); + + modeAction_.setMenu(&modeMenu_); + toolAction_.setMenu(&toolMenu_); + + reloadConfig(); +} + +MozcEngine::~MozcEngine() {} + +void MozcEngine::setConfig(const RawConfig &config) { + config_.load(config, true); + safeSaveAsIni(config_, "conf/mozc.conf"); +} + +void MozcEngine::reloadConfig() { readAsIni(config_, "conf/mozc.conf"); } +void MozcEngine::activate(const fcitx::InputMethodEntry &, + fcitx::InputContextEvent &event) { + if (client_) { + client_->EnsureConnection(); + } + auto ic = event.inputContext(); + auto mozc_state = mozcState(ic); + mozc_state->FocusIn(); + ic->statusArea().addAction(StatusGroup::InputMethod, &modeAction_); + ic->statusArea().addAction(StatusGroup::InputMethod, &toolAction_); +} +void MozcEngine::deactivate(const fcitx::InputMethodEntry &, + fcitx::InputContextEvent &event) { + auto ic = event.inputContext(); + auto mozc_state = mozcState(ic); + mozc_state->FocusOut(); +} +void MozcEngine::keyEvent(const InputMethodEntry &entry, KeyEvent &event) { + auto mozc_state = mozcState(event.inputContext()); + + auto &group = instance_->inputMethodManager().currentGroup(); + std::string layout = group.layoutFor(entry.uniqueName()); + if (layout.empty()) { + layout = group.defaultLayout(); + } + + const bool isJP = (layout == "jp" || stringutils::startsWith(layout, "jp-")); + + if (mozc_state->ProcessKeyEvent(event.rawKey().sym(), event.rawKey().code(), + event.rawKey().states(), isJP, + event.isRelease())) { + event.filterAndAccept(); + } +} + +void MozcEngine::reset(const InputMethodEntry &, InputContextEvent &event) { + auto mozc_state = mozcState(event.inputContext()); + mozc_state->Reset(); +} + +void MozcEngine::save() { + if (client_ == nullptr) { + return; + } + client_->SyncData(); +} + +std::string MozcEngine::subMode(const fcitx::InputMethodEntry &, + fcitx::InputContext &ic) { + return modeAction_.longText(&ic); +} + +MozcState *MozcEngine::mozcState(InputContext *ic) { + return ic->propertyFor(&factory_); +} + +void MozcEngine::compositionModeUpdated(InputContext *ic) { + modeAction_.update(ic); + for (const auto &modeAction : modeActions_) { + modeAction->update(ic); + } +} + +AddonInstance *MozcEngine::clipboardAddon() { return clipboard(); } +} // namespace fcitx diff -ruN google-mozc-git/src/unix/fcitx5/mozc_engine_factory.cc fcitx-mozc-git/src/unix/fcitx5/mozc_engine_factory.cc --- google-mozc-git/src/unix/fcitx5/mozc_engine_factory.cc 1970-01-01 02:00:00.000000000 +0200 +++ fcitx-mozc-git/src/unix/fcitx5/mozc_engine_factory.cc 2022-01-31 13:12:52.982202692 +0200 @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2020~2020 by CSSlayer + * wengxt@gmail.com + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, + * see . + */ +#include +#include +#include +#include +#include + +#include + +#include "base/system_util.h" +#include "mozc_engine.h" + +namespace fcitx { +class MozcEngineFactory : public AddonFactory { + public: + AddonInstance *create(AddonManager *manager) override { + // We don't have a direct way to detect, so we simply try. + auto baseDirectory = makeUniqueCPtr( + realpath(mozc::SystemUtil::GetServerDirectory().data(), nullptr)); + int numberOfSlash = 0; + if (baseDirectory) { + std::string_view view(baseDirectory.get()); + for (auto c : view) { + if (c == '/') { + numberOfSlash += 1; + } + } + if (view.empty()) { + baseDirectory.reset(); + } + } + + // Make sure we don't deadloop. + while (baseDirectory && numberOfSlash >= 0) { + auto path = stringutils::joinPath(baseDirectory.get(), "share/locale"); + if (fs::isdir(path)) { + registerDomain("fcitx5-mozc", path.data()); + } + baseDirectory = cdUp(baseDirectory.get()); + if (baseDirectory && std::string_view(baseDirectory.get()).empty()) { + baseDirectory.reset(); + } + numberOfSlash -= 1; + } + return new MozcEngine(manager->instance()); + } + + private: + UniqueCPtr cdUp(const char *path) { + return makeUniqueCPtr( + realpath(stringutils::joinPath(path, "..").data(), nullptr)); + } +}; +} // namespace fcitx + +FCITX_ADDON_FACTORY(fcitx::MozcEngineFactory) diff -ruN google-mozc-git/src/unix/fcitx5/mozc_engine.h fcitx-mozc-git/src/unix/fcitx5/mozc_engine.h --- google-mozc-git/src/unix/fcitx5/mozc_engine.h 1970-01-01 02:00:00.000000000 +0200 +++ fcitx-mozc-git/src/unix/fcitx5/mozc_engine.h 2022-01-31 13:12:52.982202692 +0200 @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2017~2017 by CSSlayer + * wengxt@gmail.com + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; see the file COPYING. If not, + * see . + */ +#ifndef _FCITX_UNIX_FCITX5_MOZC_ENGINE_H_ +#define _FCITX_UNIX_FCITX5_MOZC_ENGINE_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "base/file_util.h" +#include "base/system_util.h" +#include "unix/fcitx5/mozc_state.h" + +namespace fcitx { + +class MozcConnection; +class MozcResponseParser; +class MozcEngine; + +enum class ExpandMode { Always, OnFocus, Hotkey }; + +using CompositionMode = mozc::commands::CompositionMode; + +FCITX_CONFIG_ENUM_NAME_WITH_I18N(ExpandMode, N_("Always"), N_("On Focus"), + N_("Hotkey")); + +FCITX_CONFIG_ENUM_NAME_WITH_I18N(CompositionMode, N_("Direct"), N_("Hiragana"), + N_("Full Katakana"), N_("Half ASCII"), + N_("Full ASCII"), N_("Half Katakana")); + +FCITX_CONFIGURATION( + MozcEngineConfig, const std::string toolPath_ = mozc::FileUtil::JoinPath( + mozc::SystemUtil::GetServerDirectory(), "mozc_tool"); + std::string toolCommand(const char *arg) { + return stringutils::concat(toolPath_, " ", arg); + } + + OptionWithAnnotation + initialMode{this, "InitialMode", _("Initial Mode"), + mozc::commands::HIRAGANA}; + Option verticalList{this, "Vertical", _("Vertical candidate list"), + true}; + OptionWithAnnotation expandMode{ + this, "ExpandMode", + _("Expand Usage (Requires vertical candidate list)"), + ExpandMode::OnFocus}; + Option preeditCursorPositionAtBeginning{ + this, "PreeditCursorPositionAtBeginning", + _("Fix embedded preedit cursor at the beginning of the preedit"), + false}; + Option expand{this, "ExpandKey", _("Hotkey to expand usage"), + Key("Control+Alt+H")}; + + ExternalOption configTool{this, "ConfigTool", _("Configuration Tool"), + toolCommand("--mode=config_dialog")}; + ExternalOption dictTool{this, "Dictionary Tool", _("Dictionary Tool"), + toolCommand("--mode=dictionary_tool")}; + ExternalOption addTool{this, "Add Word", _("Add Word"), + toolCommand("--mode=word_register_dialog")}; + ExternalOption aboutTool{this, "About Mozc", _("About Mozc"), + toolCommand("--mode=about_dialog")};); + +class MozcModeAction : public Action { + public: + MozcModeAction(MozcEngine *engine) : engine_(engine) {} + + std::string shortText(fcitx::InputContext *) const override; + std::string longText(fcitx::InputContext *) const override; + std::string icon(fcitx::InputContext *) const override; + + private: + MozcEngine *engine_; +}; + +class MozcModeSubAction : public SimpleAction { + public: + MozcModeSubAction(MozcEngine *engine, mozc::commands::CompositionMode mode); + bool isChecked(fcitx::InputContext *) const override; + void activate(fcitx::InputContext *) override; + + private: + MozcEngine *engine_; + mozc::commands::CompositionMode mode_; +}; + +class MozcEngine final : public InputMethodEngine { + public: + MozcEngine(Instance *instance); + ~MozcEngine(); + Instance *instance() { return instance_; } + void activate(const InputMethodEntry &entry, + InputContextEvent &event) override; + void deactivate(const fcitx::InputMethodEntry &entry, + fcitx::InputContextEvent &event) override; + void keyEvent(const InputMethodEntry &entry, KeyEvent &keyEvent) override; + void reloadConfig() override; + void reset(const InputMethodEntry &entry, InputContextEvent &event) override; + void save() override; + std::string subMode(const fcitx::InputMethodEntry &, + fcitx::InputContext &) override; + const Configuration *getConfig() const override { return &config_; } + void setConfig(const RawConfig &config) override; + + auto &config() const { return config_; } + auto factory() const { return &factory_; } + + MozcState *mozcState(InputContext *ic); + AddonInstance *clipboardAddon(); + + void compositionModeUpdated(InputContext *ic); + + void SyncData(bool force); + + private: + Instance *instance_; + std::unique_ptr connection_; + std::unique_ptr client_; + FactoryFor factory_; + MozcModeAction modeAction_; + SimpleAction toolAction_; + std::vector> modeActions_; + + SimpleAction configToolAction_, dictionaryToolAction_, addWordAction_, + aboutAction_; + Menu toolMenu_; + Menu modeMenu_; + MozcEngineConfig config_; + uint64 lastSyncTime_; + + FCITX_ADDON_DEPENDENCY_LOADER(clipboard, instance_->addonManager()); +}; + +} // namespace fcitx + +#endif // _FCITX_UNIX_FCITX5_MOZC_ENGINE_H_ diff -ruN google-mozc-git/src/unix/fcitx5/mozc_response_parser.cc fcitx-mozc-git/src/unix/fcitx5/mozc_response_parser.cc --- google-mozc-git/src/unix/fcitx5/mozc_response_parser.cc 1970-01-01 02:00:00.000000000 +0200 +++ fcitx-mozc-git/src/unix/fcitx5/mozc_response_parser.cc 2022-01-31 13:12:52.982202692 +0200 @@ -0,0 +1,480 @@ +// Copyright 2010-2012, Google Inc. +// Copyright 2012~2013, Weng Xuetian +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "unix/fcitx5/mozc_response_parser.h" + +#include +#include +#include +#include +#include + +#include +#include + +#include "base/logging.h" +#include "base/process.h" +#include "base/util.h" +#include "protocol/commands.pb.h" +#include "unix/fcitx5/mozc_engine.h" +#include "unix/fcitx5/surrounding_text_util.h" + +namespace fcitx { + +namespace { + +// Returns a position that determines a preedit cursor position _AND_ top-left +// position of a candidate window. Note that we can't set these two positions +// independently. That's a SCIM's limitation. +uint32 GetCursorPosition(const mozc::commands::Output &response) { + if (!response.has_preedit()) { + return 0; + } + if (response.preedit().has_highlighted_position()) { + return response.preedit().highlighted_position(); + } + return response.preedit().cursor(); +} + +std::string CreateDescriptionString(const std::string &description) { + return " [" + description + "]"; +} + +class MozcCandidateWord final : public CandidateWord { + public: + MozcCandidateWord(int id, std::string text, MozcEngine *engine) + : CandidateWord(Text(text)), id_(id), engine_(engine) {} + + void select(InputContext *inputContext) const override { + auto mozc_state = engine_->mozcState(inputContext); + mozc_state->SelectCandidate(id_); + } + + private: + int id_; + MozcEngine *engine_; +}; + +class MozcCandidateList final : public CandidateList, + public PageableCandidateList { + public: + MozcCandidateList(const mozc::commands::Candidates &candidates, + InputContext *ic, MozcEngine *engine, bool use_annotation) + : ic_(ic), engine_(engine) { + auto state = engine_->mozcState(ic); + setPageable(this); + bool index_visible = false; + if (candidates.has_footer()) { + const auto &footer = candidates.footer(); + index_visible = footer.has_index_visible() && footer.index_visible(); + } + + if (candidates.candidate_size() > 0) { + if (candidates.candidate(0).index() > 0) { + hasPrev_ = true; + } + if (candidates.candidate(candidates.candidate_size() - 1).index() + 1 < + candidates.size()) { + hasNext_ = true; + } + } + const bool isVertical = *engine_->config().verticalList; + // candidates.direction is never used, we just override it with our + // configuration. + layout_ = isVertical ? CandidateLayoutHint::Vertical + : CandidateLayoutHint::Horizontal; + + int focused_index = -1; + cursor_ = -1; + if (candidates.has_focused_index()) { + focused_index = candidates.focused_index(); + } + + std::map> usage_map; + if (candidates.has_usages()) { + const mozc::commands::InformationList &usages = candidates.usages(); + for (size_t i = 0; i < usages.information().size(); ++i) { + const mozc::commands::Information &information = usages.information(i); + if (!information.has_id() || !information.has_description()) continue; + usage_map[information.id()].first = information.title(); + usage_map[information.id()].second = information.description(); + } + } + + labels_.reserve(candidates.candidate_size()); + + for (int i = 0; i < candidates.candidate_size(); ++i) { + const mozc::commands::Candidates::Candidate &candidate = + candidates.candidate(i); + const uint32 index = candidate.index(); + + std::string value; + if (use_annotation && candidate.has_annotation() && + candidate.annotation().has_prefix()) { + value = candidate.annotation().prefix(); + } + value += candidate.value(); + if (use_annotation && candidate.has_annotation() && + candidate.annotation().has_suffix()) { + value += candidate.annotation().suffix(); + } + if (use_annotation && candidate.has_annotation() && + candidate.annotation().has_description()) { + // Display descriptions ([HALF][KATAKANA], [GREEK], [Black square], + // etc). + value += CreateDescriptionString(candidate.annotation().description()); + } + + const bool is_current = + candidates.has_focused_index() && index == focused_index; + if (is_current) { + cursor_ = i; + } + if (use_annotation && candidate.has_information_id()) { + auto it = usage_map.find(candidate.information_id()); + if (it != usage_map.end()) { + if (*engine_->config().expandMode == ExpandMode::Always || + (*engine_->config().expandMode == ExpandMode::OnFocus && + is_current)) { + if (it->second.first != candidate.value()) { + value.append("\n").append(it->second.first); + } + value.append("\n").append(it->second.second); + } else if (*engine_->config().expandMode == ExpandMode::Hotkey && + is_current && engine_->config().expand->isValid()) { + state->SetUsage(it->second.first, it->second.second); + // We don't have a good library option for this, just do the simple + // replace. absl's runtime parsed format string is too copmlex. + std::string msg = _("Press %s to show usages."); + msg = stringutils::replaceAll(msg, "%s", + engine_->config().expand->toString()); + value += CreateDescriptionString(msg); + } + } + } + + if (candidate.has_annotation() && candidate.annotation().has_shortcut()) { + labels_.emplace_back(candidate.annotation().shortcut() + ". "); + } else if (index_visible) { + labels_.emplace_back(std::to_string(i + 1) + ". "); + } else { + labels_.emplace_back(); + } + + int32 id = kBadCandidateId; + if (candidate.has_id()) { + id = candidate.id(); + DCHECK_NE(kBadCandidateId, id) << "Unexpected id is passed."; + } + candidateWords_.emplace_back( + std::make_unique(id, value, engine)); + } + } + + const Text &label(int idx) const override { + checkIndex(idx); + return labels_[idx]; + } + + const CandidateWord &candidate(int idx) const override { + checkIndex(idx); + return *candidateWords_[idx]; + } + int size() const override { return candidateWords_.size(); } + + int cursorIndex() const override { return cursor_; } + + CandidateLayoutHint layoutHint() const override { return layout_; } + + bool hasPrev() const override { return hasPrev_; } + bool hasNext() const override { return hasNext_; } + void prev() override { + auto mozc_state = engine_->mozcState(ic_); + mozc_state->Paging(true); + } + void next() override { + auto mozc_state = engine_->mozcState(ic_); + mozc_state->Paging(false); + } + + bool usedNextBefore() const override { return true; } + + private: + void checkIndex(int idx) const { + if (idx < 0 && idx >= size()) { + throw std::invalid_argument("invalid index"); + } + } + + InputContext *ic_; + MozcEngine *engine_; + std::vector labels_; + bool hasPrev_ = false; + bool hasNext_ = false; + CandidateLayoutHint layout_ = CandidateLayoutHint::Vertical; + int cursor_ = -1; + std::vector> candidateWords_; +}; + +} // namespace + +MozcResponseParser::MozcResponseParser(MozcEngine *engine) : engine_(engine) {} + +MozcResponseParser::~MozcResponseParser() {} + +void MozcResponseParser::UpdateDeletionRange( + const mozc::commands::Output &response, InputContext *ic) const { + if (response.has_deletion_range() && + response.deletion_range().offset() <= 0 && + response.deletion_range().offset() + response.deletion_range().length() >= + 0) { + ic->deleteSurroundingText(response.deletion_range().offset(), + response.deletion_range().length()); + } +} + +void MozcResponseParser::LaunchTool(const mozc::commands::Output &response, + InputContext *ic) const { + if (response.has_launch_tool_mode()) { + auto mozc_state = engine_->mozcState(ic); + mozc_state->GetClient()->LaunchToolWithProtoBuf(response); + } +} + +void MozcResponseParser::ExecuteCallback(const mozc::commands::Output &response, + InputContext *ic) const { + if (!response.has_callback()) { + return; + } + + if (!response.callback().has_session_command()) { + LOG(ERROR) << "callback does not have session_command"; + return; + } + + const mozc::commands::SessionCommand &callback_command = + response.callback().session_command(); + + if (!callback_command.has_type()) { + LOG(ERROR) << "callback_command has no type"; + return; + } + + mozc::commands::SessionCommand session_command; + session_command.set_type(callback_command.type()); + + // TODO(nona): Make a function to handle CONVERT_REVERSE. + // Used by CONVERT_REVERSE and/or UNDO + // This value represents how many characters are selected as a relative + // distance of characters. Positive value represents forward text selection + // and negative value represents backword text selection. + // Note that you should not allow 0x80000000 for |relative_selected_length| + // because you cannot safely use |-relative_selected_length| nor + // |abs(relative_selected_length)| in this case due to integer overflow. + SurroundingTextInfo surrounding_text_info; + + switch (callback_command.type()) { + case mozc::commands::SessionCommand::UNDO: + break; + case mozc::commands::SessionCommand::CONVERT_REVERSE: { + if (!GetSurroundingText(ic, &surrounding_text_info, + engine_->clipboardAddon())) { + return; + } + + session_command.set_text(surrounding_text_info.selection_text); + break; + } + default: + return; + } + + auto mozc_state = engine_->mozcState(ic); + mozc::commands::Output new_output; + if (!mozc_state->SendCommand(session_command, &new_output)) { + LOG(ERROR) << "Callback Command Failed"; + return; + } + + if (callback_command.type() == + mozc::commands::SessionCommand::CONVERT_REVERSE) { + // We need to remove selected text as a first step of reconversion. + mozc::commands::DeletionRange *range = new_output.mutable_deletion_range(); + // Use DeletionRange field to remove the selected text. + // For forward selection (that is, |relative_selected_length > 0|), the + // offset should be a negative value to delete preceding text. + // For backward selection (that is, |relative_selected_length < 0|), + // IBus and/or some applications seem to expect |offset == 0| somehow. + const int32 offset = + surrounding_text_info.relative_selected_length > 0 + ? -surrounding_text_info + .relative_selected_length // forward selection + : 0; // backward selection + range->set_offset(offset); + range->set_length(abs(surrounding_text_info.relative_selected_length)); + } + + VLOG(1) << "New output" << new_output.DebugString(); + + ParseResponse(new_output, ic); +} + +bool MozcResponseParser::ParseResponse(const mozc::commands::Output &response, + InputContext *ic) const { + auto mozc_state = engine_->mozcState(ic); + mozc_state->SetUsage("", ""); + + UpdateDeletionRange(response, ic); + + // We should check the mode field first since the response for a + // SWITCH_INPUT_MODE request only contains mode and id fields. + if (response.has_mode()) { + mozc_state->SetCompositionMode(response.mode()); + } + + if (!response.consumed()) { + // The key was not consumed by Mozc. + return false; + } + + if (response.has_result()) { + const mozc::commands::Result &result = response.result(); + ParseResult(result, ic); + } + + // First, determine the cursor position. + if (response.has_preedit()) { + const mozc::commands::Preedit &preedit = response.preedit(); + ParsePreedit(preedit, GetCursorPosition(response), ic); + } + + // Then show the candidate window. + if (response.has_candidates()) { + const mozc::commands::Candidates &candidates = response.candidates(); + ParseCandidates(candidates, ic); + } + + if (response.has_url()) { + const std::string &url = response.url(); + mozc_state->SetUrl(url); + } + LaunchTool(response, ic); + ExecuteCallback(response, ic); + + return true; // mozc consumed the key. +} + +void MozcResponseParser::ParseResult(const mozc::commands::Result &result, + InputContext *ic) const { + auto mozc_state = engine_->mozcState(ic); + switch (result.type()) { + case mozc::commands::Result::NONE: { + mozc_state->SetAuxString("No result"); // not a fatal error. + break; + } + case mozc::commands::Result::STRING: { + mozc_state->SetResultString(result.value()); + break; + } + } +} + +void MozcResponseParser::ParseCandidates( + const mozc::commands::Candidates &candidates, InputContext *ic) const { + auto mozc_state = engine_->mozcState(ic); + const mozc::commands::Footer &footer = candidates.footer(); + if (candidates.has_footer()) { + std::string auxString; + if (footer.has_label()) { + // TODO(yusukes,mozc-team): label() is not localized. Currently, it's + // always + // written in Japanese (in UTF-8). + auxString += footer.label(); + } else if (footer.has_sub_label()) { + // Windows client shows sub_label() only when label() is not specified. We + // follow the policy. + auxString += footer.sub_label(); + } + + if (footer.has_index_visible() && footer.index_visible()) { + if (!auxString.empty()) { + auxString += " "; + } + auxString += std::to_string(candidates.focused_index() + 1); + auxString += "/"; + auxString += std::to_string(candidates.size()); + } + mozc_state->SetAuxString(auxString); + } + + ic->inputPanel().setCandidateList(std::make_unique( + candidates, ic, engine_, *engine_->config().verticalList)); +} + +void MozcResponseParser::ParsePreedit(const mozc::commands::Preedit &preedit, + uint32 position, InputContext *ic) const { + auto mozc_state = engine_->mozcState(ic); + Text preedit_text; + std::string s; + + for (int i = 0; i < preedit.segment_size(); ++i) { + const mozc::commands::Preedit_Segment &segment = preedit.segment(i); + const std::string &str = segment.value(); + if (!utf8::validate(str)) { + continue; + } + TextFormatFlags format_flag; + + switch (segment.annotation()) { + case mozc::commands::Preedit_Segment::NONE: + break; + case mozc::commands::Preedit_Segment::UNDERLINE: + format_flag = TextFormatFlag::Underline; + break; + case mozc::commands::Preedit_Segment::HIGHLIGHT: + format_flag = TextFormatFlag::HighLight; + break; + } + s += str; + + preedit_text.append(str, format_flag); + } + + int cursor = -1; + auto charLength = utf8::length(s); + if (charLength >= position) { + cursor = utf8::ncharByteLength(s.begin(), position); + } + preedit_text.setCursor(cursor); + + mozc_state->SetPreeditInfo(std::move(preedit_text)); +} + +} // namespace fcitx diff -ruN google-mozc-git/src/unix/fcitx5/mozc_response_parser.h fcitx-mozc-git/src/unix/fcitx5/mozc_response_parser.h --- google-mozc-git/src/unix/fcitx5/mozc_response_parser.h 1970-01-01 02:00:00.000000000 +0200 +++ fcitx-mozc-git/src/unix/fcitx5/mozc_response_parser.h 2022-01-31 13:12:52.982202692 +0200 @@ -0,0 +1,88 @@ +// Copyright 2010-2012, Google Inc. +// Copyright 2012~2013, Weng Xuetian +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef MOZC_UNIX_FCITX_MOZC_RESPONSE_PARSER_H_ +#define MOZC_UNIX_FCITX_MOZC_RESPONSE_PARSER_H_ + +#include "base/port.h" + +namespace mozc { +namespace commands { + +class Candidates; +class Input; +class Output; +class Preedit; +class Result; + +} // namespace commands +} // namespace mozc + +namespace fcitx { + +class InputContext; +class MozcEngine; + +// This class parses IPC response from mozc_server (mozc::commands::Output) and +// updates the FCITX UI. +class MozcResponseParser { + public: + MozcResponseParser(MozcEngine *engine); + ~MozcResponseParser(); + + // Parses a response from Mozc server and sets persed information on + // fcitx_mozc + // object. Returns true if response.consumed() is true. fcitx_mozc must be non + // NULL. This function does not take ownership of fcitx_mozc. + bool ParseResponse(const mozc::commands::Output &response, + InputContext *ic) const; + + private: + void UpdateDeletionRange(const mozc::commands::Output &response, + InputContext *ic) const; + void LaunchTool(const mozc::commands::Output &response, + InputContext *ic) const; + void ExecuteCallback(const mozc::commands::Output &response, + InputContext *ic) const; + void ParseResult(const mozc::commands::Result &result, + InputContext *ic) const; + void ParseCandidates(const mozc::commands::Candidates &candidates, + InputContext *ic) const; + void ParsePreedit(const mozc::commands::Preedit &preedit, uint32 position, + InputContext *ic) const; + + MozcEngine *engine_; + + DISALLOW_COPY_AND_ASSIGN(MozcResponseParser); +}; + +} // namespace fcitx + +#endif // MOZC_UNIX_FCITX_MOZC_RESPONSE_PARSER_H_ diff -ruN google-mozc-git/src/unix/fcitx5/mozc_state.cc fcitx-mozc-git/src/unix/fcitx5/mozc_state.cc --- google-mozc-git/src/unix/fcitx5/mozc_state.cc 1970-01-01 02:00:00.000000000 +0200 +++ fcitx-mozc-git/src/unix/fcitx5/mozc_state.cc 2022-01-31 13:12:52.982202692 +0200 @@ -0,0 +1,411 @@ +// Copyright 2012~2013, Weng Xuetian +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "unix/fcitx5/mozc_state.h" + +#include +#include +#include +#include +#include + +#include + +#include "base/const.h" +#include "base/file_util.h" +#include "base/logging.h" +#include "base/process.h" +#include "base/system_util.h" +#include "base/util.h" +#include "session/ime_switch_util.h" +#include "unix/fcitx5/fcitx_key_event_handler.h" +#include "unix/fcitx5/mozc_connection.h" +#include "unix/fcitx5/mozc_engine.h" +#include "unix/fcitx5/mozc_response_parser.h" +#include "unix/fcitx5/surrounding_text_util.h" + +namespace fcitx { + +MozcState::MozcState(InputContext* ic, mozc::client::ClientInterface* client, + MozcEngine* engine) + : ic_(ic), + client_(client), + engine_(engine), + handler_(std::make_unique()), + parser_(std::make_unique(engine_)) { + // mozc::Logging::SetVerboseLevel(1); + VLOG(1) << "MozcState created."; + + if (client_->EnsureConnection()) { + UpdatePreeditMethod(); + } + + std::string error; + mozc::commands::Output raw_response; + if (TrySendCompositionMode(*engine_->config().initialMode, &raw_response, + &error)) { + if (raw_response.has_mode()) { + SetCompositionMode(raw_response.mode()); + } + } +} + +MozcState::~MozcState() { + client_->SyncData(); + VLOG(1) << "MozcState destroyed."; +} + +void MozcState::UpdatePreeditMethod() { + mozc::config::Config config; + if (!client_->GetConfig(&config)) { + LOG(ERROR) << "GetConfig failed"; + return; + } + preedit_method_ = config.has_preedit_method() ? config.preedit_method() + : mozc::config::Config::ROMAN; +} + +bool MozcState::TrySendKeyEvent( + InputContext* ic, KeySym sym, uint32 keycode, KeyStates state, + mozc::commands::CompositionMode composition_mode, bool layout_is_jp, + bool is_key_up, mozc::commands::Output* out, std::string* out_error) const { + DCHECK(out); + DCHECK(out_error); + + // Call EnsureConnection just in case MozcState::MozcConnection() fails + // to establish the server connection. + if (!client_->EnsureConnection()) { + *out_error = "EnsureConnection failed"; + VLOG(1) << "EnsureConnection failed"; + return false; + } + + mozc::commands::KeyEvent event; + if (!handler_->GetKeyEvent(sym, keycode, state, preedit_method_, layout_is_jp, + is_key_up, &event)) + return false; + + if ((composition_mode == mozc::commands::DIRECT) && + !mozc::config::ImeSwitchUtil::IsDirectModeCommand(event)) { + VLOG(1) << "In DIRECT mode. Not consumed."; + return false; // not consumed. + } + + mozc::commands::Context context; + SurroundingTextInfo surrounding_text_info; + if (GetSurroundingText(ic, &surrounding_text_info, + engine_->clipboardAddon())) { + context.set_preceding_text(surrounding_text_info.preceding_text); + context.set_following_text(surrounding_text_info.following_text); + } + + VLOG(1) << "TrySendKeyEvent: " << std::endl << event.DebugString(); + if (!client_->SendKeyWithContext(event, context, out)) { + *out_error = "SendKey failed"; + VLOG(1) << "ERROR"; + return false; + } + VLOG(1) << "OK: " << std::endl << out->DebugString(); + return true; +} + +bool MozcState::TrySendClick(int32 unique_id, mozc::commands::Output* out, + std::string* out_error) const { + DCHECK(out); + DCHECK(out_error); + + mozc::commands::SessionCommand command; + command.set_type(mozc::commands::SessionCommand::SELECT_CANDIDATE); + command.set_id(unique_id); + return TrySendRawCommand(command, out, out_error); +} + +bool MozcState::TrySendCompositionMode(mozc::commands::CompositionMode mode, + mozc::commands::Output* out, + std::string* out_error) const { + DCHECK(out); + DCHECK(out_error); + + mozc::commands::SessionCommand command; + if (mode == mozc::commands::DIRECT) { + command.set_type(mozc::commands::SessionCommand::TURN_OFF_IME); + command.set_composition_mode(composition_mode_); + } else { + command.set_type(mozc::commands::SessionCommand::SWITCH_INPUT_MODE); + command.set_composition_mode(mode); + } + return TrySendRawCommand(command, out, out_error); +} + +bool MozcState::TrySendCommand(mozc::commands::SessionCommand::CommandType type, + mozc::commands::Output* out, + std::string* out_error) const { + DCHECK(out); + DCHECK(out_error); + + mozc::commands::SessionCommand command; + command.set_type(type); + return TrySendRawCommand(command, out, out_error); +} + +bool MozcState::TrySendRawCommand(const mozc::commands::SessionCommand& command, + mozc::commands::Output* out, + std::string* out_error) const { + VLOG(1) << "TrySendRawCommand: " << std::endl << command.DebugString(); + if (!client_->SendCommand(command, out)) { + *out_error = "SendCommand failed"; + VLOG(1) << "ERROR"; + return false; + } + VLOG(1) << "OK: " << std::endl << out->DebugString(); + return true; +} + +// This function is called when users press or release a key. +bool MozcState::ProcessKeyEvent(KeySym sym, uint32 keycode, KeyStates state, + bool layout_is_jp, bool is_key_up) { + auto normalized_key = Key(sym, state).normalize(); + if (displayUsage_) { + if (is_key_up) { + return true; + } + + if (normalized_key.check(Key(FcitxKey_Escape))) { + displayUsage_ = false; + ProcessKeyEvent(FcitxKey_VoidSymbol, 0, KeyState::NoState, layout_is_jp, + false); + } + return true; + } + + if (*engine_->config().expandMode == ExpandMode::Hotkey && + normalized_key.check(*engine_->config().expand)) { + if (!title_.empty() || !description_.empty()) { + DisplayUsage(); + return true; + } + } + + std::string error; + mozc::commands::Output raw_response; + if (!TrySendKeyEvent(ic_, sym, keycode, state, composition_mode_, + layout_is_jp, is_key_up, &raw_response, &error)) { + // TODO(yusukes): Show |error|. + return false; // not consumed. + } + + return ParseResponse(raw_response); +} + +// This function is called from SCIM framework when users click the candidate +// window. +void MozcState::SelectCandidate(int32 id) { + if (id == kBadCandidateId) { + LOG(ERROR) << "The clicked candidate doesn't have unique ID."; + return; + } + VLOG(1) << "select_candidate, id=" << id; + + std::string error; + mozc::commands::Output raw_response; + if (!TrySendClick(id, &raw_response, &error)) { + LOG(ERROR) << "IPC failed. error=" << error; + SetAuxString(error); + DrawAll(); + } else { + ParseResponse(raw_response); + } +} + +// This function is called from SCIM framework. +void MozcState::Reset() { + VLOG(1) << "resetim"; + std::string error; + mozc::commands::Output raw_response; + if (TrySendCommand(mozc::commands::SessionCommand::REVERT, &raw_response, + &error)) { + parser_->ParseResponse(raw_response, ic_); + } + ClearAll(); // just in case. + DrawAll(); +} + +bool MozcState::Paging(bool prev) { + VLOG(1) << "paging"; + std::string error; + mozc::commands::SessionCommand::CommandType command = + prev ? mozc::commands::SessionCommand::CONVERT_PREV_PAGE + : mozc::commands::SessionCommand::CONVERT_NEXT_PAGE; + mozc::commands::Output raw_response; + if (TrySendCommand(command, &raw_response, &error)) { + parser_->ParseResponse(raw_response, ic_); + return true; + } + return false; +} + +// This function is called when the ic gets focus. +void MozcState::FocusIn() { + VLOG(1) << "MozcState::FocusIn()"; + + UpdatePreeditMethod(); + DrawAll(); +} + +// This function is called when the ic loses focus. +void MozcState::FocusOut() { + VLOG(1) << "MozcState::FocusOut()"; + std::string error; + mozc::commands::Output raw_response; + if (TrySendCommand(mozc::commands::SessionCommand::REVERT, &raw_response, + &error)) { + parser_->ParseResponse(raw_response, ic_); + } + ClearAll(); // just in case. + DrawAll(); +} + +bool MozcState::ParseResponse(const mozc::commands::Output& raw_response) { + auto oldMode = composition_mode_; + ClearAll(); + const bool consumed = parser_->ParseResponse(raw_response, ic_); + if (!consumed) { + VLOG(1) << "The input was not consumed by Mozc."; + } + OpenUrl(); + DrawAll(); + if (oldMode != composition_mode_ && aux_.empty() && preedit_.empty() && + !ic_->inputPanel().candidateList()) { + engine_->instance()->showInputMethodInformation(ic_); + } + return consumed; +} + +void MozcState::SetResultString(const std::string& result_string) { + ic_->commitString(result_string); +} + +void MozcState::SetPreeditInfo(Text preedit_info) { + preedit_ = std::move(preedit_info); +} + +void MozcState::SetAuxString(const std::string& str) { aux_ = str; } + +void MozcState::SetCompositionMode(mozc::commands::CompositionMode mode) { + composition_mode_ = mode; + DCHECK(composition_mode_ < mozc::commands::NUM_OF_COMPOSITIONS); + engine_->compositionModeUpdated(ic_); +} + +void MozcState::SendCompositionMode(mozc::commands::CompositionMode mode) { + // Send the SWITCH_INPUT_MODE command. + std::string error; + mozc::commands::Output raw_response; + if (TrySendCompositionMode(mode, &raw_response, &error)) { + parser_->ParseResponse(raw_response, ic_); + } +} + +void MozcState::SetUrl(const std::string& url) { url_ = url; } + +void MozcState::ClearAll() { + SetPreeditInfo(Text()); + SetAuxString(""); + ic_->inputPanel().reset(); + url_.clear(); +} + +void MozcState::DrawAll() { + std::string aux; + if (!aux_.empty()) { + aux += "["; + aux += aux_; + aux += "]"; + } + if (ic_->capabilityFlags().test(CapabilityFlag::Preedit)) { + Text preedit = preedit_; + if (*engine_->config().preeditCursorPositionAtBeginning) { + preedit.setCursor(0); + } + ic_->inputPanel().setClientPreedit(preedit); + if (!aux_.empty()) { + ic_->inputPanel().setAuxUp(Text(aux)); + } + } else { + Text preedit = preedit_; + if (preedit.size()) { + preedit.append(" "); + preedit.append(aux); + ic_->inputPanel().setPreedit(std::move(preedit)); + } else if (!aux_.empty()) { + ic_->inputPanel().setAuxUp(Text(aux)); + } + } + ic_->updatePreedit(); + ic_->updateUserInterface(UserInterfaceComponent::InputPanel); +} + +void MozcState::OpenUrl() { + if (url_.empty()) { + return; + } + mozc::Process::OpenBrowser(url_); + url_.clear(); +} + +bool MozcState::SendCommand( + const mozc::commands::SessionCommand& session_command, + mozc::commands::Output* new_output) { + std::string error; + return TrySendRawCommand(session_command, new_output, &error); +} + +void MozcState::SetUsage(const std::string& title, + const std::string& description) { + title_ = title; + description_ = description; +} + +void MozcState::DisplayUsage() { + displayUsage_ = true; + + ic_->inputPanel().reset(); + auto candidateList = std::make_unique(); + + auto lines = stringutils::split(description_, "\n"); + candidateList->setLayoutHint(CandidateLayoutHint::Vertical); + candidateList->setContent(lines); + ic_->inputPanel().setCandidateList(std::move(candidateList)); + auto str = title_ + " [" + _("Press Escape to go back") + "]"; + ic_->inputPanel().setAuxUp(Text(str)); + ic_->updatePreedit(); + ic_->updateUserInterface(UserInterfaceComponent::InputPanel); +} + +} // namespace fcitx diff -ruN google-mozc-git/src/unix/fcitx5/mozc_state.h fcitx-mozc-git/src/unix/fcitx5/mozc_state.h --- google-mozc-git/src/unix/fcitx5/mozc_state.h 1970-01-01 02:00:00.000000000 +0200 +++ fcitx-mozc-git/src/unix/fcitx5/mozc_state.h 2022-01-31 13:12:52.982202692 +0200 @@ -0,0 +1,168 @@ +// Copyright 2012~2013, Weng Xuetian +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef MOZC_UNIX_FCITX_FCITX_MOZC_H_ +#define MOZC_UNIX_FCITX_FCITX_MOZC_H_ + +#include +#include +#include + +#include + +#include "base/port.h" +#include "base/run_level.h" +#include "client/client_interface.h" +#include "protocol/commands.pb.h" + +namespace fcitx { +const int32 kBadCandidateId = -12345; +class MozcConnectionInterface; +class MozcResponseParser; +class KeyTranslator; +class KeyEventHandler; +class MozcEngine; + +class MozcState : public InputContextProperty { + public: + // This constructor is used by unittests. + MozcState(InputContext *ic, mozc::client::ClientInterface *client, + MozcEngine *engine); + virtual ~MozcState(); + + void UpdatePreeditMethod(); + + bool ProcessKeyEvent(KeySym sym, uint32 keycode, KeyStates state, + bool layout_is_jp, bool is_key_up); + void SelectCandidate(int idx); + void Reset(); + void FocusIn(); + void FocusOut(); + bool Paging(bool prev); + + // Functions called by the MozcResponseParser class to update UI. + + // Displays a 'result' (aka 'commit string') on FCITX UI. + void SetResultString(const std::string &result_string); + // Displays a 'preedit' string on FCITX UI. This function takes ownership + // of preedit_info. If the parameter is NULL, hides the string currently + // displayed. + void SetPreeditInfo(Text preedit_info); + // Displays an auxiliary message (e.g., an error message, a title of + // candidate window). If the string is empty (""), hides the message + // currently being displayed. + void SetAuxString(const std::string &str); + // Sets a current composition mode (e.g., Hankaku Katakana). + void SetCompositionMode(mozc::commands::CompositionMode mode); + + void SendCompositionMode(mozc::commands::CompositionMode mode); + + // Sets the url to be opened by the default browser. + void SetUrl(const std::string &url); + + const std::string &GetIconFile(const std::string key); + + mozc::commands::CompositionMode GetCompositionMode() { + return composition_mode_; + } + + mozc::client::ClientInterface *GetClient() { return client_.get(); } + + bool SendCommand(const mozc::commands::SessionCommand &session_command, + mozc::commands::Output *new_output); + + void SetUsage(const std::string &title, const std::string &description); + + void DrawAll(); + + private: + void DisplayUsage(); + // Sends key event to the server. If the IPC succeeds, returns true and the + // response is stored on 'out' (and 'out_error' is not modified). If the IPC + // fails, returns false and the error message is stored on 'out_error'. In + // this case, 'out' is not modified. + bool TrySendKeyEvent(InputContext *ic, KeySym sym, uint32 keycode, + KeyStates state, + mozc::commands::CompositionMode composition_mode, + bool layout_is_jp, bool is_key_up, + mozc::commands::Output *out, + std::string *out_error) const; + + // Sends 'mouse click on the candidate window' event to the server. + bool TrySendClick(int32 unique_id, mozc::commands::Output *out, + std::string *out_error) const; + + // Sends composition mode to the server. + bool TrySendCompositionMode(mozc::commands::CompositionMode mode, + mozc::commands::Output *out, + std::string *out_error) const; + + // Sends a command to the server. + bool TrySendCommand(mozc::commands::SessionCommand::CommandType type, + mozc::commands::Output *out, + std::string *out_error) const; + + bool TrySendRawCommand(const mozc::commands::SessionCommand &command, + mozc::commands::Output *out, + std::string *out_error) const; + + // Parses the response from mozc_server. Returns whether the server consumes + // the input or not (true means 'consumed'). + bool ParseResponse(const mozc::commands::Output &request); + + void ClearAll(); + void DrawPreeditInfo(); + void DrawAux(); + + // Open url_ with a default browser. + void OpenUrl(); + + InputContext *ic_; + std::unique_ptr client_; + MozcEngine *engine_; + + mozc::commands::CompositionMode composition_mode_ = mozc::commands::HIRAGANA; + mozc::config::Config::PreeditMethod preedit_method_ = + mozc::config::Config::ROMAN; + const std::unique_ptr handler_; + const std::unique_ptr parser_; + + bool displayUsage_ = false; + Text preedit_; + std::string aux_; // error tooltip, or candidate window title. + std::string url_; // URL to be opened by a browser. + std::string description_; + std::string title_; + + DISALLOW_COPY_AND_ASSIGN(MozcState); +}; + +} // namespace fcitx + +#endif // MOZC_UNIX_FCITX_FCITX_MOZC_H_ diff -ruN google-mozc-git/src/unix/fcitx5/org.fcitx.Fcitx5.Addon.Mozc.metainfo.xml.in fcitx-mozc-git/src/unix/fcitx5/org.fcitx.Fcitx5.Addon.Mozc.metainfo.xml.in --- google-mozc-git/src/unix/fcitx5/org.fcitx.Fcitx5.Addon.Mozc.metainfo.xml.in 1970-01-01 02:00:00.000000000 +0200 +++ fcitx-mozc-git/src/unix/fcitx5/org.fcitx.Fcitx5.Addon.Mozc.metainfo.xml.in 2022-01-31 13:12:52.982202692 +0200 @@ -0,0 +1,16 @@ + + + org.fcitx.Fcitx5.Addon.Mozc + org.fcitx.Fcitx5 + CC0-1.0 + GPL-2.0+ + Mozc for Fcitx 5 + Japanese input method based on Mozc + https://fcitx-im.org + https://github.com/fcitx/mozc/issues + Fcitx + + + + + diff -ruN google-mozc-git/src/unix/fcitx5/po/ca.po fcitx-mozc-git/src/unix/fcitx5/po/ca.po --- google-mozc-git/src/unix/fcitx5/po/ca.po 1970-01-01 02:00:00.000000000 +0200 +++ fcitx-mozc-git/src/unix/fcitx5/po/ca.po 2022-01-31 13:12:52.982202692 +0200 @@ -0,0 +1,123 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the fcitx5-mozc package. +# +# Translators: +# csslayer , 2017 +# +msgid "" +msgstr "" +"Project-Id-Version: fcitx5-mozc\n" +"Report-Msgid-Bugs-To: fcitx-dev@googlegroups.com\n" +"POT-Creation-Date: 2021-12-30 02:39+0000\n" +"PO-Revision-Date: 2017-11-23 05:28+0000\n" +"Last-Translator: csslayer , 2017\n" +"Language-Team: Catalan (https://www.transifex.com/fcitx/teams/12005/ca/)\n" +"Language: ca\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: mozc_engine.h:84 mozc_engine.cc:196 +msgid "About Mozc" +msgstr "" + +#: mozc_engine.h:82 mozc_engine.cc:189 +msgid "Add Word" +msgstr "" + +#: mozc_engine.h:48 +msgid "Always" +msgstr "" + +#: mozc_engine.cc:96 +msgid "Composition Mode" +msgstr "" + +#: mozc_engine.h:78 mozc_engine.cc:173 +msgid "Configuration Tool" +msgstr "Eina de configuració" + +#: mozc_engine.h:80 mozc_engine.cc:181 +msgid "Dictionary Tool" +msgstr "Eina de diccionari" + +#: mozc_engine.h:51 mozc_engine.cc:52 +msgid "Direct" +msgstr "" + +#: mozc_engine.h:69 +msgid "Expand Usage (Requires vertical candidate list)" +msgstr "" + +#: mozc_engine.h:73 +msgid "Fix embedded preedit cursor at the beginning of the preedit" +msgstr "" + +#. Full width ASCII letter A. +#: mozc_engine.h:53 mozc_engine.cc:82 +msgid "Full ASCII" +msgstr "" + +#. Katakana letter A. +#: mozc_engine.h:52 mozc_engine.cc:66 +msgid "Full Katakana" +msgstr "" + +#: mozc_engine.h:52 mozc_engine.cc:74 +msgid "Half ASCII" +msgstr "" + +#. Half width Katakana letter A. +#: mozc_engine.h:53 mozc_engine.cc:89 +msgid "Half Katakana" +msgstr "" + +#. Hiragana letter A in UTF-8. +#: mozc_engine.h:51 mozc_engine.cc:59 +msgid "Hiragana" +msgstr "" + +#: mozc_engine.h:49 +msgid "Hotkey" +msgstr "" + +#: mozc_engine.h:75 +msgid "Hotkey to expand usage" +msgstr "" + +#: mozc_engine.h:63 +msgid "Initial Mode" +msgstr "" + +#: org.fcitx.Fcitx5.Addon.Mozc.metainfo.xml.in:8 +msgid "Japanese input method based on Mozc" +msgstr "" + +#: org.fcitx.Fcitx5.Addon.Mozc.metainfo.xml.in:7 +msgid "Mozc for Fcitx 5" +msgstr "" + +#: mozc_engine.h:48 +msgid "On Focus" +msgstr "" + +#. We don't have a good library option for this, just do the simple +#. replace. absl's runtime parsed format string is too copmlex. +#: mozc_response_parser.cc:175 +#, c-format +msgid "Press %s to show usages." +msgstr "" + +#: mozc_state.cc:405 +msgid "Press Escape to go back" +msgstr "" + +#: mozc_engine.cc:159 mozc_engine.cc:160 +msgid "Tool" +msgstr "" + +#: mozc_engine.h:65 +msgid "Vertical candidate list" +msgstr "" diff -ruN google-mozc-git/src/unix/fcitx5/po/da.po fcitx-mozc-git/src/unix/fcitx5/po/da.po --- google-mozc-git/src/unix/fcitx5/po/da.po 1970-01-01 02:00:00.000000000 +0200 +++ fcitx-mozc-git/src/unix/fcitx5/po/da.po 2022-01-31 13:12:52.982202692 +0200 @@ -0,0 +1,123 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the fcitx5-mozc package. +# +# Translators: +# scootergrisen, 2020 +# +msgid "" +msgstr "" +"Project-Id-Version: fcitx5-mozc\n" +"Report-Msgid-Bugs-To: fcitx-dev@googlegroups.com\n" +"POT-Creation-Date: 2021-12-30 02:39+0000\n" +"PO-Revision-Date: 2017-11-23 05:28+0000\n" +"Last-Translator: scootergrisen, 2020\n" +"Language-Team: Danish (https://www.transifex.com/fcitx/teams/12005/da/)\n" +"Language: da\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: mozc_engine.h:84 mozc_engine.cc:196 +msgid "About Mozc" +msgstr "Om Mozc" + +#: mozc_engine.h:82 mozc_engine.cc:189 +msgid "Add Word" +msgstr "Tilføj ord" + +#: mozc_engine.h:48 +msgid "Always" +msgstr "Altid" + +#: mozc_engine.cc:96 +msgid "Composition Mode" +msgstr "Kompositionstilstand" + +#: mozc_engine.h:78 mozc_engine.cc:173 +msgid "Configuration Tool" +msgstr "Konfigurationsværktøj" + +#: mozc_engine.h:80 mozc_engine.cc:181 +msgid "Dictionary Tool" +msgstr "Ordbogsværktøj" + +#: mozc_engine.h:51 mozc_engine.cc:52 +msgid "Direct" +msgstr "Direkte" + +#: mozc_engine.h:69 +msgid "Expand Usage (Requires vertical candidate list)" +msgstr "" + +#: mozc_engine.h:73 +msgid "Fix embedded preedit cursor at the beginning of the preedit" +msgstr "" + +#. Full width ASCII letter A. +#: mozc_engine.h:53 mozc_engine.cc:82 +msgid "Full ASCII" +msgstr "Fuld ASCII" + +#. Katakana letter A. +#: mozc_engine.h:52 mozc_engine.cc:66 +msgid "Full Katakana" +msgstr "Fuld Katakana" + +#: mozc_engine.h:52 mozc_engine.cc:74 +msgid "Half ASCII" +msgstr "Halv ASCII" + +#. Half width Katakana letter A. +#: mozc_engine.h:53 mozc_engine.cc:89 +msgid "Half Katakana" +msgstr "Halv Katakana" + +#. Hiragana letter A in UTF-8. +#: mozc_engine.h:51 mozc_engine.cc:59 +msgid "Hiragana" +msgstr "Hiragana" + +#: mozc_engine.h:49 +msgid "Hotkey" +msgstr "Hottast" + +#: mozc_engine.h:75 +msgid "Hotkey to expand usage" +msgstr "Hottast til at udvide anvendelse" + +#: mozc_engine.h:63 +msgid "Initial Mode" +msgstr "" + +#: org.fcitx.Fcitx5.Addon.Mozc.metainfo.xml.in:8 +msgid "Japanese input method based on Mozc" +msgstr "Japansk-inputmetode baseret på Mozc" + +#: org.fcitx.Fcitx5.Addon.Mozc.metainfo.xml.in:7 +msgid "Mozc for Fcitx 5" +msgstr "Mozc til Fcitx 5" + +#: mozc_engine.h:48 +msgid "On Focus" +msgstr "Ved fokus" + +#. We don't have a good library option for this, just do the simple +#. replace. absl's runtime parsed format string is too copmlex. +#: mozc_response_parser.cc:175 +#, c-format +msgid "Press %s to show usages." +msgstr "Tryk på %s for at vise anvendelser." + +#: mozc_state.cc:405 +msgid "Press Escape to go back" +msgstr "Tryk på Escape for at gå tilbage" + +#: mozc_engine.cc:159 mozc_engine.cc:160 +msgid "Tool" +msgstr "Værktøj" + +#: mozc_engine.h:65 +msgid "Vertical candidate list" +msgstr "" diff -ruN google-mozc-git/src/unix/fcitx5/po/de.po fcitx-mozc-git/src/unix/fcitx5/po/de.po --- google-mozc-git/src/unix/fcitx5/po/de.po 1970-01-01 02:00:00.000000000 +0200 +++ fcitx-mozc-git/src/unix/fcitx5/po/de.po 2022-01-31 13:12:52.982202692 +0200 @@ -0,0 +1,124 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the fcitx5-mozc package. +# +# Translators: +# csslayer , 2017 +# Ettore Atalan , 2022 +# +msgid "" +msgstr "" +"Project-Id-Version: fcitx5-mozc\n" +"Report-Msgid-Bugs-To: fcitx-dev@googlegroups.com\n" +"POT-Creation-Date: 2022-01-15 20:24+0000\n" +"PO-Revision-Date: 2017-11-23 05:28+0000\n" +"Last-Translator: Ettore Atalan , 2022\n" +"Language-Team: German (https://www.transifex.com/fcitx/teams/12005/de/)\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: mozc_engine.h:84 mozc_engine.cc:196 +msgid "About Mozc" +msgstr "" + +#: mozc_engine.h:82 mozc_engine.cc:189 +msgid "Add Word" +msgstr "Wort hinzufügen" + +#: mozc_engine.h:48 +msgid "Always" +msgstr "Immer" + +#: mozc_engine.cc:96 +msgid "Composition Mode" +msgstr "Kompositionsmodus" + +#: mozc_engine.h:78 mozc_engine.cc:173 +msgid "Configuration Tool" +msgstr "Konfigurationswerkzeug" + +#: mozc_engine.h:80 mozc_engine.cc:181 +msgid "Dictionary Tool" +msgstr "Wörterbuchwerkzeug" + +#: mozc_engine.h:51 mozc_engine.cc:52 +msgid "Direct" +msgstr "Direkt" + +#: mozc_engine.h:69 +msgid "Expand Usage (Requires vertical candidate list)" +msgstr "" + +#: mozc_engine.h:73 +msgid "Fix embedded preedit cursor at the beginning of the preedit" +msgstr "" + +#. Full width ASCII letter A. +#: mozc_engine.h:53 mozc_engine.cc:82 +msgid "Full ASCII" +msgstr "" + +#. Katakana letter A. +#: mozc_engine.h:52 mozc_engine.cc:66 +msgid "Full Katakana" +msgstr "" + +#: mozc_engine.h:52 mozc_engine.cc:74 +msgid "Half ASCII" +msgstr "" + +#. Half width Katakana letter A. +#: mozc_engine.h:53 mozc_engine.cc:89 +msgid "Half Katakana" +msgstr "" + +#. Hiragana letter A in UTF-8. +#: mozc_engine.h:51 mozc_engine.cc:59 +msgid "Hiragana" +msgstr "" + +#: mozc_engine.h:49 +msgid "Hotkey" +msgstr "Kurzbefehl" + +#: mozc_engine.h:75 +msgid "Hotkey to expand usage" +msgstr "" + +#: mozc_engine.h:63 +msgid "Initial Mode" +msgstr "Anfangsmodus" + +#: org.fcitx.Fcitx5.Addon.Mozc.metainfo.xml.in:8 +msgid "Japanese input method based on Mozc" +msgstr "" + +#: org.fcitx.Fcitx5.Addon.Mozc.metainfo.xml.in:7 +msgid "Mozc for Fcitx 5" +msgstr "" + +#: mozc_engine.h:48 +msgid "On Focus" +msgstr "Im Fokus" + +#. We don't have a good library option for this, just do the simple +#. replace. absl's runtime parsed format string is too copmlex. +#: mozc_response_parser.cc:175 +#, c-format +msgid "Press %s to show usages." +msgstr "" + +#: mozc_state.cc:405 +msgid "Press Escape to go back" +msgstr "" + +#: mozc_engine.cc:159 mozc_engine.cc:160 +msgid "Tool" +msgstr "Werkzeug" + +#: mozc_engine.h:65 +msgid "Vertical candidate list" +msgstr "" diff -ruN google-mozc-git/src/unix/fcitx5/po/fcitx5-mozc.pot fcitx-mozc-git/src/unix/fcitx5/po/fcitx5-mozc.pot --- google-mozc-git/src/unix/fcitx5/po/fcitx5-mozc.pot 1970-01-01 02:00:00.000000000 +0200 +++ fcitx-mozc-git/src/unix/fcitx5/po/fcitx5-mozc.pot 2022-01-31 13:12:52.982202692 +0200 @@ -0,0 +1,119 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the fcitx5-mozc package. +# +msgid "" +msgstr "" +"Project-Id-Version: fcitx5-mozc\n" +"Report-Msgid-Bugs-To: fcitx-dev@googlegroups.com\n" +"POT-Creation-Date: 2021-12-30 02:39+0000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: LANG\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: mozc_engine.h:84 mozc_engine.cc:196 +msgid "About Mozc" +msgstr "" + +#: mozc_engine.h:82 mozc_engine.cc:189 +msgid "Add Word" +msgstr "" + +#: mozc_engine.h:48 +msgid "Always" +msgstr "" + +#: mozc_engine.cc:96 +msgid "Composition Mode" +msgstr "" + +#: mozc_engine.h:78 mozc_engine.cc:173 +msgid "Configuration Tool" +msgstr "" + +#: mozc_engine.h:80 mozc_engine.cc:181 +msgid "Dictionary Tool" +msgstr "" + +#: mozc_engine.h:51 mozc_engine.cc:52 +msgid "Direct" +msgstr "" + +#: mozc_engine.h:69 +msgid "Expand Usage (Requires vertical candidate list)" +msgstr "" + +#: mozc_engine.h:73 +msgid "Fix embedded preedit cursor at the beginning of the preedit" +msgstr "" + +#. Full width ASCII letter A. +#: mozc_engine.h:53 mozc_engine.cc:82 +msgid "Full ASCII" +msgstr "" + +#. Katakana letter A. +#: mozc_engine.h:52 mozc_engine.cc:66 +msgid "Full Katakana" +msgstr "" + +#: mozc_engine.h:52 mozc_engine.cc:74 +msgid "Half ASCII" +msgstr "" + +#. Half width Katakana letter A. +#: mozc_engine.h:53 mozc_engine.cc:89 +msgid "Half Katakana" +msgstr "" + +#. Hiragana letter A in UTF-8. +#: mozc_engine.h:51 mozc_engine.cc:59 +msgid "Hiragana" +msgstr "" + +#: mozc_engine.h:49 +msgid "Hotkey" +msgstr "" + +#: mozc_engine.h:75 +msgid "Hotkey to expand usage" +msgstr "" + +#: mozc_engine.h:63 +msgid "Initial Mode" +msgstr "" + +#: org.fcitx.Fcitx5.Addon.Mozc.metainfo.xml.in:8 +msgid "Japanese input method based on Mozc" +msgstr "" + +#: org.fcitx.Fcitx5.Addon.Mozc.metainfo.xml.in:7 +msgid "Mozc for Fcitx 5" +msgstr "" + +#: mozc_engine.h:48 +msgid "On Focus" +msgstr "" + +#. We don't have a good library option for this, just do the simple +#. replace. absl's runtime parsed format string is too copmlex. +#: mozc_response_parser.cc:175 +#, c-format +msgid "Press %s to show usages." +msgstr "" + +#: mozc_state.cc:405 +msgid "Press Escape to go back" +msgstr "" + +#: mozc_engine.cc:159 mozc_engine.cc:160 +msgid "Tool" +msgstr "" + +#: mozc_engine.h:65 +msgid "Vertical candidate list" +msgstr "" diff -ruN google-mozc-git/src/unix/fcitx5/po/he.po fcitx-mozc-git/src/unix/fcitx5/po/he.po --- google-mozc-git/src/unix/fcitx5/po/he.po 1970-01-01 02:00:00.000000000 +0200 +++ fcitx-mozc-git/src/unix/fcitx5/po/he.po 2022-01-31 13:12:52.982202692 +0200 @@ -0,0 +1,124 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the fcitx5-mozc package. +# +# Translators: +# Omer I.S. , 2021 +# +msgid "" +msgstr "" +"Project-Id-Version: fcitx5-mozc\n" +"Report-Msgid-Bugs-To: fcitx-dev@googlegroups.com\n" +"POT-Creation-Date: 2021-12-30 02:39+0000\n" +"PO-Revision-Date: 2017-11-23 05:28+0000\n" +"Last-Translator: Omer I.S. , 2021\n" +"Language-Team: Hebrew (https://www.transifex.com/fcitx/teams/12005/he/)\n" +"Language: he\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n == 2 && n % " +"1 == 0) ? 1: (n % 10 == 0 && n % 1 == 0 && n > 10) ? 2 : 3;\n" + +#: mozc_engine.h:84 mozc_engine.cc:196 +msgid "About Mozc" +msgstr "על אודות Mozc" + +#: mozc_engine.h:82 mozc_engine.cc:189 +msgid "Add Word" +msgstr "הוספת מילה" + +#: mozc_engine.h:48 +msgid "Always" +msgstr "" + +#: mozc_engine.cc:96 +msgid "Composition Mode" +msgstr "" + +#: mozc_engine.h:78 mozc_engine.cc:173 +msgid "Configuration Tool" +msgstr "" + +#: mozc_engine.h:80 mozc_engine.cc:181 +msgid "Dictionary Tool" +msgstr "" + +#: mozc_engine.h:51 mozc_engine.cc:52 +msgid "Direct" +msgstr "" + +#: mozc_engine.h:69 +msgid "Expand Usage (Requires vertical candidate list)" +msgstr "" + +#: mozc_engine.h:73 +msgid "Fix embedded preedit cursor at the beginning of the preedit" +msgstr "" + +#. Full width ASCII letter A. +#: mozc_engine.h:53 mozc_engine.cc:82 +msgid "Full ASCII" +msgstr "" + +#. Katakana letter A. +#: mozc_engine.h:52 mozc_engine.cc:66 +msgid "Full Katakana" +msgstr "" + +#: mozc_engine.h:52 mozc_engine.cc:74 +msgid "Half ASCII" +msgstr "" + +#. Half width Katakana letter A. +#: mozc_engine.h:53 mozc_engine.cc:89 +msgid "Half Katakana" +msgstr "" + +#. Hiragana letter A in UTF-8. +#: mozc_engine.h:51 mozc_engine.cc:59 +msgid "Hiragana" +msgstr "" + +#: mozc_engine.h:49 +msgid "Hotkey" +msgstr "" + +#: mozc_engine.h:75 +msgid "Hotkey to expand usage" +msgstr "" + +#: mozc_engine.h:63 +msgid "Initial Mode" +msgstr "" + +#: org.fcitx.Fcitx5.Addon.Mozc.metainfo.xml.in:8 +msgid "Japanese input method based on Mozc" +msgstr "" + +#: org.fcitx.Fcitx5.Addon.Mozc.metainfo.xml.in:7 +msgid "Mozc for Fcitx 5" +msgstr "" + +#: mozc_engine.h:48 +msgid "On Focus" +msgstr "" + +#. We don't have a good library option for this, just do the simple +#. replace. absl's runtime parsed format string is too copmlex. +#: mozc_response_parser.cc:175 +#, c-format +msgid "Press %s to show usages." +msgstr "" + +#: mozc_state.cc:405 +msgid "Press Escape to go back" +msgstr "" + +#: mozc_engine.cc:159 mozc_engine.cc:160 +msgid "Tool" +msgstr "" + +#: mozc_engine.h:65 +msgid "Vertical candidate list" +msgstr "" diff -ruN google-mozc-git/src/unix/fcitx5/po/ja.po fcitx-mozc-git/src/unix/fcitx5/po/ja.po --- google-mozc-git/src/unix/fcitx5/po/ja.po 1970-01-01 02:00:00.000000000 +0200 +++ fcitx-mozc-git/src/unix/fcitx5/po/ja.po 2022-01-31 13:12:52.982202692 +0200 @@ -0,0 +1,124 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the fcitx5-mozc package. +# +# Translators: +# csslayer , 2017 +# UTUMI Hirosi , 2022 +# +msgid "" +msgstr "" +"Project-Id-Version: fcitx5-mozc\n" +"Report-Msgid-Bugs-To: fcitx-dev@googlegroups.com\n" +"POT-Creation-Date: 2022-01-16 20:24+0000\n" +"PO-Revision-Date: 2017-11-23 05:28+0000\n" +"Last-Translator: UTUMI Hirosi , 2022\n" +"Language-Team: Japanese (https://www.transifex.com/fcitx/teams/12005/ja/)\n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: mozc_engine.h:84 mozc_engine.cc:196 +msgid "About Mozc" +msgstr "Mozc について" + +#: mozc_engine.h:82 mozc_engine.cc:189 +msgid "Add Word" +msgstr "単語を追加" + +#: mozc_engine.h:48 +msgid "Always" +msgstr "常に" + +#: mozc_engine.cc:96 +msgid "Composition Mode" +msgstr "文字種" + +#: mozc_engine.h:78 mozc_engine.cc:173 +msgid "Configuration Tool" +msgstr "設定ツール" + +#: mozc_engine.h:80 mozc_engine.cc:181 +msgid "Dictionary Tool" +msgstr "辞書ツール" + +#: mozc_engine.h:51 mozc_engine.cc:52 +msgid "Direct" +msgstr "直接入力" + +#: mozc_engine.h:69 +msgid "Expand Usage (Requires vertical candidate list)" +msgstr "用例の表示 (候補が縦並びのとき)" + +#: mozc_engine.h:73 +msgid "Fix embedded preedit cursor at the beginning of the preedit" +msgstr "プリエディットカーソルをプリエディットの先頭に固定する" + +#. Full width ASCII letter A. +#: mozc_engine.h:53 mozc_engine.cc:82 +msgid "Full ASCII" +msgstr "全角英数" + +#. Katakana letter A. +#: mozc_engine.h:52 mozc_engine.cc:66 +msgid "Full Katakana" +msgstr "全角カナ" + +#: mozc_engine.h:52 mozc_engine.cc:74 +msgid "Half ASCII" +msgstr "半角英数" + +#. Half width Katakana letter A. +#: mozc_engine.h:53 mozc_engine.cc:89 +msgid "Half Katakana" +msgstr "半角カナ" + +#. Hiragana letter A in UTF-8. +#: mozc_engine.h:51 mozc_engine.cc:59 +msgid "Hiragana" +msgstr "全角かな" + +#: mozc_engine.h:49 +msgid "Hotkey" +msgstr "ホットキー" + +#: mozc_engine.h:75 +msgid "Hotkey to expand usage" +msgstr "用例を表示するホットキー" + +#: mozc_engine.h:63 +msgid "Initial Mode" +msgstr "初期モード" + +#: org.fcitx.Fcitx5.Addon.Mozc.metainfo.xml.in:8 +msgid "Japanese input method based on Mozc" +msgstr "Mozc をベースとした日本語入力メソッド" + +#: org.fcitx.Fcitx5.Addon.Mozc.metainfo.xml.in:7 +msgid "Mozc for Fcitx 5" +msgstr "Fcitx 5 用の Mozc" + +#: mozc_engine.h:48 +msgid "On Focus" +msgstr "フォーカス時" + +#. We don't have a good library option for this, just do the simple +#. replace. absl's runtime parsed format string is too copmlex. +#: mozc_response_parser.cc:175 +#, c-format +msgid "Press %s to show usages." +msgstr "%s で用例表示" + +#: mozc_state.cc:405 +msgid "Press Escape to go back" +msgstr "Esc キーを押して戻る" + +#: mozc_engine.cc:159 mozc_engine.cc:160 +msgid "Tool" +msgstr "ツール" + +#: mozc_engine.h:65 +msgid "Vertical candidate list" +msgstr "候補を縦に並べる" diff -ruN google-mozc-git/src/unix/fcitx5/po/ko.po fcitx-mozc-git/src/unix/fcitx5/po/ko.po --- google-mozc-git/src/unix/fcitx5/po/ko.po 1970-01-01 02:00:00.000000000 +0200 +++ fcitx-mozc-git/src/unix/fcitx5/po/ko.po 2022-01-31 13:12:52.982202692 +0200 @@ -0,0 +1,125 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the fcitx5-mozc package. +# +# Translators: +# csslayer , 2017 +# Jung Hee Lee , 2021 +# Bon Keun Seo , 2021 +# +msgid "" +msgstr "" +"Project-Id-Version: fcitx5-mozc\n" +"Report-Msgid-Bugs-To: fcitx-dev@googlegroups.com\n" +"POT-Creation-Date: 2021-12-30 02:39+0000\n" +"PO-Revision-Date: 2017-11-23 05:28+0000\n" +"Last-Translator: Bon Keun Seo , 2021\n" +"Language-Team: Korean (https://www.transifex.com/fcitx/teams/12005/ko/)\n" +"Language: ko\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: mozc_engine.h:84 mozc_engine.cc:196 +msgid "About Mozc" +msgstr "Mozc 정보" + +#: mozc_engine.h:82 mozc_engine.cc:189 +msgid "Add Word" +msgstr "단어 추가" + +#: mozc_engine.h:48 +msgid "Always" +msgstr "항상" + +#: mozc_engine.cc:96 +msgid "Composition Mode" +msgstr "조합 모드" + +#: mozc_engine.h:78 mozc_engine.cc:173 +msgid "Configuration Tool" +msgstr "환경설정 도구" + +#: mozc_engine.h:80 mozc_engine.cc:181 +msgid "Dictionary Tool" +msgstr "사전 도구" + +#: mozc_engine.h:51 mozc_engine.cc:52 +msgid "Direct" +msgstr "직접" + +#: mozc_engine.h:69 +msgid "Expand Usage (Requires vertical candidate list)" +msgstr "" + +#: mozc_engine.h:73 +msgid "Fix embedded preedit cursor at the beginning of the preedit" +msgstr "" + +#. Full width ASCII letter A. +#: mozc_engine.h:53 mozc_engine.cc:82 +msgid "Full ASCII" +msgstr "전각 아스키" + +#. Katakana letter A. +#: mozc_engine.h:52 mozc_engine.cc:66 +msgid "Full Katakana" +msgstr "전각 가타가나" + +#: mozc_engine.h:52 mozc_engine.cc:74 +msgid "Half ASCII" +msgstr "반각 아스키" + +#. Half width Katakana letter A. +#: mozc_engine.h:53 mozc_engine.cc:89 +msgid "Half Katakana" +msgstr "반각 가타가나" + +#. Hiragana letter A in UTF-8. +#: mozc_engine.h:51 mozc_engine.cc:59 +msgid "Hiragana" +msgstr "히라가나" + +#: mozc_engine.h:49 +msgid "Hotkey" +msgstr "단축키" + +#: mozc_engine.h:75 +msgid "Hotkey to expand usage" +msgstr "" + +#: mozc_engine.h:63 +msgid "Initial Mode" +msgstr "" + +#: org.fcitx.Fcitx5.Addon.Mozc.metainfo.xml.in:8 +msgid "Japanese input method based on Mozc" +msgstr "Mozc 기반 일본어 입력기" + +#: org.fcitx.Fcitx5.Addon.Mozc.metainfo.xml.in:7 +msgid "Mozc for Fcitx 5" +msgstr "Fcitx 5 용 Mozc" + +#: mozc_engine.h:48 +msgid "On Focus" +msgstr "" + +#. We don't have a good library option for this, just do the simple +#. replace. absl's runtime parsed format string is too copmlex. +#: mozc_response_parser.cc:175 +#, c-format +msgid "Press %s to show usages." +msgstr "%s 키를 눌러 사용법을 표시합니다." + +#: mozc_state.cc:405 +msgid "Press Escape to go back" +msgstr "돌아가려면 Esc 키를 누르십시오." + +#: mozc_engine.cc:159 mozc_engine.cc:160 +msgid "Tool" +msgstr "도구" + +#: mozc_engine.h:65 +msgid "Vertical candidate list" +msgstr "" diff -ruN google-mozc-git/src/unix/fcitx5/po/LINGUAS fcitx-mozc-git/src/unix/fcitx5/po/LINGUAS --- google-mozc-git/src/unix/fcitx5/po/LINGUAS 1970-01-01 02:00:00.000000000 +0200 +++ fcitx-mozc-git/src/unix/fcitx5/po/LINGUAS 2022-01-31 13:12:52.982202692 +0200 @@ -0,0 +1,11 @@ + +ca +da +de +he +ja +ko +ru +tr +zh_CN +zh_TW diff -ruN google-mozc-git/src/unix/fcitx5/po/ru.po fcitx-mozc-git/src/unix/fcitx5/po/ru.po --- google-mozc-git/src/unix/fcitx5/po/ru.po 1970-01-01 02:00:00.000000000 +0200 +++ fcitx-mozc-git/src/unix/fcitx5/po/ru.po 2022-02-07 12:26:47.179161226 +0200 @@ -0,0 +1,128 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the fcitx5-mozc package. +# +# Translators: +# csslayer , 2017 +# Dmitry , 2022 +# +msgid "" +msgstr "" +"Project-Id-Version: fcitx5-mozc\n" +"Report-Msgid-Bugs-To: fcitx-dev@googlegroups.com\n" +"POT-Creation-Date: 2022-01-31 20:24+0000\n" +"PO-Revision-Date: 2017-11-23 05:28+0000\n" +"Last-Translator: Dmitry , 2022\n" +"Language-Team: Russian (https://www.transifex.com/fcitx/teams/12005/ru/)\n" +"Language: ru\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n" +"%100>=11 && n%100<=14)? 2 : 3);\n" + +#: mozc_engine.h:84 mozc_engine.cc:196 +msgid "About Mozc" +msgstr "О Mozc" + +#: mozc_engine.h:82 mozc_engine.cc:189 +msgid "Add Word" +msgstr "Добавить слово" + +#: mozc_engine.h:48 +msgid "Always" +msgstr "Всегда" + +#: mozc_engine.cc:96 +msgid "Composition Mode" +msgstr "Композиционный режим" + +#: mozc_engine.h:78 mozc_engine.cc:173 +msgid "Configuration Tool" +msgstr "Инструмент настройки" + +#: mozc_engine.h:80 mozc_engine.cc:181 +msgid "Dictionary Tool" +msgstr "Инструмент словаря" + +#: mozc_engine.h:51 mozc_engine.cc:52 +msgid "Direct" +msgstr "Непосредственный" + +#: mozc_engine.h:69 +msgid "Expand Usage (Requires vertical candidate list)" +msgstr "Развернуть использование (требуется вертикальный список кандидатов)" + +#: mozc_engine.h:73 +msgid "Fix embedded preedit cursor at the beginning of the preedit" +msgstr "" +"Зафиксировать встроенный курсор предварительного редактирования в начале " +"предварительного редактирования." + +#. Full width ASCII letter A. +#: mozc_engine.h:53 mozc_engine.cc:82 +msgid "Full ASCII" +msgstr "Полная ASCII" + +#. Katakana letter A. +#: mozc_engine.h:52 mozc_engine.cc:66 +msgid "Full Katakana" +msgstr "Полная Катакана" + +#: mozc_engine.h:52 mozc_engine.cc:74 +msgid "Half ASCII" +msgstr "Половинная ASCII" + +#. Half width Katakana letter A. +#: mozc_engine.h:53 mozc_engine.cc:89 +msgid "Half Katakana" +msgstr "Половинная Катакана" + +#. Hiragana letter A in UTF-8. +#: mozc_engine.h:51 mozc_engine.cc:59 +msgid "Hiragana" +msgstr "Хирагана" + +#: mozc_engine.h:49 +msgid "Hotkey" +msgstr "Горячая клавиша" + +#: mozc_engine.h:75 +msgid "Hotkey to expand usage" +msgstr "Горячая клавиша для расширения использования" + +#: mozc_engine.h:63 +msgid "Initial Mode" +msgstr "Начальный режим" + +#: org.fcitx.Fcitx5.Addon.Mozc.metainfo.xml.in:8 +msgid "Japanese input method based on Mozc" +msgstr "Японский метод ввода на основе Mozc" + +#: org.fcitx.Fcitx5.Addon.Mozc.metainfo.xml.in:7 +msgid "Mozc for Fcitx 5" +msgstr "Mozc для Fcitx 5" + +#: mozc_engine.h:48 +msgid "On Focus" +msgstr "В фокусе" + +#. We don't have a good library option for this, just do the simple +#. replace. absl's runtime parsed format string is too copmlex. +#: mozc_response_parser.cc:175 +#, c-format +msgid "Press %s to show usages." +msgstr "Нажмите %s , чтобы показать использование." + +#: mozc_state.cc:405 +msgid "Press Escape to go back" +msgstr "Нажмите Escape, чтобы вернуться назад" + +#: mozc_engine.cc:159 mozc_engine.cc:160 +msgid "Tool" +msgstr "Инструмент" + +#: mozc_engine.h:65 +msgid "Vertical candidate list" +msgstr "Вертикальный список кандидатов" diff -ruN google-mozc-git/src/unix/fcitx5/po/tr.po fcitx-mozc-git/src/unix/fcitx5/po/tr.po --- google-mozc-git/src/unix/fcitx5/po/tr.po 1970-01-01 02:00:00.000000000 +0200 +++ fcitx-mozc-git/src/unix/fcitx5/po/tr.po 2022-01-31 13:12:52.982202692 +0200 @@ -0,0 +1,123 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the fcitx5-mozc package. +# +# Translators: +# abc Def , 2021 +# +msgid "" +msgstr "" +"Project-Id-Version: fcitx5-mozc\n" +"Report-Msgid-Bugs-To: fcitx-dev@googlegroups.com\n" +"POT-Creation-Date: 2021-12-30 02:39+0000\n" +"PO-Revision-Date: 2017-11-23 05:28+0000\n" +"Last-Translator: abc Def , 2021\n" +"Language-Team: Turkish (https://www.transifex.com/fcitx/teams/12005/tr/)\n" +"Language: tr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: mozc_engine.h:84 mozc_engine.cc:196 +msgid "About Mozc" +msgstr "Mozc Hakkında" + +#: mozc_engine.h:82 mozc_engine.cc:189 +msgid "Add Word" +msgstr "Kelime Ekle" + +#: mozc_engine.h:48 +msgid "Always" +msgstr "" + +#: mozc_engine.cc:96 +msgid "Composition Mode" +msgstr "" + +#: mozc_engine.h:78 mozc_engine.cc:173 +msgid "Configuration Tool" +msgstr "" + +#: mozc_engine.h:80 mozc_engine.cc:181 +msgid "Dictionary Tool" +msgstr "" + +#: mozc_engine.h:51 mozc_engine.cc:52 +msgid "Direct" +msgstr "" + +#: mozc_engine.h:69 +msgid "Expand Usage (Requires vertical candidate list)" +msgstr "" + +#: mozc_engine.h:73 +msgid "Fix embedded preedit cursor at the beginning of the preedit" +msgstr "" + +#. Full width ASCII letter A. +#: mozc_engine.h:53 mozc_engine.cc:82 +msgid "Full ASCII" +msgstr "" + +#. Katakana letter A. +#: mozc_engine.h:52 mozc_engine.cc:66 +msgid "Full Katakana" +msgstr "" + +#: mozc_engine.h:52 mozc_engine.cc:74 +msgid "Half ASCII" +msgstr "" + +#. Half width Katakana letter A. +#: mozc_engine.h:53 mozc_engine.cc:89 +msgid "Half Katakana" +msgstr "" + +#. Hiragana letter A in UTF-8. +#: mozc_engine.h:51 mozc_engine.cc:59 +msgid "Hiragana" +msgstr "" + +#: mozc_engine.h:49 +msgid "Hotkey" +msgstr "" + +#: mozc_engine.h:75 +msgid "Hotkey to expand usage" +msgstr "" + +#: mozc_engine.h:63 +msgid "Initial Mode" +msgstr "" + +#: org.fcitx.Fcitx5.Addon.Mozc.metainfo.xml.in:8 +msgid "Japanese input method based on Mozc" +msgstr "" + +#: org.fcitx.Fcitx5.Addon.Mozc.metainfo.xml.in:7 +msgid "Mozc for Fcitx 5" +msgstr "" + +#: mozc_engine.h:48 +msgid "On Focus" +msgstr "" + +#. We don't have a good library option for this, just do the simple +#. replace. absl's runtime parsed format string is too copmlex. +#: mozc_response_parser.cc:175 +#, c-format +msgid "Press %s to show usages." +msgstr "" + +#: mozc_state.cc:405 +msgid "Press Escape to go back" +msgstr "" + +#: mozc_engine.cc:159 mozc_engine.cc:160 +msgid "Tool" +msgstr "" + +#: mozc_engine.h:65 +msgid "Vertical candidate list" +msgstr "" diff -ruN google-mozc-git/src/unix/fcitx5/po/zh_CN.po fcitx-mozc-git/src/unix/fcitx5/po/zh_CN.po --- google-mozc-git/src/unix/fcitx5/po/zh_CN.po 1970-01-01 02:00:00.000000000 +0200 +++ fcitx-mozc-git/src/unix/fcitx5/po/zh_CN.po 2022-01-31 13:12:52.982202692 +0200 @@ -0,0 +1,124 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the fcitx5-mozc package. +# +# Translators: +# csslayer , 2021 +# +msgid "" +msgstr "" +"Project-Id-Version: fcitx5-mozc\n" +"Report-Msgid-Bugs-To: fcitx-dev@googlegroups.com\n" +"POT-Creation-Date: 2021-12-30 02:39+0000\n" +"PO-Revision-Date: 2017-11-23 05:28+0000\n" +"Last-Translator: csslayer , 2021\n" +"Language-Team: Chinese (China) (https://www.transifex.com/fcitx/teams/12005/" +"zh_CN/)\n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: mozc_engine.h:84 mozc_engine.cc:196 +msgid "About Mozc" +msgstr "关于 Mozc" + +#: mozc_engine.h:82 mozc_engine.cc:189 +msgid "Add Word" +msgstr "添加词组" + +#: mozc_engine.h:48 +msgid "Always" +msgstr "总是" + +#: mozc_engine.cc:96 +msgid "Composition Mode" +msgstr "编辑模式" + +#: mozc_engine.h:78 mozc_engine.cc:173 +msgid "Configuration Tool" +msgstr "配置工具" + +#: mozc_engine.h:80 mozc_engine.cc:181 +msgid "Dictionary Tool" +msgstr "词典工具" + +#: mozc_engine.h:51 mozc_engine.cc:52 +msgid "Direct" +msgstr "直接键盘输入" + +#: mozc_engine.h:69 +msgid "Expand Usage (Requires vertical candidate list)" +msgstr "展开用法 (需要垂直候选列表)" + +#: mozc_engine.h:73 +msgid "Fix embedded preedit cursor at the beginning of the preedit" +msgstr "固定嵌入预编辑文本光标在预编辑的开头" + +#. Full width ASCII letter A. +#: mozc_engine.h:53 mozc_engine.cc:82 +msgid "Full ASCII" +msgstr "全角 ASCII" + +#. Katakana letter A. +#: mozc_engine.h:52 mozc_engine.cc:66 +msgid "Full Katakana" +msgstr "全角片假名" + +#: mozc_engine.h:52 mozc_engine.cc:74 +msgid "Half ASCII" +msgstr "半角 ASCII" + +#. Half width Katakana letter A. +#: mozc_engine.h:53 mozc_engine.cc:89 +msgid "Half Katakana" +msgstr "半角片假名" + +#. Hiragana letter A in UTF-8. +#: mozc_engine.h:51 mozc_engine.cc:59 +msgid "Hiragana" +msgstr "平假名" + +#: mozc_engine.h:49 +msgid "Hotkey" +msgstr "快捷键" + +#: mozc_engine.h:75 +msgid "Hotkey to expand usage" +msgstr "展开用法的快捷键" + +#: mozc_engine.h:63 +msgid "Initial Mode" +msgstr "初始模式" + +#: org.fcitx.Fcitx5.Addon.Mozc.metainfo.xml.in:8 +msgid "Japanese input method based on Mozc" +msgstr "基于 Mozc 的日语输入法" + +#: org.fcitx.Fcitx5.Addon.Mozc.metainfo.xml.in:7 +msgid "Mozc for Fcitx 5" +msgstr "Fcitx 5 的 Mozc 支持" + +#: mozc_engine.h:48 +msgid "On Focus" +msgstr "选中时" + +#. We don't have a good library option for this, just do the simple +#. replace. absl's runtime parsed format string is too copmlex. +#: mozc_response_parser.cc:175 +#, c-format +msgid "Press %s to show usages." +msgstr "按下 %s 显示用法。" + +#: mozc_state.cc:405 +msgid "Press Escape to go back" +msgstr "按 Escape 返回" + +#: mozc_engine.cc:159 mozc_engine.cc:160 +msgid "Tool" +msgstr "工具" + +#: mozc_engine.h:65 +msgid "Vertical candidate list" +msgstr "垂直候选列表" diff -ruN google-mozc-git/src/unix/fcitx5/po/zh_TW.po fcitx-mozc-git/src/unix/fcitx5/po/zh_TW.po --- google-mozc-git/src/unix/fcitx5/po/zh_TW.po 1970-01-01 02:00:00.000000000 +0200 +++ fcitx-mozc-git/src/unix/fcitx5/po/zh_TW.po 2022-01-31 13:12:52.982202692 +0200 @@ -0,0 +1,125 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the fcitx5-mozc package. +# +# Translators: +# csslayer , 2017 +# bruh, 2020 +# +msgid "" +msgstr "" +"Project-Id-Version: fcitx5-mozc\n" +"Report-Msgid-Bugs-To: fcitx-dev@googlegroups.com\n" +"POT-Creation-Date: 2021-12-30 02:39+0000\n" +"PO-Revision-Date: 2017-11-23 05:28+0000\n" +"Last-Translator: bruh, 2020\n" +"Language-Team: Chinese (Taiwan) (https://www.transifex.com/fcitx/teams/12005/" +"zh_TW/)\n" +"Language: zh_TW\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: mozc_engine.h:84 mozc_engine.cc:196 +msgid "About Mozc" +msgstr "關於 Mozc" + +#: mozc_engine.h:82 mozc_engine.cc:189 +msgid "Add Word" +msgstr "添加單詞" + +#: mozc_engine.h:48 +msgid "Always" +msgstr "" + +#: mozc_engine.cc:96 +msgid "Composition Mode" +msgstr "編輯模式" + +#: mozc_engine.h:78 mozc_engine.cc:173 +msgid "Configuration Tool" +msgstr "設定工具" + +#: mozc_engine.h:80 mozc_engine.cc:181 +msgid "Dictionary Tool" +msgstr "字典工具" + +#: mozc_engine.h:51 mozc_engine.cc:52 +msgid "Direct" +msgstr "直接鍵盤輸入" + +#: mozc_engine.h:69 +msgid "Expand Usage (Requires vertical candidate list)" +msgstr "" + +#: mozc_engine.h:73 +msgid "Fix embedded preedit cursor at the beginning of the preedit" +msgstr "" + +#. Full width ASCII letter A. +#: mozc_engine.h:53 mozc_engine.cc:82 +msgid "Full ASCII" +msgstr "全形 ASCII" + +#. Katakana letter A. +#: mozc_engine.h:52 mozc_engine.cc:66 +msgid "Full Katakana" +msgstr "全形片假名" + +#: mozc_engine.h:52 mozc_engine.cc:74 +msgid "Half ASCII" +msgstr "半形 ASCII" + +#. Half width Katakana letter A. +#: mozc_engine.h:53 mozc_engine.cc:89 +msgid "Half Katakana" +msgstr "半形片假名" + +#. Hiragana letter A in UTF-8. +#: mozc_engine.h:51 mozc_engine.cc:59 +msgid "Hiragana" +msgstr "平假名" + +#: mozc_engine.h:49 +msgid "Hotkey" +msgstr "" + +#: mozc_engine.h:75 +msgid "Hotkey to expand usage" +msgstr "" + +#: mozc_engine.h:63 +msgid "Initial Mode" +msgstr "" + +#: org.fcitx.Fcitx5.Addon.Mozc.metainfo.xml.in:8 +msgid "Japanese input method based on Mozc" +msgstr "基於 Mozc 的日語輸入法" + +#: org.fcitx.Fcitx5.Addon.Mozc.metainfo.xml.in:7 +msgid "Mozc for Fcitx 5" +msgstr "Fcitx 5 的 Mozc 支援" + +#: mozc_engine.h:48 +msgid "On Focus" +msgstr "" + +#. We don't have a good library option for this, just do the simple +#. replace. absl's runtime parsed format string is too copmlex. +#: mozc_response_parser.cc:175 +#, c-format +msgid "Press %s to show usages." +msgstr "" + +#: mozc_state.cc:405 +msgid "Press Escape to go back" +msgstr "按下 Escape 返回" + +#: mozc_engine.cc:159 mozc_engine.cc:160 +msgid "Tool" +msgstr "工具" + +#: mozc_engine.h:65 +msgid "Vertical candidate list" +msgstr "" diff -ruN google-mozc-git/src/unix/fcitx5/surrounding_text_util.cc fcitx-mozc-git/src/unix/fcitx5/surrounding_text_util.cc --- google-mozc-git/src/unix/fcitx5/surrounding_text_util.cc 1970-01-01 02:00:00.000000000 +0200 +++ fcitx-mozc-git/src/unix/fcitx5/surrounding_text_util.cc 2022-01-31 13:12:52.982202692 +0200 @@ -0,0 +1,222 @@ +// Copyright 2010-2013, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "unix/fcitx5/surrounding_text_util.h" + +#include +#include + +#include +#include + +#include "base/logging.h" +#include "base/port.h" +#include "base/util.h" + +namespace fcitx { + +using namespace mozc; + +bool SurroundingTextUtil::GetSafeDelta(unsigned int from, unsigned int to, + int32 *delta) { + DCHECK(delta); + + static_assert(sizeof(int64) >= sizeof(unsigned int), + "int64 must be sufficient to store a unsigned int value."); + static_assert(sizeof(int64) == sizeof(llabs(0)), + "|llabs(0)| must returns a 64-bit integer."); + const int64 kInt32AbsMax = + llabs(static_cast(std::numeric_limits::max())); + const int64 kInt32AbsMin = + llabs(static_cast(std::numeric_limits::min())); + const int64 kInt32SafeAbsMax = std::min(kInt32AbsMax, kInt32AbsMin); + + const int64 diff = static_cast(from) - static_cast(to); + if (llabs(diff) > kInt32SafeAbsMax) { + return false; + } + + *delta = static_cast(diff); + return true; +} + +namespace { + +// Moves |iter| with |skip_count| characters. +// Returns false if |iter| reaches to the end before skipping +// |skip_count| characters. +bool Skip(ConstChar32Iterator *iter, size_t skip_count) { + for (size_t i = 0; i < skip_count; ++i) { + if (iter->Done()) { + return false; + } + iter->Next(); + } + return true; +} + +// Returns true if |prefix_iter| is the prefix of |iter|. +// Returns false if |prefix_iter| is an empty sequence. +// Otherwise returns false. +// This function receives ConstChar32Iterator as pointer because +// ConstChar32Iterator is defined as non-copyable. +bool StartsWith(ConstChar32Iterator *iter, ConstChar32Iterator *prefix_iter) { + if (iter->Done() || prefix_iter->Done()) { + return false; + } + + while (true) { + if (iter->Get() != prefix_iter->Get()) { + return false; + } + prefix_iter->Next(); + if (prefix_iter->Done()) { + return true; + } + iter->Next(); + if (iter->Done()) { + return false; + } + } +} + +// Returns true if |surrounding_text| contains |selected_text| +// from |cursor_pos| to |*anchor_pos|. +// Otherwise returns false. +bool SearchAnchorPosForward(const std::string &surrounding_text, + const std::string &selected_text, + size_t selected_chars_len, unsigned int cursor_pos, + unsigned int *anchor_pos) { + ConstChar32Iterator iter(surrounding_text); + // Move |iter| to cursor pos. + if (!Skip(&iter, cursor_pos)) { + return false; + } + + ConstChar32Iterator sel_iter(selected_text); + if (!StartsWith(&iter, &sel_iter)) { + return false; + } + *anchor_pos = cursor_pos + selected_chars_len; + return true; +} + +// Returns true if |surrounding_text| contains |selected_text| +// from |*anchor_pos| to |cursor_pos|. +// Otherwise returns false. +bool SearchAnchorPosBackward(const std::string &surrounding_text, + const std::string &selected_text, + size_t selected_chars_len, unsigned int cursor_pos, + unsigned int *anchor_pos) { + if (cursor_pos < selected_chars_len) { + return false; + } + + ConstChar32Iterator iter(surrounding_text); + // Skip |iter| to (potential) anchor pos. + const unsigned int skip_count = cursor_pos - selected_chars_len; + DCHECK_LE(skip_count, cursor_pos); + if (!Skip(&iter, skip_count)) { + return false; + } + + ConstChar32Iterator sel_iter(selected_text); + if (!StartsWith(&iter, &sel_iter)) { + return false; + } + *anchor_pos = cursor_pos - selected_chars_len; + return true; +} + +} // namespace + +bool SurroundingTextUtil::GetAnchorPosFromSelection( + const std::string &surrounding_text, const std::string &selected_text, + unsigned int cursor_pos, unsigned int *anchor_pos) { + DCHECK(anchor_pos); + + if (surrounding_text.empty()) { + return false; + } + + if (selected_text.empty()) { + return false; + } + + const size_t selected_chars_len = Util::CharsLen(selected_text); + + if (SearchAnchorPosForward(surrounding_text, selected_text, + selected_chars_len, cursor_pos, anchor_pos)) { + return true; + } + + return SearchAnchorPosBackward(surrounding_text, selected_text, + selected_chars_len, cursor_pos, anchor_pos); +} + +bool GetSurroundingText(InputContext *ic, SurroundingTextInfo *info, + AddonInstance *clipboard) { + if (!ic->capabilityFlags().test(CapabilityFlag::SurroundingText) || + !ic->surroundingText().isValid()) { + return false; + } + + const auto surrounding_text = ic->surroundingText().text(); + unsigned int cursor_pos = ic->surroundingText().cursor(); + unsigned int anchor_pos = ic->surroundingText().anchor(); + + if (cursor_pos == anchor_pos && clipboard) { + std::string primary = clipboard->call(ic); + if (!primary.empty()) { + unsigned int new_anchor_pos = 0; + if (SurroundingTextUtil::GetAnchorPosFromSelection( + surrounding_text, primary, cursor_pos, &new_anchor_pos)) { + anchor_pos = new_anchor_pos; + } + } + } + + if (!SurroundingTextUtil::GetSafeDelta(cursor_pos, anchor_pos, + &info->relative_selected_length)) { + LOG(ERROR) << "Too long text selection."; + return false; + } + + const size_t selection_start = std::min(cursor_pos, anchor_pos); + const size_t selection_length = std::abs(info->relative_selected_length); + info->preceding_text = + Util::Utf8SubString(surrounding_text, 0, selection_start); + info->selection_text = + Util::Utf8SubString(surrounding_text, selection_start, selection_length); + info->following_text = + Util::Utf8SubString(surrounding_text, selection_start + selection_length); + return true; +} + +} // namespace fcitx diff -ruN google-mozc-git/src/unix/fcitx5/surrounding_text_util.h fcitx-mozc-git/src/unix/fcitx5/surrounding_text_util.h --- google-mozc-git/src/unix/fcitx5/surrounding_text_util.h 1970-01-01 02:00:00.000000000 +0200 +++ fcitx-mozc-git/src/unix/fcitx5/surrounding_text_util.h 2022-01-31 13:12:52.982202692 +0200 @@ -0,0 +1,86 @@ +// Copyright 2010-2013, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef MOZC_UNIX_FCITX_SURROUNDING_TEXT_URIL_H_ +#define MOZC_UNIX_FCITX_SURROUNDING_TEXT_URIL_H_ + +#include + +#include + +#include "base/port.h" + +namespace fcitx { + +class AddonInstance; + +struct SurroundingTextInfo { + SurroundingTextInfo() : relative_selected_length(0) {} + + int32 relative_selected_length; + std::string preceding_text; + std::string selection_text; + std::string following_text; +}; + +class SurroundingTextUtil { + public: + // Calculates |from| - |to| and stores the result into |delta| with + // checking integer overflow. + // Returns true when neither |abs(delta)| nor |-delta| does not cause + // integer overflow, that is, |delta| is in a safe range. + // Returns false otherwise. + static bool GetSafeDelta(unsigned int from, unsigned int to, int32 *delta); + + // Returns true if + // 1. |surrounding_text| contains |selected_text| + // from |cursor_pos| to |*anchor_pos|. + // or, + // 2. |surrounding_text| contains |selected_text| + // from |*anchor_pos| to |cursor_pos|. + // with calculating |*anchor_pos|, + // where |cursor_pos| and |*anchor_pos| are counts of Unicode characters. + // When both 1) and 2) are satisfied, this function calculates + // |*anchor_pos| for case 1). + // Otherwise returns false. + static bool GetAnchorPosFromSelection(const std::string &surrounding_text, + const std::string &selected_text, + unsigned int cursor_pos, + unsigned int *anchor_pos); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(SurroundingTextUtil); +}; + +bool GetSurroundingText(InputContext *ic, SurroundingTextInfo *info, + AddonInstance *clipboard); + +} // namespace fcitx + +#endif // MOZC_UNIX_FCITX_SURROUNDING_TEXT_URIL_H_ diff -ruN google-mozc-git/src/WORKSPACE.bazel fcitx-mozc-git/src/WORKSPACE.bazel --- google-mozc-git/src/WORKSPACE.bazel 2022-01-31 13:10:42.543472208 +0200 +++ fcitx-mozc-git/src/WORKSPACE.bazel 2022-01-31 13:12:52.548863897 +0200 @@ -60,6 +60,22 @@ build_file = "BUILD.ibus.bazel", ) +# Fcitx +new_local_repository( + name = "fcitx", + # This path should be updated per the environment. + path = "/usr", # For Debian + build_file = "BUILD.fcitx.bazel", +) + +# Fcitx 5 +new_local_repository( + name = "fcitx5", + # This path should be updated per the environment. + path = "/usr", # For Debian + build_file = "BUILD.fcitx5.bazel", +) + # Japanese Usage Dictionary new_local_repository( name = "ja_usage_dict",