File fcitx-mozc-2.23.2815.102.1.patch of Package mozc

diff --git a/src/unix/fcitx/eim.cc b/src/unix/fcitx/eim.cc
new file mode 100644
index 00000000..ce3e205a
--- /dev/null
+++ b/src/unix/fcitx/eim.cc
@@ -0,0 +1,271 @@
+// Copyright 2012~2013, Weng Xuetian <wengxt@gmail.com>
+// 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 <fcitx/instance.h>
+#include <fcitx/ime.h>
+#include <fcitx/hook.h>
+#include <fcitx/module.h>
+#include <fcitx/keys.h>
+#include <fcitx-config/xdg.h>
+#include "fcitx_mozc.h"
+#include "mozc_connection.h"
+#include "mozc_response_parser.h"
+#include "base/init_mozc.h"
+
+typedef struct _FcitxMozcState {
+    mozc::fcitx::FcitxMozc* mozc;
+    int inUsageState;
+} FcitxMozcState;
+
+
+static void* FcitxMozcCreate(FcitxInstance* instance);
+static void FcitxMozcDestroy(void *arg);
+static boolean FcitxMozcInit(void *arg); /**< FcitxMozcInit */
+static void FcitxMozcResetIM(void *arg); /**< FcitxMozcResetIM */
+static void FcitxMozcReset(void *arg); /**< FcitxMozcResetIM */
+static INPUT_RETURN_VALUE FcitxMozcDoInput(void *arg, FcitxKeySym, unsigned int); /**< FcitxMozcDoInput */
+static INPUT_RETURN_VALUE FcitxMozcDoReleaseInput(void *arg, FcitxKeySym, unsigned int); /**< FcitxMozcDoInput */
+static void FcitxMozcSave(void *arg); /**< FcitxMozcSave */
+static void FcitxMozcReloadConfig(void *arg); /**< FcitxMozcReloadConfig */
+
+extern "C" {
+
+FCITX_EXPORT_API
+FcitxIMClass ime = {
+    FcitxMozcCreate,
+    FcitxMozcDestroy
+};
+FCITX_EXPORT_API
+int ABI_VERSION = FCITX_ABI_VERSION;
+
+}
+
+static inline bool CheckLayout(FcitxInstance* instance)
+{
+    char *layout = NULL, *variant = NULL;
+    FcitxModuleFunctionArg args;
+    args.args[0] = &layout;
+    args.args[1] = &variant;
+    bool layout_is_jp = false;
+    FcitxModuleInvokeFunctionByName(instance, "fcitx-xkb", 1, args);
+    if (layout && strcmp(layout, "jp") == 0)
+        layout_is_jp = true;
+
+    fcitx_utils_free(layout);
+    fcitx_utils_free(variant);
+
+
+    return layout_is_jp;
+}
+
+static void* FcitxMozcCreate(FcitxInstance* instance)
+{
+    FcitxMozcState* mozcState = (FcitxMozcState*) fcitx_utils_malloc0(sizeof(FcitxMozcState));
+    bindtextdomain("fcitx-mozc", LOCALEDIR);
+    bind_textdomain_codeset("fcitx-mozc", "UTF-8");
+
+    int argc = 1;
+    char argv0[] = "fcitx_mozc";
+    char *_argv[] = {  argv0 };
+    char **argv = _argv;
+    mozc::InitMozc(argv[0], &argc, &argv, true);
+    mozcState->mozc = new mozc::fcitx::FcitxMozc(
+        instance,
+        mozc::fcitx::MozcConnection::CreateMozcConnection(),
+        new mozc::fcitx::MozcResponseParser
+    );
+
+    mozcState->mozc->SetCompositionMode(mozc::commands::HIRAGANA);
+
+    FcitxIMEventHook hk;
+    hk.arg = mozcState;
+    hk.func = FcitxMozcReset;
+
+    FcitxInstanceRegisterResetInputHook(instance, hk);
+
+    FcitxIMIFace iface;
+    memset(&iface, 0, sizeof(FcitxIMIFace));
+    iface.Init = FcitxMozcInit;
+    iface.ResetIM = FcitxMozcResetIM;
+    iface.DoInput = FcitxMozcDoInput;
+    iface.DoReleaseInput = FcitxMozcDoReleaseInput;
+    iface.ReloadConfig = FcitxMozcReloadConfig;
+    iface.Save = FcitxMozcSave;
+
+
+    FcitxInstanceRegisterIMv2(
+        instance,
+        mozcState,
+        "mozc",
+        "Mozc",
+        mozcState->mozc->GetIconFile("mozc.png").c_str(),
+        iface,
+        1,
+        "ja"
+    );
+
+    return mozcState;
+}
+
+static void FcitxMozcDestroy(void *arg)
+{
+    FcitxMozcState* mozcState = (FcitxMozcState*) arg;
+    delete mozcState->mozc;
+    free(mozcState);
+}
+
+static const FcitxHotkey MOZC_CTRL_ALT_H[2] = {
+    {NULL, FcitxKey_H, FcitxKeyState_Ctrl_Alt},
+    {NULL, FcitxKey_None, 0}
+};
+
+INPUT_RETURN_VALUE FcitxMozcDoInput(void* arg, FcitxKeySym _sym, unsigned int _state)
+{
+    FcitxMozcState* mozcState = (FcitxMozcState*) arg;
+    FcitxInstance* instance = mozcState->mozc->GetInstance();
+    FcitxInputState* input = FcitxInstanceGetInputState(mozcState->mozc->GetInstance());
+
+    if (mozcState->inUsageState) {
+        if (FcitxHotkeyIsHotKey(_sym, _state, FCITX_ESCAPE)) {
+            mozcState->inUsageState = false;
+            // send a dummy key to let server send us the candidate info back without side effect
+            mozcState->mozc->process_key_event(FcitxKey_VoidSymbol, 0, 0, CheckLayout(instance), false);
+            return IRV_DISPLAY_CANDWORDS;
+        } else {
+            return IRV_DO_NOTHING;
+        }
+    }
+
+    if (FcitxHotkeyIsHotKey(_sym, _state, MOZC_CTRL_ALT_H)) {
+        std::pair< string, string > usage = mozcState->mozc->GetUsage();
+        if (usage.first.size() != 0 || usage.second.size() != 0) {
+            mozcState->inUsageState = true;
+            FcitxCandidateWordList* candList = FcitxInputStateGetCandidateList(mozcState->mozc->GetInputState());
+
+            // clear preedit, but keep client preedit
+            FcitxMessages* preedit = FcitxInputStateGetPreedit(input);
+            FcitxMessagesSetMessageCount(preedit, 0);
+            FcitxInputStateSetShowCursor(input, false);
+
+            // clear aux
+            FcitxMessages* auxUp = FcitxInputStateGetAuxUp(input);
+            FcitxMessages* auxDown = FcitxInputStateGetAuxDown(input);
+            FcitxMessagesSetMessageCount(auxUp, 0);
+            FcitxMessagesSetMessageCount(auxDown, 0);
+
+            // clear candidate table
+            FcitxCandidateWordReset(candList);
+            FcitxCandidateWordSetPageSize(candList, 9);
+            FcitxCandidateWordSetLayoutHint(candList, CLH_Vertical);
+            FcitxCandidateWordSetChoose(candList, "\0\0\0\0\0\0\0\0\0\0");
+            FcitxMessagesAddMessageAtLast(preedit, MSG_TIPS, "%s [%s]", usage.first.c_str(), _("Press Escape to go back"));
+
+            UT_array* lines = fcitx_utils_split_string(usage.second.c_str(), '\n');
+            utarray_foreach(line, lines, char*) {
+                FcitxCandidateWord candWord;
+                candWord.callback = NULL;
+                candWord.extraType = MSG_OTHER;
+                candWord.strExtra = NULL;
+                candWord.priv = NULL;
+                candWord.strWord = strdup(*line);
+                candWord.wordType = MSG_OTHER;
+                candWord.owner = NULL;
+                FcitxCandidateWordAppend(candList, &candWord);
+            }
+            utarray_free(lines);
+            return IRV_DISPLAY_MESSAGE;
+        }
+    }
+
+    FCITX_UNUSED(_sym);
+    FCITX_UNUSED(_state);
+    FcitxKeySym sym = (FcitxKeySym) FcitxInputStateGetKeySym(input);
+    uint32 keycode = FcitxInputStateGetKeyCode(input);
+    uint32 state = FcitxInputStateGetKeyState(input);
+    bool result = mozcState->mozc->process_key_event(sym, keycode, state, CheckLayout(instance), false);
+    if (!result)
+        return IRV_TO_PROCESS;
+    else
+        return IRV_DISPLAY_CANDWORDS;
+}
+
+INPUT_RETURN_VALUE FcitxMozcDoReleaseInput(void* arg, FcitxKeySym _sym, unsigned int _state)
+{
+    FcitxMozcState* mozcState = (FcitxMozcState*) arg;
+    FcitxInstance* instance = mozcState->mozc->GetInstance();
+    FcitxInputState* input = FcitxInstanceGetInputState(mozcState->mozc->GetInstance());
+    FCITX_UNUSED(_sym);
+    FCITX_UNUSED(_state);
+
+    if (mozcState->inUsageState) {
+        return IRV_DONOT_PROCESS;
+    }
+
+    FcitxKeySym sym = (FcitxKeySym) FcitxInputStateGetKeySym(input);
+    uint32 keycode = FcitxInputStateGetKeyCode(input);
+    uint32 state = FcitxInputStateGetKeyState(input);
+    bool result = mozcState->mozc->process_key_event(sym, keycode, state, CheckLayout(instance), true);
+    if (!result)
+        return IRV_TO_PROCESS;
+    else
+        return IRV_DISPLAY_CANDWORDS;
+}
+
+
+
+boolean FcitxMozcInit(void* arg)
+{
+    FcitxMozcState* mozcState = (FcitxMozcState*) arg;
+    mozcState->mozc->init();
+    return true;
+}
+
+void FcitxMozcReloadConfig(void* arg)
+{
+
+}
+
+void FcitxMozcSave(void* arg)
+{
+    FCITX_UNUSED(arg);
+}
+
+void FcitxMozcResetIM(void* arg)
+{
+    FcitxMozcState* mozcState = (FcitxMozcState*) arg;
+    mozcState->inUsageState = false;
+    mozcState->mozc->resetim();
+}
+
+void FcitxMozcReset(void* arg)
+{
+    FcitxMozcState* mozcState = (FcitxMozcState*) arg;
+    mozcState->mozc->reset();
+
+}
diff --git a/src/unix/fcitx/fcitx-mozc.conf b/src/unix/fcitx/fcitx-mozc.conf
new file mode 100644
index 00000000..65d0e113
--- /dev/null
+++ b/src/unix/fcitx/fcitx-mozc.conf
@@ -0,0 +1,11 @@
+[Addon]
+Name=fcitx-mozc
+GeneralName=Mozc
+Comment=Mozc support for Fcitx
+Category=InputMethod
+Enabled=True
+Library=fcitx-mozc.so
+Type=SharedLibrary
+SubConfig=
+IMRegisterMethod=ConfigFile
+LoadLocal=True
diff --git a/src/unix/fcitx/fcitx.gyp b/src/unix/fcitx/fcitx.gyp
new file mode 100644
index 00000000..e59d43a3
--- /dev/null
+++ b/src/unix/fcitx/fcitx.gyp
@@ -0,0 +1,111 @@
+#
+# Copyright (c) 2010-2012 fcitx Project http://code.google.com/p/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_fcitx%': 'YES',
+    'relative_dir': 'unix/fcitx',
+    'gen_out_dir': '<(SHARED_INTERMEDIATE_DIR)/<(relative_dir)',
+    'pkg_config_libs': [
+      'fcitx',
+      'fcitx-config',
+      'fcitx-utils',
+    ],
+    'fcitx_dep_include_dirs': [
+    ],
+    '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_fcitx=="YES"', {
+  'targets': [
+    {
+      'target_name': 'gen_fcitx_mozc_i18n',
+      'type': 'none',
+      'actions': [
+        {
+          'action_name': 'gen_fcitx_mozc_i18n',
+          'inputs': [
+            './gen_fcitx_mozc_i18n.sh'
+          ],
+          'outputs': [
+            '<(gen_out_dir)/po/zh_CN.mo',
+            '<(gen_out_dir)/po/zh_TW.mo',
+            '<(gen_out_dir)/po/ja.mo',
+            '<(gen_out_dir)/po/de.mo',
+          ],
+          'action': [
+            'sh',
+            './gen_fcitx_mozc_i18n.sh',
+            '<(gen_out_dir)/po',
+          ],
+        }],
+    },
+    {
+      'target_name': 'fcitx-mozc',
+      'product_prefix': '',
+      'type': 'loadable_module',
+      'sources': [
+        'fcitx_mozc.cc',
+        'fcitx_key_translator.cc',
+        'fcitx_key_event_handler.cc',
+        'mozc_connection.cc',
+        'mozc_response_parser.cc',
+        'surrounding_text_util.cc',
+        'eim.cc',
+      ],
+      'dependencies': [
+        '<@(fcitx_dependencies)',
+        'gen_fcitx_mozc_i18n',
+      ],
+      'cflags': [
+        '<!@(pkg-config --cflags <@(pkg_config_libs))',
+      ],
+      'include_dirs': [
+        '<@(fcitx_dep_include_dirs)',
+      ],
+      'defines': [
+        'LOCALEDIR="<!@(fcitx4-config --prefix)/share/locale/"',
+      ],
+    },
+  ],
+  }, {
+  'targets': [
+    {
+      'target_name': 'no_fcitx_dummy',
+      'type': 'none',
+    }
+  ]}
+  ]],
+}
diff --git a/src/unix/fcitx/fcitx_key_event_handler.cc b/src/unix/fcitx/fcitx_key_event_handler.cc
new file mode 100644
index 00000000..4ec8b5d0
--- /dev/null
+++ b/src/unix/fcitx/fcitx_key_event_handler.cc
@@ -0,0 +1,243 @@
+// Copyright 2010-2012, Google Inc.
+// Copyright 2012~2013, Weng Xuetian <wengxt@gmail.com>
+// 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/fcitx/fcitx_key_event_handler.h"
+
+#include <map>
+
+#include "base/logging.h"
+#include "base/singleton.h"
+
+namespace mozc {
+namespace fcitx {
+
+namespace {
+// TODO(hsumita): Removes this class, and moves |data_| into member
+// variables of KeyEventhandler.
+class AdditionalModifiersData {
+ public:
+  AdditionalModifiersData() {
+    data_[commands::KeyEvent::LEFT_ALT] = commands::KeyEvent::ALT;
+    data_[commands::KeyEvent::RIGHT_ALT] = commands::KeyEvent::ALT;
+    data_[commands::KeyEvent::LEFT_CTRL] = commands::KeyEvent::CTRL;
+    data_[commands::KeyEvent::RIGHT_CTRL] = commands::KeyEvent::CTRL;
+    data_[commands::KeyEvent::LEFT_SHIFT] = commands::KeyEvent::SHIFT;
+    data_[commands::KeyEvent::RIGHT_SHIFT] = commands::KeyEvent::SHIFT;
+  }
+  const std::map<uint32, commands::KeyEvent::ModifierKey> &data() {
+    return data_;
+  }
+
+ private:
+  std::map<uint32, commands::KeyEvent::ModifierKey> data_;
+};
+
+// TODO(hsumita): Moves this function into member functions of
+// KeyEventHandler.
+void AddAdditionalModifiers(
+    std::set<commands::KeyEvent::ModifierKey> *modifier_keys_set) {
+  DCHECK(modifier_keys_set);
+
+  const std::map<uint32, commands::KeyEvent::ModifierKey> &data =
+      Singleton<AdditionalModifiersData>::get()->data();
+
+  // Adds MODIFIER if there are (LEFT|RIGHT)_MODIFIER like LEFT_SHIFT.
+  for (std::set<commands::KeyEvent::ModifierKey>::const_iterator it =
+           modifier_keys_set->begin(); it != modifier_keys_set->end(); ++it) {
+    std::map<uint32, commands::KeyEvent::ModifierKey>::const_iterator item =
+        data.find(*it);
+    if (item != data.end()) {
+      modifier_keys_set->insert(item->second);
+    }
+  }
+}
+
+bool IsModifierToBeSentOnKeyUp(const 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) == commands::KeyEvent::CAPS) {
+    return false;
+  }
+
+  return true;
+}
+}  // namespace
+
+KeyEventHandler::KeyEventHandler() : key_translator_(new KeyTranslator) {
+  Clear();
+}
+
+bool KeyEventHandler::GetKeyEvent(
+    FcitxKeySym keyval, uint32 keycode, uint32 modifiers,
+    config::Config::PreeditMethod preedit_method,
+    bool layout_is_jp, bool is_key_up, 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,
+                                       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.
+  //    <Event from ibus> <Event to server>
+  //     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.
+  //    <Event from ibus> <Event to server>
+  //     Ctrl down       | None
+  //     "a" down        | Ctrl+a
+  //     "a" up          | None
+  //     Ctrl up         | None
+  //
+  // E.g.) Modifier key is sent on key up.
+  //    <Event from ibus> <Event to server>
+  //     Shift down      | None
+  //     Shift up        | Shift
+  //
+  // E.g.) Multiple modifier keys are sent on the last key up.
+  //    <Event from ibus> <Event to server>
+  //     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.)
+  //    <Event from ibus> <Event to server>
+  //     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<commands::KeyEvent::ModifierKey>::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 ibus
+}  // namespace mozc
diff --git a/src/unix/fcitx/fcitx_key_event_handler.h b/src/unix/fcitx/fcitx_key_event_handler.h
new file mode 100644
index 00000000..7b759a18
--- /dev/null
+++ b/src/unix/fcitx/fcitx_key_event_handler.h
@@ -0,0 +1,79 @@
+// Copyright 2010-2012, Google Inc.
+// Copyright 2012~2013, Weng Xuetian <wengxt@gmail.com>
+// 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_KEY_EVENT_HANDLER_H_
+#define MOZC_UNIX_FCITX_KEY_EVENT_HANDLER_H_
+
+#include <set>
+#include <memory>
+
+#include "base/port.h"
+#include "protocol/config.pb.h"
+#include "protocol/commands.pb.h"
+#include "unix/fcitx/fcitx_key_translator.h"
+
+namespace mozc {
+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(FcitxKeySym keyval, uint32 keycode, uint32 modifiers,
+                   config::Config::PreeditMethod preedit_method,
+                   bool layout_is_jp, bool is_key_up, 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,
+                        commands::KeyEvent *key_event);
+
+  std::unique_ptr<KeyTranslator> 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<uint32> currently_pressed_modifiers_;
+  // Pending modifier keys.
+  std::set<commands::KeyEvent::ModifierKey> modifiers_to_be_sent_;
+
+  DISALLOW_COPY_AND_ASSIGN(KeyEventHandler);
+};
+
+}  // namespace fcitx
+}  // namespace mozc
+
+#endif  // MOZC_UNIX_FCITX_KEY_EVENT_HANDLER_H_
diff --git a/src/unix/fcitx/fcitx_key_translator.cc b/src/unix/fcitx/fcitx_key_translator.cc
new file mode 100644
index 00000000..44347abf
--- /dev/null
+++ b/src/unix/fcitx/fcitx_key_translator.cc
@@ -0,0 +1,521 @@
+// Copyright 2010-2012, Google Inc.
+// Copyright 2012~2013, Weng Xuetian <wengxt@gmail.com>
+// 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/fcitx/fcitx_key_translator.h"
+
+#include "base/logging.h"
+
+namespace {
+
+const struct SpecialKeyMap {
+  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 ModifierKeyMap {
+  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},
+  {FcitxKeyState_CapsLock, mozc::commands::KeyEvent::CAPS},
+};
+
+const struct ModifierMaskMap {
+  uint32 from;
+  mozc::commands::KeyEvent::ModifierKey to;
+} modifier_mask_map[] = {
+  {FcitxKeyState_Shift, mozc::commands::KeyEvent::SHIFT},
+  {FcitxKeyState_Ctrl, mozc::commands::KeyEvent::CTRL},
+  {FcitxKeyState_Alt, mozc::commands::KeyEvent::ALT},
+};
+
+// TODO(team): Add kana_map_dv to support Dvoraklayout.
+const struct KanaMap {
+  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
+
+namespace mozc {
+namespace fcitx {
+
+KeyTranslator::KeyTranslator() {
+  Init();
+}
+
+KeyTranslator::~KeyTranslator() {
+}
+
+// TODO(nona): Fix 'Shift-0' behavior b/4338394
+bool KeyTranslator::Translate(FcitxKeySym keyval,
+                              uint32 keycode,
+                              uint32 modifiers,
+                              config::Config::PreeditMethod method,
+                              bool layout_is_jp,
+                              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 & FcitxKeyState_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 &= ~FcitxKeyState_Shift;
+    keyval = FcitxKey_Katakana;
+  }
+  string kana_key_string;
+  if ((method == 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 (FcitxKeyState_CapsLock & modifiers) {
+      out_event->add_modifier_keys(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 == 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(uint32 keyval,
+                                  uint32 keycode,
+                                  uint32 modifiers) const {
+  return modifier_key_map_.find(keyval) != modifier_key_map_.end();
+}
+
+bool KeyTranslator::IsSpecialKey(uint32 keyval,
+                                 uint32 keycode,
+                                 uint32 modifiers) const {
+  return special_key_map_.find(keyval) != special_key_map_.end();
+}
+
+bool KeyTranslator::IsHiraganaKatakanaKeyWithShift(uint32 keyval,
+                                                   uint32 keycode,
+                                                   uint32 modifiers) {
+  return ((modifiers & FcitxKeyState_Shift) && (keyval == FcitxKey_Hiragana_Katakana));
+}
+
+bool KeyTranslator::IsKanaAvailable(uint32 keyval,
+                                    uint32 keycode,
+                                    uint32 modifiers,
+                                    bool layout_is_jp,
+                                    string *out) const {
+  if ((modifiers & FcitxKeyState_Ctrl) || (modifiers & FcitxKeyState_Alt)) {
+    return false;
+  }
+  const KanaMap &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 & FcitxKeyState_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(uint32 keyval, uint32 keycode, uint32 modifiers) {
+  if ((modifiers & FcitxKeyState_Ctrl) || (modifiers & FcitxKeyState_Alt)) {
+    return false;
+  }
+  return IsAscii(keyval, keycode, modifiers);
+}
+
+bool KeyTranslator::IsAscii(uint32 keyval, uint32 keycode, uint32 modifiers) {
+  return (keyval > FcitxKey_space &&
+          // Note: Space key (0x20) is a special key in Mozc.
+          keyval <= FcitxKey_asciitilde);  // 0x7e.
+}
+
+}  // namespace ibus
+}  // namespace mozc
diff --git a/src/unix/fcitx/fcitx_key_translator.h b/src/unix/fcitx/fcitx_key_translator.h
new file mode 100644
index 00000000..b473672f
--- /dev/null
+++ b/src/unix/fcitx/fcitx_key_translator.h
@@ -0,0 +1,121 @@
+// Copyright 2010-2012, Google Inc.
+// Copyright 2012~2013, Weng Xuetian <wengxt@gmail.com>
+// 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_KEY_TRANSLATOR_H_
+#define MOZC_UNIX_FCITX_FCITX_KEY_TRANSLATOR_H_
+
+#include <map>
+#include <set>
+#include <string>
+
+#include <fcitx-config/hotkey.h>
+
+#include "base/port.h"
+#include "protocol/commands.pb.h"
+#include <fcitx/ime.h>
+
+namespace mozc {
+
+namespace fcitx {
+
+// This class is responsible for converting scim::KeyEvent object (defined in
+// /usr/include/scim-1.0/scim_event.h) to IPC input for mozc_server.
+class KeyTranslator {
+public:
+  KeyTranslator();
+  virtual ~KeyTranslator();
+
+  // Converts scim_key into Mozc key code and stores them on out_translated.
+  // scim_key must satisfy the following precondition: CanConvert(scim_key)
+  bool Translate(FcitxKeySym keyval,
+                 uint32 keycode,
+                 uint32 modifiers,
+                 mozc::config::Config::PreeditMethod method,
+                 bool layout_is_jp,
+                 mozc::commands::KeyEvent *out_event) const;
+
+private:
+  typedef std::map<uint32, commands::KeyEvent::SpecialKey> SpecialKeyMap;
+  typedef std::map<uint32, commands::KeyEvent::ModifierKey> ModifierKeyMap;
+  typedef std::map<uint32, std::pair<string, string> > KanaMap;
+
+  // Returns true iff key is modifier key such as SHIFT, ALT, or CAPSLOCK.
+  bool IsModifierKey(uint32 keyval,
+                     uint32 keycode,
+                     uint32 modifiers) const;
+
+  // Returns true iff key is special key such as ENTER, ESC, or PAGE_UP.
+  bool IsSpecialKey(uint32 keyval,
+                    uint32 keycode,
+                    uint32 modifiers) const;
+
+  // Returns true iff |keyval| is a key with a kana assigned.
+  bool IsKanaAvailable(uint32 keyval,
+                       uint32 keycode,
+                       uint32 modifiers,
+                       bool layout_is_jp,
+                       string *out) const;
+
+  // Returns true iff key is ASCII such as '0', 'A', or '!'.
+  static bool IsAscii(uint32 keyval,
+                      uint32 keycode,
+                      uint32 modifiers);
+
+  // Returns true iff key is printable.
+  static bool IsPrintable(uint32 keyval, uint32 keycode, uint32 modifiers);
+
+  // Returns true iff key is HiraganaKatakana with shift modifier.
+  static bool IsHiraganaKatakanaKeyWithShift(uint32 keyval,
+                                             uint32 keycode,
+                                             uint32 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
+
+}  // namespace mozc
+
+#endif  // MOZC_UNIX_FCITX_FCITX_KEY_TRANSLATOR_H_
diff --git a/src/unix/fcitx/fcitx_mozc.cc b/src/unix/fcitx/fcitx_mozc.cc
new file mode 100644
index 00000000..0c8ce651
--- /dev/null
+++ b/src/unix/fcitx/fcitx_mozc.cc
@@ -0,0 +1,557 @@
+// Copyright 2012~2013, Weng Xuetian <wengxt@gmail.com>
+// 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/fcitx/fcitx_mozc.h"
+
+#include <string>
+#include <fcitx/candidate.h>
+#include <fcitx/module.h>
+#include <fcitx-config/xdg.h>
+
+#include "base/const.h"
+#include "base/logging.h"
+#include "base/process.h"
+#include "base/util.h"
+#include "base/file_util.h"
+#include "base/system_util.h"
+#include "unix/fcitx/mozc_connection.h"
+#include "unix/fcitx/mozc_response_parser.h"
+#include <fcitx/context.h>
+
+#define N_(x) (x)
+
+namespace
+{
+
+static const std::string empty_string;
+
+const struct CompositionMode
+{
+    const char *icon;
+    const char *label;
+    const char *description;
+    mozc::commands::CompositionMode mode;
+} kPropCompositionModes[] =
+{
+    {
+        "mozc-direct.png",
+        "A",
+        N_("Direct"),
+        mozc::commands::DIRECT,
+    }, {
+        "mozc-hiragana.png",
+        "\xe3\x81\x82",  // Hiragana letter A in UTF-8.
+        N_("Hiragana"),
+        mozc::commands::HIRAGANA,
+    }, {
+        "mozc-katakana_full.png",
+        "\xe3\x82\xa2",  // Katakana letter A.
+        N_("Full Katakana"),
+        mozc::commands::FULL_KATAKANA,
+    }, {
+        "mozc-alpha_half.png",
+        "A",
+        N_("Half ASCII"),
+        mozc::commands::HALF_ASCII,
+    }, {
+        "mozc-alpha_full.png",
+        "\xef\xbc\xa1",  // Full width ASCII letter A.
+        N_("Full ASCII"),
+        mozc::commands::FULL_ASCII,
+    }, {
+        "mozc-katakana_half.png",
+        "\xef\xbd\xb1",  // Half width Katakana letter A.
+        N_("Half Katakana"),
+        mozc::commands::HALF_KATAKANA,
+    },
+};
+const size_t kNumCompositionModes = arraysize ( kPropCompositionModes );
+
+// This array must correspond with the CompositionMode enum in the
+// mozc/session/command.proto file.
+static_assert (
+    mozc::commands::NUM_OF_COMPOSITIONS == arraysize ( kPropCompositionModes ),
+    "number of modes must match" );
+
+}  // namespace
+
+INPUT_RETURN_VALUE FcitxMozcGetCandidateWord(void* arg, FcitxCandidateWord* candWord)
+{
+    mozc::fcitx::FcitxMozc* fcitx_mozc = (mozc::fcitx::FcitxMozc*) arg;
+    fcitx_mozc->select_candidate(candWord);
+
+    return IRV_DISPLAY_CANDWORDS;
+}
+
+
+namespace mozc
+{
+
+namespace fcitx
+{
+
+// For unittests.
+FcitxMozc::FcitxMozc ( FcitxInstance* inst,
+                       MozcConnectionInterface *connection,
+                       MozcResponseParser *parser ) :
+        instance(inst),
+        input(FcitxInstanceGetInputState(inst)),
+        connection_ ( connection ),
+        parser_ ( parser ),
+        composition_mode_ ( mozc::commands::HIRAGANA )
+{
+    // mozc::Logging::SetVerboseLevel(1);
+    VLOG ( 1 ) << "FcitxMozc created.";
+    const bool is_vertical = true;
+    parser_->set_use_annotation ( is_vertical );
+    InitializeBar();
+    InitializeMenu();
+    SetCompositionMode( mozc::commands::HIRAGANA );
+}
+
+FcitxMozc::~FcitxMozc()
+{
+    VLOG ( 1 ) << "FcitxMozc destroyed.";
+}
+
+// This function is called from SCIM framework when users press or release a
+// key.
+bool FcitxMozc::process_key_event (FcitxKeySym sym, uint32 keycode, uint32 state, bool layout_is_jp, bool is_key_up)
+{
+    string error;
+    mozc::commands::Output raw_response;
+    if ( !connection_->TrySendKeyEvent (
+                GetInstance(), 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 FcitxMozc::select_candidate ( FcitxCandidateWord* candWord )
+{
+    int32 *id = (int32*) candWord->priv;
+
+    if ( *id == kBadCandidateId )
+    {
+        LOG ( ERROR ) << "The clicked candidate doesn't have unique ID.";
+        return;
+    }
+    VLOG ( 1 ) << "select_candidate, id=" << *id;
+
+    string error;
+    mozc::commands::Output raw_response;
+    if ( !connection_->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 FcitxMozc::resetim()
+{
+    VLOG ( 1 ) << "resetim";
+    string error;
+    mozc::commands::Output raw_response;
+    if ( connection_->TrySendCommand (
+                mozc::commands::SessionCommand::REVERT, &raw_response, &error ) )
+    {
+        parser_->ParseResponse ( raw_response, this );
+    }
+    ClearAll();  // just in case.
+    DrawAll();
+
+}
+
+void FcitxMozc::reset()
+{
+    FcitxIM* im = FcitxInstanceGetCurrentIM(instance);
+    if (!im || strcmp(im->uniqueName, "mozc") != 0) {
+        FcitxUISetStatusVisable(instance, "mozc-tool", false);
+        FcitxUISetStatusVisable(instance, "mozc-composition-mode", false);
+    }
+    else {
+        FcitxUISetStatusVisable(instance, "mozc-tool", true);
+        FcitxUISetStatusVisable(instance, "mozc-composition-mode", true);
+        connection_->UpdatePreeditMethod();
+    }
+}
+
+bool FcitxMozc::paging(bool prev)
+{
+    VLOG ( 1 ) << "paging";
+    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 ( connection_->TrySendCommand (
+        command, &raw_response, &error ) )
+    {
+        parser_->ParseResponse ( raw_response, this );
+        return true;
+    }
+    return false;
+}
+
+// This function is called from SCIM framework when the ic gets focus.
+void FcitxMozc::init()
+{
+    VLOG ( 1 ) << "init";
+    boolean flag = true;
+    FcitxInstanceSetContext(instance, CONTEXT_DISABLE_AUTOENG, &flag);
+    FcitxInstanceSetContext(instance, CONTEXT_DISABLE_FULLWIDTH, &flag);
+    FcitxInstanceSetContext(instance, CONTEXT_DISABLE_QUICKPHRASE, &flag);
+    FcitxInstanceSetContext(instance, CONTEXT_IM_KEYBOARD_LAYOUT, "jp");
+    FcitxInstanceSetContext(instance, "CONTEXT_DISABLE_AUTO_FIRST_CANDIDATE_HIGHTLIGHT", &flag);
+
+    connection_->UpdatePreeditMethod();
+    DrawAll();
+}
+
+// This function is called when the ic loses focus.
+void FcitxMozc::focus_out()
+{
+    VLOG ( 1 ) << "focus_out";
+    string error;
+    mozc::commands::Output raw_response;
+    if ( connection_->TrySendCommand (
+                mozc::commands::SessionCommand::REVERT, &raw_response, &error ) )
+    {
+        parser_->ParseResponse ( raw_response, this );
+    }
+    ClearAll();  // just in case.
+    DrawAll();
+    // TODO(yusukes): Call client::SyncData() like ibus-mozc.
+}
+
+
+bool FcitxMozc::ParseResponse ( const mozc::commands::Output &raw_response )
+{
+    ClearAll();
+    const bool consumed = parser_->ParseResponse ( raw_response, this );
+    if ( !consumed )
+    {
+        VLOG ( 1 ) << "The input was not consumed by Mozc.";
+    }
+    OpenUrl();
+    DrawAll();
+    return consumed;
+}
+
+void FcitxMozc::SetResultString ( const std::string &result_string )
+{
+    FcitxInstanceCommitString(instance, FcitxInstanceGetCurrentIC(instance), result_string.c_str());
+}
+
+void FcitxMozc::SetPreeditInfo ( const PreeditInfo *preedit_info )
+{
+    preedit_info_.reset ( preedit_info );
+}
+
+void FcitxMozc::SetAuxString ( const std::string &str )
+{
+    aux_ = str;
+}
+
+void FcitxMozc::SetCompositionMode ( mozc::commands::CompositionMode mode )
+{
+    composition_mode_ = mode;
+    DCHECK(composition_mode_ < kNumCompositionModes);
+    if (composition_mode_ < kNumCompositionModes) {
+        FcitxUISetStatusString(instance,
+                               "mozc-composition-mode",
+                               _(kPropCompositionModes[composition_mode_].label),
+                               _(kPropCompositionModes[composition_mode_].description));
+    }
+}
+
+void FcitxMozc::SendCompositionMode(mozc::commands::CompositionMode mode)
+{
+    // Send the SWITCH_INPUT_MODE command.
+    string error;
+    mozc::commands::Output raw_response;
+    if (connection_->TrySendCompositionMode(
+            kPropCompositionModes[mode].mode, &raw_response, &error)) {
+        parser_->ParseResponse(raw_response, this);
+    }
+}
+
+
+void FcitxMozc::SetUrl ( const string &url )
+{
+    url_ = url;
+}
+
+void FcitxMozc::ClearAll()
+{
+    SetPreeditInfo ( NULL );
+    SetAuxString ( "" );
+    FcitxCandidateWordReset(FcitxInputStateGetCandidateList(input));
+    url_.clear();
+}
+
+void FcitxMozc::DrawPreeditInfo()
+{
+    FcitxMessages* preedit = FcitxInputStateGetPreedit(input);
+    FcitxMessages* clientpreedit = FcitxInputStateGetClientPreedit(input);
+    FcitxMessagesSetMessageCount(preedit, 0);
+    FcitxMessagesSetMessageCount(clientpreedit, 0);
+    if ( preedit_info_.get() )
+    {
+        VLOG ( 1 ) << "DrawPreeditInfo: cursor=" << preedit_info_->cursor_pos;
+
+        FcitxInputContext* ic = FcitxInstanceGetCurrentIC(instance);
+        boolean supportPreedit = FcitxInstanceICSupportPreedit(instance, ic);
+
+        if (!supportPreedit)
+            FcitxInputStateSetShowCursor(input, true);
+
+        for (int i = 0; i < preedit_info_->preedit.size(); i ++) {
+            if (!supportPreedit)
+                FcitxMessagesAddMessageAtLast(preedit, preedit_info_->preedit[i].type, "%s", preedit_info_->preedit[i].str.c_str());
+            FcitxMessagesAddMessageAtLast(clientpreedit, preedit_info_->preedit[i].type, "%s", preedit_info_->preedit[i].str.c_str());
+        }
+        if (!supportPreedit)
+            FcitxInputStateSetCursorPos(input, preedit_info_->cursor_pos);
+        FcitxInputStateSetClientCursorPos(input, preedit_info_->cursor_pos);
+    }
+    else {
+        FcitxInputStateSetShowCursor(input, false);
+    }
+    if ( !aux_.empty() ) {
+        FcitxMessagesAddMessageAtLast(preedit, MSG_TIPS, "%s[%s]", preedit_info_.get() ? " " : "", aux_.c_str());
+    }
+}
+
+void FcitxMozc::DrawAux()
+{
+    FcitxMessages* auxUp = FcitxInputStateGetAuxUp(input);
+    FcitxMessages* auxDown = FcitxInputStateGetAuxDown(input);
+    FcitxMessagesSetMessageCount(auxUp, 0);
+    FcitxMessagesSetMessageCount(auxDown, 0);
+}
+
+void FcitxMozc::DrawAll()
+{
+    DrawPreeditInfo();
+    DrawAux();
+}
+
+void FcitxMozc::OpenUrl()
+{
+    if ( url_.empty() )
+    {
+        return;
+    }
+    mozc::Process::OpenBrowser ( url_ );
+    url_.clear();
+}
+
+static const char* GetCompositionIconName(void* arg)
+{
+    FcitxMozc* mozc = (FcitxMozc*) arg;
+    return mozc->GetCurrentCompositionModeIcon().c_str();
+}
+
+
+static const char* GetMozcToolIcon(void* arg)
+{
+    FcitxMozc* mozc = (FcitxMozc*) arg;
+    return mozc->GetIconFile("mozc-tool.png").c_str();
+}
+
+void FcitxMozc::InitializeBar()
+{
+    VLOG ( 1 ) << "Registering properties";
+
+    FcitxUIRegisterComplexStatus(instance, this,
+        "mozc-composition-mode",
+        _("Composition Mode"),
+        _("Composition Mode"),
+        NULL,
+        GetCompositionIconName
+    );
+
+    if ( mozc::FileUtil::FileExists ( mozc::FileUtil::JoinPath (
+                                      mozc::SystemUtil::GetServerDirectory(), mozc::kMozcTool ) ) )
+    {
+        FcitxUIRegisterComplexStatus(instance, this,
+            "mozc-tool",
+            _("Tool"),
+            _("Tool"),
+            NULL,
+            GetMozcToolIcon
+        );
+    }
+    FcitxUISetStatusVisable(instance, "mozc-tool", false);
+    FcitxUISetStatusVisable(instance, "mozc-composition-mode", false);
+}
+
+boolean CompositionMenuAction(struct _FcitxUIMenu *menu, int index)
+{
+    FcitxMozc* mozc = (FcitxMozc*) menu->priv;
+    mozc->SendCompositionMode((mozc::commands::CompositionMode) index);
+    return true;
+}
+
+void UpdateCompositionMenu(struct _FcitxUIMenu *menu)
+{
+    FcitxMozc* mozc = (FcitxMozc*) menu->priv;
+    menu->mark = mozc->GetCompositionMode();
+}
+
+boolean ToolMenuAction(struct _FcitxUIMenu *menu, int index)
+{
+    string args;
+    switch(index) {
+        case 0:
+            args = "--mode=config_dialog";
+            break;
+        case 1:
+            args = "--mode=dictionary_tool";
+            break;
+        case 2:
+            args = "--mode=hand_writing";
+            break;
+        case 3:
+            args = "--mode=character_palette";
+            break;
+        case 4:
+            args = "--mode=word_register_dialog";
+            break;
+        case 5:
+            args = "--mode=about_dialog";
+            break;
+    }
+    mozc::Process::SpawnMozcProcess("mozc_tool", args);
+    return true;
+}
+
+void UpdateToolMenu(struct _FcitxUIMenu *menu)
+{
+    return;
+}
+
+void FcitxMozc::InitializeMenu()
+{
+    FcitxMenuInit(&this->compositionMenu);
+    compositionMenu.name = strdup(_("Composition Mode"));
+    compositionMenu.candStatusBind = strdup("mozc-composition-mode");
+    compositionMenu.UpdateMenu = UpdateCompositionMenu;
+    compositionMenu.MenuAction = CompositionMenuAction;
+    compositionMenu.priv = this;
+    compositionMenu.isSubMenu = false;
+    int i;
+    for (i = 0; i < kNumCompositionModes; i ++)
+        FcitxMenuAddMenuItem(&compositionMenu, _(kPropCompositionModes[i].description), MENUTYPE_SIMPLE, NULL);
+
+    FcitxUIRegisterMenu(instance, &compositionMenu);
+
+    FcitxMenuInit(&this->toolMenu);
+    toolMenu.name = strdup(_("Mozc Tool"));
+    toolMenu.candStatusBind = strdup("mozc-tool");
+    toolMenu.UpdateMenu = UpdateToolMenu;
+    toolMenu.MenuAction = ToolMenuAction;
+    toolMenu.priv = this;
+    toolMenu.isSubMenu = false;
+    FcitxMenuAddMenuItem(&toolMenu, _("Configuration Tool"), MENUTYPE_SIMPLE, NULL);
+    FcitxMenuAddMenuItem(&toolMenu, _("Dictionary Tool"), MENUTYPE_SIMPLE, NULL);
+    FcitxMenuAddMenuItem(&toolMenu, _("Hand Writing"), MENUTYPE_SIMPLE, NULL);
+    FcitxMenuAddMenuItem(&toolMenu, _("Character Palette"), MENUTYPE_SIMPLE, NULL);
+    FcitxMenuAddMenuItem(&toolMenu, _("Add Word"), MENUTYPE_SIMPLE, NULL);
+    FcitxMenuAddMenuItem(&toolMenu, _("About Mozc"), MENUTYPE_SIMPLE, NULL);
+    FcitxUIRegisterMenu(instance, &toolMenu);
+}
+
+bool FcitxMozc::SendCommand(const mozc::commands::SessionCommand& session_command, commands::Output* new_output)
+{
+    string error;
+    return connection_->TrySendRawCommand(session_command, new_output, &error);
+}
+
+
+FcitxInputState* FcitxMozc::GetInputState()
+{
+    return input;
+}
+
+const std::string& FcitxMozc::GetIconFile(const std::string key)
+{
+    if (iconMap.count(key)) {
+        return iconMap[key];
+    }
+
+    char* retFile;
+    FILE* fp = FcitxXDGGetFileWithPrefix("mozc/icon", key.c_str(), "r", &retFile);
+    if (fp)
+        fclose(fp);
+    if (retFile) {
+        iconMap[key] = std::string(retFile);
+        free(retFile);
+    }
+    else {
+        iconMap[key] = "";
+    }
+    return iconMap[key];
+}
+
+
+const std::string& FcitxMozc::GetCurrentCompositionModeIcon() {
+    DCHECK(composition_mode_ < kNumCompositionModes);
+    if (composition_mode_ < kNumCompositionModes) {
+        return GetIconFile(kPropCompositionModes[composition_mode_].icon);
+    }
+    return empty_string;
+}
+
+void FcitxMozc::SetUsage(const string& title_, const string& description_)
+{
+    title = title_;
+    description = description_;
+}
+
+std::pair< string, string > FcitxMozc::GetUsage()
+{
+    return make_pair(title, description);
+}
+
+}  // namespace fcitx
+
+}  // namespace mozc_unix_scim
diff --git a/src/unix/fcitx/fcitx_mozc.h b/src/unix/fcitx/fcitx_mozc.h
new file mode 100644
index 00000000..0610d6e2
--- /dev/null
+++ b/src/unix/fcitx/fcitx_mozc.h
@@ -0,0 +1,176 @@
+// Copyright 2012~2013, Weng Xuetian <wengxt@gmail.com>
+// 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 <memory>
+
+#include <fcitx/instance.h>
+#include <fcitx/candidate.h>
+#include <fcitx-config/hotkey.h>
+#include <libintl.h>
+
+#include "base/port.h"
+#include "base/run_level.h"
+#include "protocol/commands.pb.h"
+#include "client/client_interface.h"
+#include "mozc_connection.h"
+
+#define _(x) dgettext("fcitx-mozc", (x))
+
+INPUT_RETURN_VALUE FcitxMozcGetCandidateWord(void* arg, FcitxCandidateWord* candWord);;
+
+namespace mozc
+{
+
+namespace fcitx
+{
+const int32 kBadCandidateId = -12345;
+class IMEngineFactory;
+class MozcConnectionInterface;
+class MozcResponseParser;
+class KeyTranslator;
+
+struct PreeditItem {
+        std::string str;
+        FcitxMessageType type;
+};
+
+// Preedit string and its attributes.
+struct PreeditInfo
+{
+    uint32 cursor_pos;
+    
+    std::vector<PreeditItem> preedit;
+};
+
+class FcitxMozc
+{
+public:
+    // This constructor is used by unittests.
+    FcitxMozc ( FcitxInstance* instance,
+                MozcConnectionInterface *connection,
+                MozcResponseParser *parser );
+    virtual ~FcitxMozc();
+
+    bool process_key_event (FcitxKeySym sym, uint32 keycode, uint32 state, bool layout_is_jp, bool is_key_up);
+    void select_candidate ( FcitxCandidateWord* candWord );
+    void resetim();
+    void reset();
+    void init();
+    void focus_out();
+    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 ( const PreeditInfo *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 string &url );
+
+    const std::string& GetIconFile(const std::string key);
+    
+    const std::string& GetCurrentCompositionModeIcon();
+    
+    mozc::commands::CompositionMode GetCompositionMode() { return composition_mode_; }
+    
+    FcitxInstance* GetInstance() { return instance; }
+    
+    FcitxInputState* GetInputState();
+
+    mozc::client::ClientInterface* GetClient() { return connection_->GetClient(); }
+
+    bool SendCommand(const mozc::commands::SessionCommand& session_command, mozc::commands::Output* new_output);
+
+    void SetUsage(const std::string& title, const std::string& description);
+
+    std::pair<std::string, std::string> GetUsage();
+
+    void DrawAll();
+
+private:
+    friend class FcitxMozcTest;
+
+    // Adds Mozc-specific icons to FCITX toolbar.
+    void InitializeBar();
+    
+    void InitializeMenu();
+
+    // 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();
+
+    FcitxInstance* instance;
+    FcitxInputState* input;
+    const std::unique_ptr<MozcConnectionInterface> connection_;
+    const std::unique_ptr<MozcResponseParser> parser_;
+
+    // Strings and a window currently displayed on FCITX UI.
+    std::unique_ptr<const PreeditInfo> preedit_info_;
+    std::string aux_;  // error tooltip, or candidate window title.
+    string url_;  // URL to be opened by a browser.
+    mozc::commands::CompositionMode composition_mode_;
+    
+    std::map<std::string, std::string> iconMap;
+    
+    FcitxUIMenu compositionMenu;
+    FcitxUIMenu toolMenu;
+    string description;
+    string title;
+
+    DISALLOW_COPY_AND_ASSIGN ( FcitxMozc );
+};
+
+}  // namespace fcitx
+
+}  // namespace mozc
+
+#endif  // MOZC_UNIX_FCITX_FCITX_MOZC_H_
+
diff --git a/src/unix/fcitx/gen_fcitx_mozc_i18n.sh b/src/unix/fcitx/gen_fcitx_mozc_i18n.sh
new file mode 100755
index 00000000..97ff4a49
--- /dev/null
+++ b/src/unix/fcitx/gen_fcitx_mozc_i18n.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+objdir="$1"
+
+mkdir -p "$1"
+
+for pofile in po/*.po
+do
+    msgfmt "$pofile" -o "$1/`basename ${pofile} .po`.mo"
+done
diff --git a/src/unix/fcitx/mozc.conf b/src/unix/fcitx/mozc.conf
new file mode 100644
index 00000000..ad192303
--- /dev/null
+++ b/src/unix/fcitx/mozc.conf
@@ -0,0 +1,7 @@
+[InputMethod]
+UniqueName=mozc
+Name=Mozc
+IconName=/usr/share/fcitx/mozc/icon/mozc.png
+Priority=1
+LangCode=ja
+Parent=fcitx-mozc
diff --git a/src/unix/fcitx/mozc_connection.cc b/src/unix/fcitx/mozc_connection.cc
new file mode 100755
index 00000000..068dcf46
--- /dev/null
+++ b/src/unix/fcitx/mozc_connection.cc
@@ -0,0 +1,209 @@
+// Copyright 2010-2012, Google Inc.
+// Copyright 2012~2013, Weng Xuetian <wengxt@gmail.com>
+// 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/fcitx/mozc_connection.h"
+
+#include <string>
+
+#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"
+#include "unix/fcitx/fcitx_key_event_handler.h"
+#include "unix/fcitx/surrounding_text_util.h"
+#include "fcitx_mozc.h"
+
+namespace mozc {
+namespace fcitx {
+
+MozcConnectionInterface::~MozcConnectionInterface() {
+}
+
+mozc::client::ClientInterface* CreateAndConfigureClient() {
+  mozc::client::ClientInterface *client = client::ClientFactory::NewClient();
+  // Currently client capability is fixed.
+  commands::Capability capability;
+  capability.set_text_deletion(commands::Capability::DELETE_PRECEDING_TEXT);
+  client->set_client_capability(capability);
+  return client;
+}
+
+MozcConnection::MozcConnection(
+    mozc::client::ServerLauncherInterface *server_launcher,
+    mozc::IPCClientFactoryInterface *client_factory)
+    : handler_(new KeyEventHandler),
+      preedit_method_(mozc::config::Config::ROMAN),
+      client_factory_(client_factory) {
+  VLOG(1) << "MozcConnection is created";
+  mozc::client::ClientInterface *client = CreateAndConfigureClient();
+  client->SetServerLauncher(server_launcher);
+  client->SetIPCClientFactory(client_factory_.get());
+  client_.reset(client);
+
+  if (client_->EnsureConnection()) {
+    UpdatePreeditMethod();
+  }
+  VLOG(1)
+      << "Current preedit method is "
+      << (preedit_method_ == mozc::config::Config::ROMAN ? "Roman" : "Kana");
+}
+
+MozcConnection::~MozcConnection() {
+  client_->SyncData();
+  VLOG(1) << "MozcConnection is destroyed";
+}
+
+void MozcConnection::UpdatePreeditMethod() {
+  mozc::config::Config config;
+  if (!client_->GetConfig(&config)) {
+    LOG(ERROR) << "GetConfig failed";
+    return;
+  }
+  preedit_method_ = config.has_preedit_method() ?
+      config.preedit_method() : config::Config::ROMAN;
+}
+
+bool MozcConnection::TrySendKeyEvent(
+    FcitxInstance* instance,
+    FcitxKeySym sym, uint32 keycode, uint32 state,
+    mozc::commands::CompositionMode composition_mode,
+    bool layout_is_jp,
+    bool is_key_up,
+    mozc::commands::Output *out,
+    string *out_error) const {
+  DCHECK(out);
+  DCHECK(out_error);
+
+  // Call EnsureConnection just in case MozcConnection::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.
+  }
+
+  commands::Context context;
+  SurroundingTextInfo surrounding_text_info;
+  if (GetSurroundingText(instance,
+                         &surrounding_text_info)) {
+    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 MozcConnection::TrySendClick(int32 unique_id,
+                                  mozc::commands::Output *out,
+                                  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 MozcConnection::TrySendCompositionMode(
+    mozc::commands::CompositionMode mode,
+    mozc::commands::Output *out,
+    string *out_error) const {
+  DCHECK(out);
+  DCHECK(out_error);
+
+  mozc::commands::SessionCommand command;
+  command.set_type(mozc::commands::SessionCommand::SWITCH_INPUT_MODE);
+  command.set_composition_mode(mode);
+  return TrySendRawCommand(command, out, out_error);
+}
+
+bool MozcConnection::TrySendCommand(
+    mozc::commands::SessionCommand::CommandType type,
+    mozc::commands::Output *out,
+    string *out_error) const {
+  DCHECK(out);
+  DCHECK(out_error);
+
+  mozc::commands::SessionCommand command;
+  command.set_type(type);
+  return TrySendRawCommand(command, out, out_error);
+}
+
+
+
+bool MozcConnection::TrySendRawCommand(
+    const mozc::commands::SessionCommand& command,
+    mozc::commands::Output *out,
+    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;
+}
+
+mozc::client::ClientInterface* MozcConnection::GetClient()
+{
+    return client_.get();
+}
+
+MozcConnection *MozcConnection::CreateMozcConnection() {
+  mozc::client::ServerLauncher *server_launcher
+      = new mozc::client::ServerLauncher;
+
+  return new MozcConnection(server_launcher, new mozc::IPCClientFactory);
+}
+
+}  // namespace fcitx
+
+}  // namespace mozc
diff --git a/src/unix/fcitx/mozc_connection.h b/src/unix/fcitx/mozc_connection.h
new file mode 100755
index 00000000..0181bf73
--- /dev/null
+++ b/src/unix/fcitx/mozc_connection.h
@@ -0,0 +1,152 @@
+// Copyright 2010-2012, Google Inc.
+// Copyright 2012~2013, Weng Xuetian <wengxt@gmail.com>
+// 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_CONNECTION_H_
+#define MOZC_UNIX_FCITX_MOZC_CONNECTION_H_
+
+#include <string>
+#include <memory>
+
+#include <fcitx-config/hotkey.h>
+#include <fcitx/instance.h>
+
+#include "base/port.h"
+#include "protocol/commands.pb.h"
+#include "unix/fcitx/fcitx_key_event_handler.h"
+
+namespace mozc {
+
+class IPCClientInterface;
+class IPCClientFactoryInterface;
+
+namespace client {
+class ClientInterface;
+class ServerLauncherInterface;
+}  // namespace client
+
+}  // namespace mozc
+
+namespace mozc {
+    
+namespace fcitx {
+
+class KeyTranslator;
+
+// This class is for mozc_response_parser_test.cc.
+class MozcConnectionInterface {
+ public:
+  virtual ~MozcConnectionInterface();
+
+  virtual bool TrySendKeyEvent(FcitxInstance* instance,
+                               FcitxKeySym sym, uint32 keycode, uint32 state,
+                               mozc::commands::CompositionMode composition_mode,
+                               bool layout_is_jp,
+                               bool is_key_up,
+                               mozc::commands::Output *out,
+                               string *out_error) const = 0;
+  virtual bool TrySendClick(int32 unique_id,
+                            mozc::commands::Output *out,
+                            string *out_error) const = 0;
+  virtual bool TrySendCompositionMode(mozc::commands::CompositionMode mode,
+                                      mozc::commands::Output *out,
+                                      string *out_error) const = 0;
+  virtual bool TrySendCommand(mozc::commands::SessionCommand::CommandType type,
+                              mozc::commands::Output *out,
+                              string *out_error) const = 0;
+
+  virtual bool TrySendRawCommand(const mozc::commands::SessionCommand& command,
+                                 mozc::commands::Output *out,
+                                 string *out_error) const = 0;
+  virtual mozc::client::ClientInterface* GetClient() = 0;
+  virtual void UpdatePreeditMethod() = 0;
+};
+
+class MozcConnection : public MozcConnectionInterface {
+ public:
+  static const int kNoSession;
+
+  static MozcConnection *CreateMozcConnection();
+  virtual ~MozcConnection();
+
+  // 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.
+  virtual bool TrySendKeyEvent(FcitxInstance* instance,
+                               FcitxKeySym sym, uint32 keycode, uint32 state,
+                               mozc::commands::CompositionMode composition_mode,
+                               bool layout_is_jp,
+                               bool is_key_up,
+                               mozc::commands::Output *out,
+                               string *out_error) const;
+
+  // Sends 'mouse click on the candidate window' event to the server.
+  virtual bool TrySendClick(int32 unique_id,
+                            mozc::commands::Output *out,
+                            string *out_error) const;
+
+  // Sends composition mode to the server.
+  virtual bool TrySendCompositionMode(mozc::commands::CompositionMode mode,
+                                      mozc::commands::Output *out,
+                                      string *out_error) const;
+
+  // Sends a command to the server.
+  virtual bool TrySendCommand(mozc::commands::SessionCommand::CommandType type,
+                              mozc::commands::Output *out,
+                              string *out_error) const;
+
+  virtual bool TrySendRawCommand(const mozc::commands::SessionCommand& command,
+                                 mozc::commands::Output *out,
+                                 string *out_error) const;
+
+  virtual mozc::client::ClientInterface* GetClient();
+
+  virtual void UpdatePreeditMethod();
+
+ private:
+  friend class MozcConnectionTest;
+  MozcConnection(mozc::client::ServerLauncherInterface *server_launcher,
+                 mozc::IPCClientFactoryInterface *client_factory);
+
+  const std::unique_ptr<KeyEventHandler> handler_;
+  mozc::config::Config::PreeditMethod preedit_method_;
+  // Keep definition order of client_factory_ and client_.
+  // We should delete client_ before deleting client_factory_.
+  std::unique_ptr<mozc::IPCClientFactoryInterface> client_factory_;
+  std::unique_ptr<mozc::client::ClientInterface> client_;
+
+  DISALLOW_COPY_AND_ASSIGN(MozcConnection);
+};
+
+}  // namespace fcitx
+
+}  // namespace mozc
+
+#endif  // MOZC_UNIX_SCIM_MOZC_CONNECTION_H_
diff --git a/src/unix/fcitx/mozc_response_parser.cc b/src/unix/fcitx/mozc_response_parser.cc
new file mode 100755
index 00000000..cd9ed811
--- /dev/null
+++ b/src/unix/fcitx/mozc_response_parser.cc
@@ -0,0 +1,448 @@
+// Copyright 2010-2012, Google Inc.
+// Copyright 2012~2013, Weng Xuetian <wengxt@gmail.com>
+// 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/fcitx/mozc_response_parser.h"
+
+#include <string>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/process.h"
+#include "base/util.h"
+#include "protocol/commands.pb.h"
+#include "unix/fcitx/fcitx_mozc.h"
+#include "unix/fcitx/surrounding_text_util.h"
+#include <fcitx/candidate.h>
+
+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();
+}
+
+string CreateDescriptionString(const string &description) {
+    return " [" + description + "]";
+}
+
+}  // namespace
+
+namespace mozc {
+
+namespace fcitx {
+
+MozcResponseParser::MozcResponseParser()
+        : use_annotation_(false) {
+}
+
+MozcResponseParser::~MozcResponseParser() {
+}
+
+void MozcResponseParser::UpdateDeletionRange(const mozc::commands::Output& response, FcitxMozc* fcitx_mozc) const
+{
+    if (response.has_deletion_range() &&
+        response.deletion_range().offset() <= 0 &&
+        response.deletion_range().offset() + response.deletion_range().length() >= 0) {
+        FcitxInstanceDeleteSurroundingText(fcitx_mozc->GetInstance(),
+                                           FcitxInstanceGetCurrentIC(fcitx_mozc->GetInstance()),
+                                           response.deletion_range().offset(),
+                                           response.deletion_range().length());
+    }
+}
+
+void MozcResponseParser::LaunchTool(const mozc::commands::Output& response, FcitxMozc* fcitx_mozc) const
+{
+    FCITX_UNUSED(fcitx_mozc);
+    if (response.has_launch_tool_mode()) {
+        fcitx_mozc->GetClient()->LaunchToolWithProtoBuf(response);
+    }
+}
+
+void MozcResponseParser::ExecuteCallback(const mozc::commands::Output& response, FcitxMozc* fcitx_mozc) const
+{
+    if (!response.has_callback()) {
+        return;
+    }
+
+    if (!response.callback().has_session_command()) {
+        LOG(ERROR) << "callback does not have session_command";
+        return;
+    }
+
+    const commands::SessionCommand &callback_command =
+        response.callback().session_command();
+
+    if (!callback_command.has_type()) {
+        LOG(ERROR) << "callback_command has no type";
+        return;
+    }
+
+    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 commands::SessionCommand::UNDO:
+            break;
+        case commands::SessionCommand::CONVERT_REVERSE: {
+
+            if (!GetSurroundingText(fcitx_mozc->GetInstance(),
+                                    &surrounding_text_info)) {
+                return;
+            }
+
+            session_command.set_text(surrounding_text_info.selection_text);
+            break;
+        }
+        default:
+            return;
+    }
+
+    commands::Output new_output;
+    if (!fcitx_mozc->SendCommand(session_command, &new_output)) {
+        LOG(ERROR) << "Callback Command Failed";
+        return;
+    }
+
+    if (callback_command.type() == commands::SessionCommand::CONVERT_REVERSE) {
+        // We need to remove selected text as a first step of reconversion.
+        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, fcitx_mozc);
+}
+
+bool MozcResponseParser::ParseResponse(const mozc::commands::Output &response,
+                                       FcitxMozc *fcitx_mozc) const {
+    DCHECK(fcitx_mozc);
+    if (!fcitx_mozc) {
+        return false;
+    }
+
+    fcitx_mozc->SetUsage("", "");
+
+    UpdateDeletionRange(response, fcitx_mozc);
+
+    // 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()) {
+        fcitx_mozc->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, fcitx_mozc);
+    }
+
+    // First, determine the cursor position.
+    if (response.has_preedit()) {
+        const mozc::commands::Preedit &preedit = response.preedit();
+        ParsePreedit(preedit, GetCursorPosition(response), fcitx_mozc);
+    }
+
+    // Then show the candidate window.
+    if (response.has_candidates()) {
+        const mozc::commands::Candidates &candidates = response.candidates();
+        ParseCandidates(candidates, fcitx_mozc);
+    }
+
+    if (response.has_url()) {
+        const string &url = response.url();
+        fcitx_mozc->SetUrl(url);
+    }
+    LaunchTool(response, fcitx_mozc);
+    ExecuteCallback(response, fcitx_mozc);
+
+    return true;  // mozc consumed the key.
+}
+
+void MozcResponseParser::set_use_annotation(bool use_annotation) {
+    use_annotation_ = use_annotation;
+}
+
+void MozcResponseParser::ParseResult(const mozc::commands::Result &result,
+                                     FcitxMozc *fcitx_mozc) const {
+    switch (result.type()) {
+    case mozc::commands::Result::NONE: {
+        fcitx_mozc->SetAuxString("No result");  // not a fatal error.
+        break;
+    }
+    case mozc::commands::Result::STRING: {
+        fcitx_mozc->SetResultString(result.value());
+        break;
+    }
+    }
+}
+
+static boolean FcitxMozcPaging(void* arg, boolean prev)
+{
+    FcitxMozc* mozc = static_cast<FcitxMozc*>(arg);
+    return mozc->paging(prev);
+}
+
+void MozcResponseParser::ParseCandidates(
+    const mozc::commands::Candidates &candidates, FcitxMozc *fcitx_mozc) const {
+    const commands::Footer &footer = candidates.footer();
+    bool hasPrev = false;
+    bool hasNext = false;
+    if (candidates.has_footer()) {
+        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()) {
+            // Max size of candidates is 200 so 128 is sufficient size for the buffer.
+            char index_buf[128] = {0};
+            const int result = snprintf(index_buf,
+                                        sizeof(index_buf) - 1,
+                                        "%s%d/%d",
+                                        (auxString.empty() ? "" : " "),
+                                        candidates.focused_index() + 1,
+                                        candidates.size());
+            DCHECK_GE(result, 0) << "snprintf in ComposeAuxiliaryText failed";
+            auxString += index_buf;
+
+            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;
+                }
+            }
+        }
+        fcitx_mozc->SetAuxString(auxString);
+    }
+
+    FcitxCandidateWordList* candList = FcitxInputStateGetCandidateList(fcitx_mozc->GetInputState());
+    FcitxCandidateWordReset(candList);
+    FcitxCandidateWordSetPageSize(candList, 9);
+    if (candidates.has_direction() &&
+        candidates.direction() == commands::Candidates::HORIZONTAL) {
+        FcitxCandidateWordSetLayoutHint(candList, CLH_Horizontal);
+    } else {
+        FcitxCandidateWordSetLayoutHint(candList, CLH_Vertical);
+    }
+
+    std::map<int32, std::pair<string, string> > usage_map;
+    if (candidates.has_usages()) {
+        const commands::InformationList& usages = candidates.usages();
+        for (size_t i = 0; i < usages.information().size(); ++i) {
+            const 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();
+        }
+    }
+
+#define EMPTY_STR_CHOOSE "\0\0\0\0\0\0\0\0\0\0"
+    std::vector<char> choose;
+
+    int focused_index = -1;
+    int local_index = -1;
+    if (candidates.has_focused_index()) {
+        focused_index = candidates.focused_index();
+    }
+    for (int i = 0; i < candidates.candidate_size(); ++i) {
+        const commands::Candidates::Candidate& candidate = candidates.candidate(i);
+        const uint32 index = candidate.index();
+        FcitxMessageType type;
+        if (focused_index != -1 && index == focused_index) {
+            local_index = i;
+            type = MSG_FIRSTCAND;
+        } else {
+            type = MSG_OTHER;
+        }
+        int32* id = (int32*) fcitx_utils_malloc0(sizeof(int32));
+        FcitxCandidateWord candWord;
+        candWord.callback = FcitxMozcGetCandidateWord;
+        candWord.extraType = MSG_OTHER;
+        candWord.strExtra = NULL;
+        candWord.priv = id;
+        candWord.strWord = NULL;
+        candWord.wordType = type;
+        candWord.owner = fcitx_mozc;
+
+        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());
+        }
+
+        if (use_annotation_ && focused_index != -1 && index == focused_index) {
+            local_index = i;
+            type = MSG_FIRSTCAND;
+
+            if (candidate.has_information_id()) {
+                std::map<int32, std::pair<string, string> >::iterator it =
+                    usage_map.find(candidate.information_id());
+                if (it != usage_map.end()) {
+                    fcitx_mozc->SetUsage(it->second.first, it->second.second);
+                }
+                value += CreateDescriptionString(_("Press Ctrl+Alt+H to show usages."));
+            }
+        }
+
+        if (candidate.has_annotation() &&
+            candidate.annotation().has_shortcut()) {
+            choose.push_back(candidate.annotation().shortcut().c_str()[0]);
+        }
+
+        candWord.strWord = strdup(value.c_str());
+
+        if (candidate.has_id()) {
+            const int32 cid = candidate.id();
+            DCHECK_NE(kBadCandidateId, cid) << "Unexpected id is passed.";
+            *id = cid;
+        } else {
+            // The parent node of the cascading window does not have an id since the
+            // node does not contain a candidate word.
+            *id = kBadCandidateId;
+        }
+        FcitxCandidateWordAppend(candList, &candWord);
+    }
+
+    while (choose.size() < 10) {
+        choose.push_back('\0');
+    }
+
+    if (footer.has_index_visible() && footer.index_visible())
+        FcitxCandidateWordSetChoose(candList, choose.data());
+    else
+        FcitxCandidateWordSetChoose(candList, EMPTY_STR_CHOOSE);
+    FcitxCandidateWordSetFocus(candList, local_index);
+    FcitxCandidateWordSetOverridePaging(candList, hasPrev, hasNext, FcitxMozcPaging, fcitx_mozc, NULL);
+}
+
+static int GetRawCursorPos(const char * str, int upos)
+{
+    unsigned int i;
+    int pos = 0;
+    for (i = 0; i < upos; i++) {
+        pos += fcitx_utf8_char_len(fcitx_utf8_get_nth_char((char*)str, i));
+    }
+    return pos;
+}
+
+
+void MozcResponseParser::ParsePreedit(const mozc::commands::Preedit &preedit,
+                                      uint32 position,
+                                      FcitxMozc *fcitx_mozc) const {
+    PreeditInfo *info = new PreeditInfo;
+    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();
+        FcitxMessageType type = MSG_INPUT;
+
+        switch (segment.annotation()) {
+        case mozc::commands::Preedit_Segment::NONE:
+            type = (FcitxMessageType) (MSG_INPUT | MSG_NOUNDERLINE);
+            break;
+        case mozc::commands::Preedit_Segment::UNDERLINE:
+            type = (FcitxMessageType) (MSG_TIPS);
+            break;
+        case mozc::commands::Preedit_Segment::HIGHLIGHT:
+            type = (FcitxMessageType) (MSG_CODE | MSG_NOUNDERLINE | MSG_HIGHLIGHT);
+            break;
+        }
+        s += str;
+
+        PreeditItem item;
+        item.type = type;
+        item.str = str;
+        info->preedit.push_back(item);
+    }
+    info->cursor_pos = GetRawCursorPos(s.c_str(), position);
+
+    fcitx_mozc->SetPreeditInfo(info);
+}
+
+}  // namespace fcitx
+
+}  // namespace mozc
diff --git a/src/unix/fcitx/mozc_response_parser.h b/src/unix/fcitx/mozc_response_parser.h
new file mode 100755
index 00000000..beeef709
--- /dev/null
+++ b/src/unix/fcitx/mozc_response_parser.h
@@ -0,0 +1,97 @@
+// Copyright 2010-2012, Google Inc.
+// Copyright 2012~2013, Weng Xuetian <wengxt@gmail.com>
+// 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 mozc
+{
+
+namespace fcitx
+{
+
+class FcitxMozc;
+
+// This class parses IPC response from mozc_server (mozc::commands::Output) and
+// updates the FCITX UI.
+class MozcResponseParser
+{
+public:
+    MozcResponseParser();
+    ~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,
+                         FcitxMozc *fcitx_mozc ) const;
+
+    // Setter for use_annotation_. If use_annotation_ is true, ParseCandidates()
+    // uses annotation infomation.
+    void set_use_annotation ( bool use_annotation );
+
+private:
+    void UpdateDeletionRange(const mozc::commands::Output& response, FcitxMozc* fcitx_mozc) const;
+    void LaunchTool(const mozc::commands::Output& response, FcitxMozc* fcitx_mozc) const;
+    void ExecuteCallback(const mozc::commands::Output& response, FcitxMozc* fcitx_mozc) const;
+    void ParseResult ( const mozc::commands::Result &result,
+                       FcitxMozc *fcitx_mozc ) const;
+    void ParseCandidates ( const mozc::commands::Candidates &candidates,
+                           FcitxMozc *fcitx_mozc ) const;
+    void ParsePreedit ( const mozc::commands::Preedit &preedit,
+                        uint32 position,
+                        FcitxMozc *fcitx_mozc ) const;
+
+    bool use_annotation_;
+
+    DISALLOW_COPY_AND_ASSIGN ( MozcResponseParser );
+};
+
+}  // namespace fcitx
+
+}  // namespace mozc
+
+#endif  // MOZC_UNIX_FCITX_MOZC_RESPONSE_PARSER_H_
diff --git a/src/unix/fcitx/po/Messages.sh b/src/unix/fcitx/po/Messages.sh
new file mode 100755
index 00000000..be341716
--- /dev/null
+++ b/src/unix/fcitx/po/Messages.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+BASEDIR="../" # root of translatable sources
+PROJECT="fcitx-mozc" # project name
+BUGADDR="fcitx-dev@googlegroups.com" # MSGID-Bugs
+WDIR="`pwd`" # working dir
+
+echo "Preparing rc files"
+
+echo "Done preparing rc files"
+echo "Extracting messages"
+
+# see above on sorting
+
+find "${BASEDIR}" -name '*.cc' -o -name '*.h' -o -name '*.c' | sort > "${WDIR}/infiles.list"
+
+xgettext --from-code=UTF-8 -k_ -kN_ --msgid-bugs-address="${BUGADDR}" --files-from=infiles.list \
+    -D "${BASEDIR}" -D "${WDIR}" -o "${PROJECT}.pot" || \
+    { echo "error while calling xgettext. aborting."; exit 1; }
+echo "Done extracting messages"
+
+echo "Merging translations"
+catalogs=`find . -name '*.po'`
+for cat in $catalogs; do
+    echo "$cat"
+    msgmerge -o "$cat.new" "$cat" "${WDIR}/${PROJECT}.pot"
+    mv "$cat.new" "$cat"
+done
+
+echo "Done merging translations"
+echo "Cleaning up"
+rm "${WDIR}/infiles.list"
+echo "Done"
diff --git a/src/unix/fcitx/po/ca.po b/src/unix/fcitx/po/ca.po
new file mode 100644
index 00000000..b8b10f5a
--- /dev/null
+++ b/src/unix/fcitx/po/ca.po
@@ -0,0 +1,88 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# Robert Antoni Buj Gelonch <rbuj@fedoraproject.org>, 2017
+# Walter Garcia-Fontes <walter.garcia@upf.edu>, 2017
+msgid ""
+msgstr ""
+"Project-Id-Version: fcitx\n"
+"Report-Msgid-Bugs-To: fcitx-dev@googlegroups.com\n"
+"POT-Creation-Date: 2017-12-21 00:03-0800\n"
+"PO-Revision-Date: 2017-12-20 05:19+0000\n"
+"Last-Translator: Robert Antoni Buj Gelonch <rbuj@fedoraproject.org>\n"
+"Language-Team: Catalan (http://www.transifex.com/fcitx/fcitx/language/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"
+
+#: ../eim.cc:187
+msgid "Press Escape to go back"
+msgstr "Premeu Esc per tornar"
+
+#: ../fcitx_mozc.cc:65
+msgid "Direct"
+msgstr "Directe"
+
+#: ../fcitx_mozc.cc:70
+msgid "Hiragana"
+msgstr "Hiragana"
+
+#: ../fcitx_mozc.cc:75
+msgid "Full Katakana"
+msgstr "Katakana complet"
+
+#: ../fcitx_mozc.cc:80
+msgid "Half ASCII"
+msgstr "ASCII mig"
+
+#: ../fcitx_mozc.cc:85
+msgid "Full ASCII"
+msgstr "ASCII complet"
+
+#: ../fcitx_mozc.cc:90
+msgid "Half Katakana"
+msgstr "Mig katakana"
+
+#: ../fcitx_mozc.cc:406 ../fcitx_mozc.cc:407 ../fcitx_mozc.cc:475
+msgid "Composition Mode"
+msgstr "Mode de composició"
+
+#: ../fcitx_mozc.cc:417 ../fcitx_mozc.cc:418
+msgid "Tool"
+msgstr "Eina"
+
+#: ../fcitx_mozc.cc:488
+msgid "Mozc Tool"
+msgstr "Eina mozc"
+
+#: ../fcitx_mozc.cc:494
+msgid "Configuration Tool"
+msgstr "Eina de configuració"
+
+#: ../fcitx_mozc.cc:495
+msgid "Dictionary Tool"
+msgstr "Eina de diccionari"
+
+#: ../fcitx_mozc.cc:496
+msgid "Hand Writing"
+msgstr "Escriptura a mà"
+
+#: ../fcitx_mozc.cc:497
+msgid "Character Palette"
+msgstr "Paleta de caràcters"
+
+#: ../fcitx_mozc.cc:498
+msgid "Add Word"
+msgstr "Afegeix una paraula"
+
+#: ../fcitx_mozc.cc:499
+msgid "About Mozc"
+msgstr "Quant al mozc"
+
+#: ../mozc_response_parser.cc:366
+msgid "Press Ctrl+Alt+H to show usages."
+msgstr "Premeu Ctrl+Alt+H per mostrar els usos."
diff --git a/src/unix/fcitx/po/da.po b/src/unix/fcitx/po/da.po
new file mode 100644
index 00000000..21f8e0b3
--- /dev/null
+++ b/src/unix/fcitx/po/da.po
@@ -0,0 +1,87 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# scootergrisen, 2017
+msgid ""
+msgstr ""
+"Project-Id-Version: fcitx\n"
+"Report-Msgid-Bugs-To: fcitx-dev@googlegroups.com\n"
+"POT-Creation-Date: 2017-10-18 06:03-0700\n"
+"PO-Revision-Date: 2017-10-18 12:19+0000\n"
+"Last-Translator: scootergrisen\n"
+"Language-Team: Danish (http://www.transifex.com/fcitx/fcitx/language/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"
+
+#: ../eim.cc:187
+msgid "Press Escape to go back"
+msgstr "Tryk på Escape for at gå tilbage"
+
+#: ../fcitx_mozc.cc:65
+msgid "Direct"
+msgstr "Direkte"
+
+#: ../fcitx_mozc.cc:70
+msgid "Hiragana"
+msgstr "Hiragana"
+
+#: ../fcitx_mozc.cc:75
+msgid "Full Katakana"
+msgstr "Fuld Katakana"
+
+#: ../fcitx_mozc.cc:80
+msgid "Half ASCII"
+msgstr "Halv ASCII"
+
+#: ../fcitx_mozc.cc:85
+msgid "Full ASCII"
+msgstr "Fuld ASCII"
+
+#: ../fcitx_mozc.cc:90
+msgid "Half Katakana"
+msgstr "Halv Katakana"
+
+#: ../fcitx_mozc.cc:406 ../fcitx_mozc.cc:407 ../fcitx_mozc.cc:475
+msgid "Composition Mode"
+msgstr "Kompositionstilstand"
+
+#: ../fcitx_mozc.cc:417 ../fcitx_mozc.cc:418
+msgid "Tool"
+msgstr "Værktøj"
+
+#: ../fcitx_mozc.cc:488
+msgid "Mozc Tool"
+msgstr "Mozc-værktøj"
+
+#: ../fcitx_mozc.cc:494
+msgid "Configuration Tool"
+msgstr "Konfigurationsværktøj"
+
+#: ../fcitx_mozc.cc:495
+msgid "Dictionary Tool"
+msgstr "Ordbogsværktøj"
+
+#: ../fcitx_mozc.cc:496
+msgid "Hand Writing"
+msgstr "Håndskrift"
+
+#: ../fcitx_mozc.cc:497
+msgid "Character Palette"
+msgstr "Tegnpalet"
+
+#: ../fcitx_mozc.cc:498
+msgid "Add Word"
+msgstr "Tilføj ord"
+
+#: ../fcitx_mozc.cc:499
+msgid "About Mozc"
+msgstr "Om Mozc"
+
+#: ../mozc_response_parser.cc:366
+msgid "Press Ctrl+Alt+H to show usages."
+msgstr "Tryk på Ctrl+Alt+H for at vise anvendelser."
diff --git a/src/unix/fcitx/po/de.po b/src/unix/fcitx/po/de.po
new file mode 100644
index 00000000..11960867
--- /dev/null
+++ b/src/unix/fcitx/po/de.po
@@ -0,0 +1,91 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# Lucius Annaeus Seneca, 2013
+# mar well <m.wellendorf@gmx.de>, 2013
+# Seneca, 2013
+# csslayer <wengxt@gmail.com>, 2013
+# csslayer <wengxt@gmail.com>, 2013
+msgid ""
+msgstr ""
+"Project-Id-Version: fcitx\n"
+"Report-Msgid-Bugs-To: fcitx-dev@googlegroups.com\n"
+"POT-Creation-Date: 2015-08-03 18:01+0200\n"
+"PO-Revision-Date: 2013-11-16 14:13+0000\n"
+"Last-Translator: csslayer <wengxt@gmail.com>\n"
+"Language-Team: German (http://www.transifex.com/fcitx/fcitx/language/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"
+
+#: ../eim.cc:181
+msgid "Press Escape to go back"
+msgstr "ESC drücken um zurück zu kehren"
+
+#: ../fcitx_mozc.cc:65
+msgid "Direct"
+msgstr "Direkt"
+
+#: ../fcitx_mozc.cc:70
+msgid "Hiragana"
+msgstr "Hiragana"
+
+#: ../fcitx_mozc.cc:75
+msgid "Full Katakana"
+msgstr "Normalbreite Katakana"
+
+#: ../fcitx_mozc.cc:80
+msgid "Half ASCII"
+msgstr "6-Bit ASCII (Half ASCII)"
+
+#: ../fcitx_mozc.cc:85
+msgid "Full ASCII"
+msgstr "7-Bit ASCII (Full ASCII)"
+
+#: ../fcitx_mozc.cc:90
+msgid "Half Katakana"
+msgstr "Halbbreite Katakana"
+
+#: ../fcitx_mozc.cc:406 ../fcitx_mozc.cc:407 ../fcitx_mozc.cc:475
+msgid "Composition Mode"
+msgstr "Kompositionsmodus"
+
+#: ../fcitx_mozc.cc:417 ../fcitx_mozc.cc:418
+msgid "Tool"
+msgstr "Werkzeug"
+
+#: ../fcitx_mozc.cc:488
+msgid "Mozc Tool"
+msgstr "Mozc Werkzeug"
+
+#: ../fcitx_mozc.cc:494
+msgid "Configuration Tool"
+msgstr "Konfigurationswerkzeug"
+
+#: ../fcitx_mozc.cc:495
+msgid "Dictionary Tool"
+msgstr "Wörterbuchwerkzeug"
+
+#: ../fcitx_mozc.cc:496
+msgid "Hand Writing"
+msgstr "Eingabe Handschrift"
+
+#: ../fcitx_mozc.cc:497
+msgid "Character Palette"
+msgstr "Palette Symbole"
+
+#: ../fcitx_mozc.cc:498
+msgid "Add Word"
+msgstr "Wort hinzufügen"
+
+#: ../fcitx_mozc.cc:499
+msgid "About Mozc"
+msgstr "Über Mozc"
+
+#: ../mozc_response_parser.cc:366
+msgid "Press Ctrl+Alt+H to show usages."
+msgstr "Ctrl+Alt+H um die Hilfe anzuzeigen"
diff --git a/src/unix/fcitx/po/fcitx-mozc.pot b/src/unix/fcitx/po/fcitx-mozc.pot
new file mode 100644
index 00000000..d9983e40
--- /dev/null
+++ b/src/unix/fcitx/po/fcitx-mozc.pot
@@ -0,0 +1,86 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: fcitx-dev@googlegroups.com\n"
+"POT-Creation-Date: 2013-11-14 13:55-0500\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../eim.cc:184
+msgid "Press Escape to go back"
+msgstr ""
+
+#: ../fcitx_mozc.cc:68
+msgid "Direct"
+msgstr ""
+
+#: ../fcitx_mozc.cc:73
+msgid "Hiragana"
+msgstr ""
+
+#: ../fcitx_mozc.cc:78
+msgid "Full Katakana"
+msgstr ""
+
+#: ../fcitx_mozc.cc:83
+msgid "Half ASCII"
+msgstr ""
+
+#: ../fcitx_mozc.cc:88
+msgid "Full ASCII"
+msgstr ""
+
+#: ../fcitx_mozc.cc:93
+msgid "Half Katakana"
+msgstr ""
+
+#: ../fcitx_mozc.cc:410 ../fcitx_mozc.cc:411 ../fcitx_mozc.cc:484
+msgid "Composition Mode"
+msgstr ""
+
+#: ../fcitx_mozc.cc:421 ../fcitx_mozc.cc:422
+msgid "Tool"
+msgstr ""
+
+#: ../fcitx_mozc.cc:497
+msgid "Mozc Tool"
+msgstr ""
+
+#: ../fcitx_mozc.cc:503
+msgid "Configuration Tool"
+msgstr ""
+
+#: ../fcitx_mozc.cc:504
+msgid "Dictionary Tool"
+msgstr ""
+
+#: ../fcitx_mozc.cc:505
+msgid "Hand Writing"
+msgstr ""
+
+#: ../fcitx_mozc.cc:506
+msgid "Character Palette"
+msgstr ""
+
+#: ../fcitx_mozc.cc:507
+msgid "Add Word"
+msgstr ""
+
+#: ../fcitx_mozc.cc:508
+msgid "About Mozc"
+msgstr ""
+
+#: ../mozc_response_parser.cc:374
+msgid "Press Ctrl+Alt+H to show usages."
+msgstr ""
diff --git a/src/unix/fcitx/po/ja.po b/src/unix/fcitx/po/ja.po
new file mode 100644
index 00000000..a3f4d5f3
--- /dev/null
+++ b/src/unix/fcitx/po/ja.po
@@ -0,0 +1,93 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# しろう, 2013
+# AWASHIRO Ikuya <ikunya@gmail.com>, 2013
+# AWASHIRO Ikuya <ikunya@gmail.com>, 2012-2013
+# WAKAYAMA Shirou <shirou.faw@gmail.com>, 2013
+# csslayer <wengxt@gmail.com>, 2013
+# csslayer <wengxt@gmail.com>, 2012
+# csslayer <wengxt@gmail.com>, 2012-2013
+msgid ""
+msgstr ""
+"Project-Id-Version: fcitx\n"
+"Report-Msgid-Bugs-To: fcitx-dev@googlegroups.com\n"
+"POT-Creation-Date: 2015-08-03 18:01+0200\n"
+"PO-Revision-Date: 2013-11-16 14:13+0000\n"
+"Last-Translator: csslayer <wengxt@gmail.com>\n"
+"Language-Team: Japanese (http://www.transifex.com/fcitx/fcitx/language/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"
+
+#: ../eim.cc:181
+msgid "Press Escape to go back"
+msgstr "Escキーを押して戻る"
+
+#: ../fcitx_mozc.cc:65
+msgid "Direct"
+msgstr "直接入力"
+
+#: ../fcitx_mozc.cc:70
+msgid "Hiragana"
+msgstr "ひらがな"
+
+#: ../fcitx_mozc.cc:75
+msgid "Full Katakana"
+msgstr "全角カタカナ"
+
+#: ../fcitx_mozc.cc:80
+msgid "Half ASCII"
+msgstr "半角英数"
+
+#: ../fcitx_mozc.cc:85
+msgid "Full ASCII"
+msgstr "全角英数"
+
+#: ../fcitx_mozc.cc:90
+msgid "Half Katakana"
+msgstr "半角カタカナ"
+
+#: ../fcitx_mozc.cc:406 ../fcitx_mozc.cc:407 ../fcitx_mozc.cc:475
+msgid "Composition Mode"
+msgstr "変換モード"
+
+#: ../fcitx_mozc.cc:417 ../fcitx_mozc.cc:418
+msgid "Tool"
+msgstr "ツール"
+
+#: ../fcitx_mozc.cc:488
+msgid "Mozc Tool"
+msgstr "Mozc ツール"
+
+#: ../fcitx_mozc.cc:494
+msgid "Configuration Tool"
+msgstr "設定ツール"
+
+#: ../fcitx_mozc.cc:495
+msgid "Dictionary Tool"
+msgstr "辞書ツール"
+
+#: ../fcitx_mozc.cc:496
+msgid "Hand Writing"
+msgstr "手書き文字認識"
+
+#: ../fcitx_mozc.cc:497
+msgid "Character Palette"
+msgstr "文字パレット"
+
+#: ../fcitx_mozc.cc:498
+msgid "Add Word"
+msgstr "単語登録"
+
+#: ../fcitx_mozc.cc:499
+msgid "About Mozc"
+msgstr "Mozc について"
+
+#: ../mozc_response_parser.cc:366
+msgid "Press Ctrl+Alt+H to show usages."
+msgstr "Ctrl+Alt+H キーを押して用例を表示"
diff --git a/src/unix/fcitx/po/ko.po b/src/unix/fcitx/po/ko.po
new file mode 100644
index 00000000..0d4b46a6
--- /dev/null
+++ b/src/unix/fcitx/po/ko.po
@@ -0,0 +1,87 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# Bon Keun Seo <scobyseo@gmail.com>, 2017
+msgid ""
+msgstr ""
+"Project-Id-Version: fcitx\n"
+"Report-Msgid-Bugs-To: fcitx-dev@googlegroups.com\n"
+"POT-Creation-Date: 2017-07-15 14:20-0700\n"
+"PO-Revision-Date: 2017-07-09 21:58+0000\n"
+"Last-Translator: Bon Keun Seo <scobyseo@gmail.com>\n"
+"Language-Team: Korean (http://www.transifex.com/fcitx/fcitx/language/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"
+
+#: ../eim.cc:187
+msgid "Press Escape to go back"
+msgstr "돌아가려면 ESC를 누르세요"
+
+#: ../fcitx_mozc.cc:65
+msgid "Direct"
+msgstr "직접입력"
+
+#: ../fcitx_mozc.cc:70
+msgid "Hiragana"
+msgstr "히라가나"
+
+#: ../fcitx_mozc.cc:75
+msgid "Full Katakana"
+msgstr "전각 가타가나"
+
+#: ../fcitx_mozc.cc:80
+msgid "Half ASCII"
+msgstr "반각 아스키"
+
+#: ../fcitx_mozc.cc:85
+msgid "Full ASCII"
+msgstr "전각 아스키"
+
+#: ../fcitx_mozc.cc:90
+msgid "Half Katakana"
+msgstr "반각 가타가나"
+
+#: ../fcitx_mozc.cc:406 ../fcitx_mozc.cc:407 ../fcitx_mozc.cc:475
+msgid "Composition Mode"
+msgstr "조합 모드"
+
+#: ../fcitx_mozc.cc:417 ../fcitx_mozc.cc:418
+msgid "Tool"
+msgstr "도구"
+
+#: ../fcitx_mozc.cc:488
+msgid "Mozc Tool"
+msgstr "Mozc 도구"
+
+#: ../fcitx_mozc.cc:494
+msgid "Configuration Tool"
+msgstr "설정 도구"
+
+#: ../fcitx_mozc.cc:495
+msgid "Dictionary Tool"
+msgstr "사전 도구"
+
+#: ../fcitx_mozc.cc:496
+msgid "Hand Writing"
+msgstr "손 글씨"
+
+#: ../fcitx_mozc.cc:497
+msgid "Character Palette"
+msgstr "글자 팔레트"
+
+#: ../fcitx_mozc.cc:498
+msgid "Add Word"
+msgstr "단어 추가"
+
+#: ../fcitx_mozc.cc:499
+msgid "About Mozc"
+msgstr "Mozc에 대해"
+
+#: ../mozc_response_parser.cc:366
+msgid "Press Ctrl+Alt+H to show usages."
+msgstr "사용법을 보려면 Ctrl+Alt+H를 누르세요."
diff --git a/src/unix/fcitx/po/ru.po b/src/unix/fcitx/po/ru.po
new file mode 100644
index 00000000..22c1fcc3
--- /dev/null
+++ b/src/unix/fcitx/po/ru.po
@@ -0,0 +1,89 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# TotalCaesar659 <x24cm5b8c54q6szxw@yandex.ru>, 2016
+msgid ""
+msgstr ""
+"Project-Id-Version: fcitx\n"
+"Report-Msgid-Bugs-To: fcitx-dev@googlegroups.com\n"
+"POT-Creation-Date: 2016-12-01 08:40-0800\n"
+"PO-Revision-Date: 2016-11-30 23:24+0000\n"
+"Last-Translator: TotalCaesar659 <x24cm5b8c54q6szxw@yandex.ru>\n"
+"Language-Team: Russian (http://www.transifex.com/fcitx/fcitx/language/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"
+
+#: ../eim.cc:187
+msgid "Press Escape to go back"
+msgstr "Нажмите  для перехода назад"
+
+#: ../fcitx_mozc.cc:65
+msgid "Direct"
+msgstr "Прямой"
+
+#: ../fcitx_mozc.cc:70
+msgid "Hiragana"
+msgstr "Хирагана"
+
+#: ../fcitx_mozc.cc:75
+msgid "Full Katakana"
+msgstr "Полная катакана"
+
+#: ../fcitx_mozc.cc:80
+msgid "Half ASCII"
+msgstr "Половинный "
+
+#: ../fcitx_mozc.cc:85
+msgid "Full ASCII"
+msgstr "Полный "
+
+#: ../fcitx_mozc.cc:90
+msgid "Half Katakana"
+msgstr "Половинная катакана"
+
+#: ../fcitx_mozc.cc:406 ../fcitx_mozc.cc:407 ../fcitx_mozc.cc:475
+msgid "Composition Mode"
+msgstr "Режим композиции"
+
+#: ../fcitx_mozc.cc:417 ../fcitx_mozc.cc:418
+msgid "Tool"
+msgstr "Инструмент"
+
+#: ../fcitx_mozc.cc:488
+msgid "Mozc Tool"
+msgstr "Инструмент Mozc"
+
+#: ../fcitx_mozc.cc:494
+msgid "Configuration Tool"
+msgstr "Инструмент настройки"
+
+#: ../fcitx_mozc.cc:495
+msgid "Dictionary Tool"
+msgstr "Инструмент словаря"
+
+#: ../fcitx_mozc.cc:496
+msgid "Hand Writing"
+msgstr "Ручное письмо"
+
+#: ../fcitx_mozc.cc:497
+msgid "Character Palette"
+msgstr "Палитра символов"
+
+#: ../fcitx_mozc.cc:498
+msgid "Add Word"
+msgstr "Добавить слово"
+
+#: ../fcitx_mozc.cc:499
+msgid "About Mozc"
+msgstr "О "
+
+#: ../mozc_response_parser.cc:366
+msgid "Press Ctrl+Alt+H to show usages."
+msgstr "Нажмите Ctrl+Alt+H, чтобы показать использование."
diff --git a/src/unix/fcitx/po/zh_CN.po b/src/unix/fcitx/po/zh_CN.po
new file mode 100644
index 00000000..6e46bc64
--- /dev/null
+++ b/src/unix/fcitx/po/zh_CN.po
@@ -0,0 +1,92 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# csslayer <wengxt@gmail.com>, 2013
+# csslayer <wengxt@gmail.com>, 2012
+# wwj402 <wwj402@gmail.com>, 2013
+# wwj402 <wwj402@gmail.com>, 2013
+# csslayer <wengxt@gmail.com>, 2012-2013
+msgid ""
+msgstr ""
+"Project-Id-Version: fcitx\n"
+"Report-Msgid-Bugs-To: fcitx-dev@googlegroups.com\n"
+"POT-Creation-Date: 2015-07-21 12:01+0200\n"
+"PO-Revision-Date: 2013-11-16 14:13+0000\n"
+"Last-Translator: csslayer <wengxt@gmail.com>\n"
+"Language-Team: Chinese (China) (http://www.transifex.com/projects/p/fcitx/"
+"language/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"
+
+#: ../eim.cc:181
+msgid "Press Escape to go back"
+msgstr "按下 Escape 返回"
+
+#: ../fcitx_mozc.cc:65
+msgid "Direct"
+msgstr "直接键盘输入"
+
+#: ../fcitx_mozc.cc:70
+msgid "Hiragana"
+msgstr "平假名"
+
+#: ../fcitx_mozc.cc:75
+msgid "Full Katakana"
+msgstr "全角片假名"
+
+#: ../fcitx_mozc.cc:80
+msgid "Half ASCII"
+msgstr "半角 ASCII"
+
+#: ../fcitx_mozc.cc:85
+msgid "Full ASCII"
+msgstr "全角 ASCII"
+
+#: ../fcitx_mozc.cc:90
+msgid "Half Katakana"
+msgstr "半角片假名"
+
+#: ../fcitx_mozc.cc:405 ../fcitx_mozc.cc:406 ../fcitx_mozc.cc:474
+msgid "Composition Mode"
+msgstr "编辑模式"
+
+#: ../fcitx_mozc.cc:416 ../fcitx_mozc.cc:417
+msgid "Tool"
+msgstr "工具"
+
+#: ../fcitx_mozc.cc:487
+msgid "Mozc Tool"
+msgstr "Mozc 工具"
+
+#: ../fcitx_mozc.cc:493
+msgid "Configuration Tool"
+msgstr "配置工具"
+
+#: ../fcitx_mozc.cc:494
+msgid "Dictionary Tool"
+msgstr "词典工具"
+
+#: ../fcitx_mozc.cc:495
+msgid "Hand Writing"
+msgstr "手写输入"
+
+#: ../fcitx_mozc.cc:496
+msgid "Character Palette"
+msgstr "字符映射表"
+
+#: ../fcitx_mozc.cc:497
+msgid "Add Word"
+msgstr "添加单词"
+
+#: ../fcitx_mozc.cc:498
+msgid "About Mozc"
+msgstr "关于 Mozc"
+
+#: ../mozc_response_parser.cc:366
+msgid "Press Ctrl+Alt+H to show usages."
+msgstr "按下 Ctrl+Alt+H 显示用法。"
diff --git a/src/unix/fcitx/po/zh_TW.po b/src/unix/fcitx/po/zh_TW.po
new file mode 100644
index 00000000..69a6c5c0
--- /dev/null
+++ b/src/unix/fcitx/po/zh_TW.po
@@ -0,0 +1,91 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# Alisha <alisha.4m@gmail.com>, 2012
+# csslayer <wengxt@gmail.com>, 2013
+# csslayer <wengxt@gmail.com>, 2012
+# csslayer <wengxt@gmail.com>, 2012-2013
+msgid ""
+msgstr ""
+"Project-Id-Version: fcitx\n"
+"Report-Msgid-Bugs-To: fcitx-dev@googlegroups.com\n"
+"POT-Creation-Date: 2015-07-21 12:01+0200\n"
+"PO-Revision-Date: 2013-11-16 14:13+0000\n"
+"Last-Translator: csslayer <wengxt@gmail.com>\n"
+"Language-Team: Chinese (Taiwan) (http://www.transifex.com/projects/p/fcitx/"
+"language/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"
+
+#: ../eim.cc:181
+msgid "Press Escape to go back"
+msgstr "按下 Escape 返回"
+
+#: ../fcitx_mozc.cc:65
+msgid "Direct"
+msgstr "直接鍵盤輸入"
+
+#: ../fcitx_mozc.cc:70
+msgid "Hiragana"
+msgstr "平假名"
+
+#: ../fcitx_mozc.cc:75
+msgid "Full Katakana"
+msgstr "全形片假名"
+
+#: ../fcitx_mozc.cc:80
+msgid "Half ASCII"
+msgstr "半形 ASCII"
+
+#: ../fcitx_mozc.cc:85
+msgid "Full ASCII"
+msgstr "全形 ASCII"
+
+#: ../fcitx_mozc.cc:90
+msgid "Half Katakana"
+msgstr "半形片假名"
+
+#: ../fcitx_mozc.cc:405 ../fcitx_mozc.cc:406 ../fcitx_mozc.cc:474
+msgid "Composition Mode"
+msgstr "編輯模式"
+
+#: ../fcitx_mozc.cc:416 ../fcitx_mozc.cc:417
+msgid "Tool"
+msgstr "工具"
+
+#: ../fcitx_mozc.cc:487
+msgid "Mozc Tool"
+msgstr "Mozc 工具"
+
+#: ../fcitx_mozc.cc:493
+msgid "Configuration Tool"
+msgstr "設定工具"
+
+#: ../fcitx_mozc.cc:494
+msgid "Dictionary Tool"
+msgstr "字典工具"
+
+#: ../fcitx_mozc.cc:495
+msgid "Hand Writing"
+msgstr "手寫輸入"
+
+#: ../fcitx_mozc.cc:496
+msgid "Character Palette"
+msgstr "字符映射表"
+
+#: ../fcitx_mozc.cc:497
+msgid "Add Word"
+msgstr "添加單詞"
+
+#: ../fcitx_mozc.cc:498
+msgid "About Mozc"
+msgstr "關於 Mozc"
+
+#: ../mozc_response_parser.cc:366
+msgid "Press Ctrl+Alt+H to show usages."
+msgstr "按下 Ctrl+Alt+H 顯示用法。"
diff --git a/src/unix/fcitx/surrounding_text_util.cc b/src/unix/fcitx/surrounding_text_util.cc
new file mode 100644
index 00000000..d6ccc34a
--- /dev/null
+++ b/src/unix/fcitx/surrounding_text_util.cc
@@ -0,0 +1,242 @@
+// 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/fcitx/surrounding_text_util.h"
+
+#include <limits>
+#include <string>
+#include <fcitx/instance.h>
+#include <fcitx/module/clipboard/fcitx-clipboard.h>
+
+#include "base/port.h"
+#include "base/logging.h"
+#include "base/util.h"
+
+namespace mozc {
+namespace fcitx {
+
+bool SurroundingTextUtil::GetSafeDelta(uint from, uint to, int32 *delta) {
+  DCHECK(delta);
+
+  static_assert(sizeof(int64) >= sizeof(uint),
+                "int64 must be sufficient to store a guint value.");
+  static_assert(sizeof(int64) == sizeof(llabs(0)),
+                "|llabs(0)| must returns a 64-bit integer.");
+  const int64 kInt32AbsMax =
+      llabs(static_cast<int64>(std::numeric_limits<int32>::max()));
+  const int64 kInt32AbsMin =
+      llabs(static_cast<int64>(std::numeric_limits<int32>::min()));
+  const int64 kInt32SafeAbsMax =
+      std::min(kInt32AbsMax, kInt32AbsMin);
+
+  const int64 diff = static_cast<int64>(from) - static_cast<int64>(to);
+  if (llabs(diff) > kInt32SafeAbsMax) {
+    return false;
+  }
+
+  *delta = static_cast<int32>(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 string &surrounding_text,
+    const string &selected_text,
+    size_t selected_chars_len,
+    uint cursor_pos,
+    uint *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 string &surrounding_text,
+    const string &selected_text,
+    size_t selected_chars_len,
+    uint cursor_pos,
+    uint *anchor_pos) {
+  if (cursor_pos < selected_chars_len) {
+    return false;
+  }
+
+  ConstChar32Iterator iter(surrounding_text);
+  // Skip |iter| to (potential) anchor pos.
+  const uint 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 string &surrounding_text,
+    const string &selected_text,
+    uint cursor_pos,
+    uint *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(FcitxInstance* instance,
+                        SurroundingTextInfo *info) {
+    FcitxInputContext* ic = FcitxInstanceGetCurrentIC(instance);
+    if (!ic || !(ic->contextCaps & CAPACITY_SURROUNDING_TEXT)) {
+        return false;
+    }
+
+    uint cursor_pos = 0;
+    uint anchor_pos = 0;
+    char* str = NULL;
+
+    if (!FcitxInstanceGetSurroundingText(instance, ic, &str, &cursor_pos, &anchor_pos)) {
+        return false;
+    }
+
+    const string surrounding_text(str);
+    free(str);
+
+    if (cursor_pos == anchor_pos) {
+        const char* primary = NULL;
+
+        if ((primary = FcitxClipboardGetPrimarySelection(instance, NULL)) != NULL) {
+            uint new_anchor_pos = 0;
+            const string primary_text(primary);
+            if (SurroundingTextUtil::GetAnchorPosFromSelection(
+                surrounding_text, primary_text,
+                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);
+    Util::SubStringPiece(surrounding_text, 0, selection_start)
+       .CopyToString(&info->preceding_text);
+    Util::SubStringPiece(surrounding_text, selection_start, selection_length)
+       .CopyToString(&info->selection_text);
+    Util::SubStringPiece(surrounding_text, selection_start + selection_length)
+       .CopyToString(&info->following_text);
+    return true;
+}
+
+}  // namespace fcitx
+}  // namespace mozc
diff --git a/src/unix/fcitx/surrounding_text_util.h b/src/unix/fcitx/surrounding_text_util.h
new file mode 100644
index 00000000..5bf661db
--- /dev/null
+++ b/src/unix/fcitx/surrounding_text_util.h
@@ -0,0 +1,87 @@
+// 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 <string>
+#include <fcitx/instance.h>
+
+#include "base/port.h"
+
+namespace mozc {
+namespace fcitx {
+
+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(uint from, uint 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 string &surrounding_text,
+      const string &selected_text,
+      uint cursor_pos,
+      uint *anchor_pos);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(SurroundingTextUtil);
+};
+
+bool GetSurroundingText(FcitxInstance* instance,
+                        SurroundingTextInfo *info);
+
+}  // namespace fcitx
+}  // namespace mozc
+
+#endif  // MOZC_UNIX_FCITX_SURROUNDING_TEXT_URIL_H_
diff --git a/src/unix/fcitx5/Messages.sh b/src/unix/fcitx5/Messages.sh
new file mode 100755
index 00000000..3bd2d00d
--- /dev/null
+++ b/src/unix/fcitx5/Messages.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+DOMAIN=fcitx5-mozc
+POT_FILE=po/$DOMAIN.pot
+set -x
+XGETTEXT="xgettext --package-name=$DOMAIN --add-comments --sort-output --msgid-bugs-address=fcitx-dev@googlegroups.com"
+source_files=$(find . -name \*.cpp -o -name \*.cc -o -name \*.h)
+$XGETTEXT --keyword=_ --keyword=N_ --language=C++ -o ${POT_FILE} $source_files
+#desktop_files=$(find . -name \*.conf.in -o -name \*.conf.in.in -o -name \*.desktop.in)
+#$XGETTEXT --language=Desktop $desktop_files -j -o ${POT_FILE}
+
+sed -i 's|^"Content-Type: text/plain; charset=CHARSET\\n"|"Content-Type: text/plain; charset=utf-8\\n"|g' ${POT_FILE}
+
+# Due to transifex problem, delete the date.
+#sed -i '/^"PO-Revision-Date/d' ${POT_FILE}
+#sed -i '/^"PO-Revision-Date/d' ${POT_FILE}
+sed -i '/^# FIRST AUTHOR/d' ${POT_FILE}
+sed -i '/^#, fuzzy/d' ${POT_FILE}
+sed -i 's|^"Language: \\n"|"Language: LANG\\n"|g' ${POT_FILE}
+
+echo > po/LINGUAS
+
+for pofile in $(ls po/*.po | sort); do
+  pofilebase=$(basename $pofile)
+  pofilebase=${pofilebase/.po/}
+  msgmerge -U --backup=none $pofile ${POT_FILE}
+  project_line=$(grep "Project-Id-Version" ${POT_FILE} | head -n 1 | tr --delete '\n' | sed -e 's/[\/&]/\\&/g')
+  sed -i "s|.*Project-Id-Version.*|$project_line|g" $pofile
+  echo $pofilebase >> po/LINGUAS
+done
diff --git a/src/unix/fcitx5/fcitx5.gyp b/src/unix/fcitx5/fcitx5.gyp
new file mode 100644
index 00000000..7f6941db
--- /dev/null
+++ b/src/unix/fcitx5/fcitx5.gyp
@@ -0,0 +1,140 @@
+#
+# 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 ibus. 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': [
+          '<!@(pkg-config --cflags <@(target_libs))',
+        ],
+        'link_settings': {
+          'libraries': [
+            '<!@(pkg-config --libs-only-l <@(target_libs))',
+          ],
+          'ldflags': [
+            '<!@(pkg-config --libs-only-L <@(target_libs))',
+          ],
+        },
+      },
+    },
+    {
+      'target_name': 'gen_fcitx_mozc_i18n',
+      'type': 'none',
+      'actions': [
+        {
+          'action_name': 'gen_fcitx_mozc_i18n',
+          'inputs': [
+            './gen_fcitx_mozc_i18n.sh'
+          ],
+          'outputs': [
+            '<(gen_out_dir)/po/zh_CN.mo',
+            '<(gen_out_dir)/po/zh_TW.mo',
+            '<(gen_out_dir)/po/ja.mo',
+            '<(gen_out_dir)/po/de.mo',
+          ],
+          'action': [
+            'sh',
+            './gen_fcitx_mozc_i18n.sh',
+            '<(gen_out_dir)/po',
+          ],
+        }],
+    },
+    {
+      'target_name': 'fcitx5-mozc',
+      'product_prefix': '',
+      'type': 'loadable_module',
+      'sources': [
+        'fcitx_key_translator.cc',
+        'fcitx_key_event_handler.cc',
+        'surrounding_text_util.cc',
+        'mozc_connection.cc',
+        'mozc_response_parser.cc',
+        'mozc_engine.cc',
+        'mozc_state.cc',
+      ],
+      'dependencies': [
+        '<@(fcitx_dependencies)',
+        'gen_fcitx_mozc_i18n',
+        'fcitx5_build_environment',
+      ],
+      'cflags_cc': [
+        '-std=c++14',
+      ],
+      'cflags_cc!': [
+        '-std=gnu++0x'
+      ],
+      'cflags!': [
+        '-fno-exceptions',
+      ],
+      'ldflags': [
+        '-Wl,--no-undefined',
+        '-Wl,--as-needed',
+      ],
+      'defines': [
+        'FCITX_GETTEXT_DOMAIN="fcitx5-mozc"',
+      ],
+    },
+  ],
+  }, {
+  'targets': [
+    {
+      'target_name': 'no_fcitx5_dummy',
+      'type': 'none',
+    }
+  ]}
+  ]],
+}
diff --git a/src/unix/fcitx5/fcitx_key_event_handler.cc b/src/unix/fcitx5/fcitx_key_event_handler.cc
new file mode 100644
index 00000000..0203a92c
--- /dev/null
+++ b/src/unix/fcitx5/fcitx_key_event_handler.cc
@@ -0,0 +1,244 @@
+// Copyright 2010-2012, Google Inc.
+// Copyright 2012-2017, Weng Xuetian <wengxt@gmail.com>
+// 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 <map>
+
+#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<uint32, mozc::commands::KeyEvent::ModifierKey> &data() {
+    return data_;
+  }
+
+ private:
+  std::map<uint32, mozc::commands::KeyEvent::ModifierKey> data_;
+};
+
+// TODO(hsumita): Moves this function into member functions of
+// KeyEventHandler.
+void AddAdditionalModifiers(
+    std::set<mozc::commands::KeyEvent::ModifierKey> *modifier_keys_set) {
+  DCHECK(modifier_keys_set);
+
+  const std::map<uint32, mozc::commands::KeyEvent::ModifierKey> &data =
+      mozc::Singleton<AdditionalModifiersData>::get()->data();
+
+  // Adds MODIFIER if there are (LEFT|RIGHT)_MODIFIER like LEFT_SHIFT.
+  for (std::set<mozc::commands::KeyEvent::ModifierKey>::const_iterator it =
+           modifier_keys_set->begin();
+       it != modifier_keys_set->end(); ++it) {
+    std::map<uint32, mozc::commands::KeyEvent::ModifierKey>::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.
+  //    <Event from ibus> <Event to server>
+  //     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.
+  //    <Event from ibus> <Event to server>
+  //     Ctrl down       | None
+  //     "a" down        | Ctrl+a
+  //     "a" up          | None
+  //     Ctrl up         | None
+  //
+  // E.g.) Modifier key is sent on key up.
+  //    <Event from ibus> <Event to server>
+  //     Shift down      | None
+  //     Shift up        | Shift
+  //
+  // E.g.) Multiple modifier keys are sent on the last key up.
+  //    <Event from ibus> <Event to server>
+  //     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.)
+  //    <Event from ibus> <Event to server>
+  //     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<mozc::commands::KeyEvent::ModifierKey>::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 --git a/src/unix/fcitx5/fcitx_key_event_handler.h b/src/unix/fcitx5/fcitx_key_event_handler.h
new file mode 100644
index 00000000..555718da
--- /dev/null
+++ b/src/unix/fcitx5/fcitx_key_event_handler.h
@@ -0,0 +1,78 @@
+// Copyright 2010-2012, Google Inc.
+// Copyright 2012-2017, Weng Xuetian <wengxt@gmail.com>
+// 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 <fcitx-utils/key.h>
+#include <memory>
+#include <set>
+
+#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<KeyTranslator> 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<uint32> currently_pressed_modifiers_;
+  // Pending modifier keys.
+  std::set<mozc::commands::KeyEvent::ModifierKey> modifiers_to_be_sent_;
+
+  DISALLOW_COPY_AND_ASSIGN(KeyEventHandler);
+};
+
+}  // namespace fcitx
+
+#endif  // UNIX_FCITX5_FCITX_KEY_EVENT_HANDLER_H_
diff --git a/src/unix/fcitx5/fcitx_key_translator.cc b/src/unix/fcitx5/fcitx_key_translator.cc
new file mode 100644
index 00000000..3c06d119
--- /dev/null
+++ b/src/unix/fcitx5/fcitx_key_translator.cc
@@ -0,0 +1,526 @@
+// Copyright 2010-2012, Google Inc.
+// Copyright 2012-2017, Weng Xuetian <wengxt@gmail.com>
+// 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<uint32_t>(KeyState::CapsLock), mozc::commands::KeyEvent::CAPS},
+};
+
+const struct {
+  uint32 from;
+  mozc::commands::KeyEvent::ModifierKey to;
+} modifier_mask_map[] = {
+    {static_cast<uint32_t>(KeyState::Shift), mozc::commands::KeyEvent::SHIFT},
+    {static_cast<uint32_t>(KeyState::Ctrl), mozc::commands::KeyEvent::CTRL},
+    {static_cast<uint32_t>(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;
+  }
+  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,
+                                    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 --git a/src/unix/fcitx5/fcitx_key_translator.h b/src/unix/fcitx5/fcitx_key_translator.h
new file mode 100644
index 00000000..a78be640
--- /dev/null
+++ b/src/unix/fcitx5/fcitx_key_translator.h
@@ -0,0 +1,102 @@
+// Copyright 2010-2012, Google Inc.
+// Copyright 2012-2017, Weng Xuetian <wengxt@gmail.com>
+// 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 <fcitx-utils/key.h>
+#include <map>
+#include <set>
+#include <string>
+
+#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<uint32, mozc::commands::KeyEvent::SpecialKey> SpecialKeyMap;
+  typedef std::map<uint32, mozc::commands::KeyEvent::ModifierKey>
+      ModifierKeyMap;
+  typedef std::map<uint32, std::pair<string, string> > 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, 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 --git a/src/unix/fcitx5/gen_fcitx_mozc_i18n.sh b/src/unix/fcitx5/gen_fcitx_mozc_i18n.sh
new file mode 100755
index 00000000..97ff4a49
--- /dev/null
+++ b/src/unix/fcitx5/gen_fcitx_mozc_i18n.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+objdir="$1"
+
+mkdir -p "$1"
+
+for pofile in po/*.po
+do
+    msgfmt "$pofile" -o "$1/`basename ${pofile} .po`.mo"
+done
diff --git a/src/unix/fcitx5/mozc-addon.conf b/src/unix/fcitx5/mozc-addon.conf
new file mode 100644
index 00000000..e520d4b9
--- /dev/null
+++ b/src/unix/fcitx5/mozc-addon.conf
@@ -0,0 +1,9 @@
+[Addon]
+Name=mozc
+Category=InputMethod
+Library=fcitx5-mozc
+Type=SharedLibrary
+OnDemand=True
+
+[Addon/OptionalDependencies]
+0=clipboard
diff --git a/src/unix/fcitx5/mozc.conf b/src/unix/fcitx5/mozc.conf
new file mode 100644
index 00000000..ab0b7aa5
--- /dev/null
+++ b/src/unix/fcitx5/mozc.conf
@@ -0,0 +1,6 @@
+[InputMethod]
+Name=Mozc
+Icon=PREFIX/share/fcitx5/mozc/icon/mozc.png
+Label=あ
+LangCode=ja
+Addon=mozc
diff --git a/src/unix/fcitx5/mozc_connection.cc b/src/unix/fcitx5/mozc_connection.cc
new file mode 100644
index 00000000..0cc930b0
--- /dev/null
+++ b/src/unix/fcitx5/mozc_connection.cc
@@ -0,0 +1,69 @@
+// Copyright 2010-2012, Google Inc.
+// Copyright 2012~2013, Weng Xuetian <wengxt@gmail.com>
+// 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 <string>
+
+#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 --git a/src/unix/fcitx5/mozc_connection.h b/src/unix/fcitx5/mozc_connection.h
new file mode 100644
index 00000000..4f7b09c2
--- /dev/null
+++ b/src/unix/fcitx5/mozc_connection.h
@@ -0,0 +1,72 @@
+// Copyright 2010-2012, Google Inc.
+// Copyright 2012~2013, Weng Xuetian <wengxt@gmail.com>
+// 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 <memory>
+#include <string>
+
+#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 --git a/src/unix/fcitx5/mozc_engine.cc b/src/unix/fcitx5/mozc_engine.cc
new file mode 100644
index 00000000..59c3b0aa
--- /dev/null
+++ b/src/unix/fcitx5/mozc_engine.cc
@@ -0,0 +1,273 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "unix/fcitx5/mozc_engine.h"
+
+#include <fcitx-utils/i18n.h>
+#include <fcitx-utils/log.h>
+#include <fcitx-utils/standardpath.h>
+#include <fcitx/inputcontext.h>
+#include <fcitx/inputcontextmanager.h>
+#include <fcitx/userinterfacemanager.h>
+#include <vector>
+
+#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 CompositionMode {
+  const char *name;
+  const char *icon;
+  const char *label;
+  const char *description;
+  mozc::commands::CompositionMode mode;
+} kPropCompositionModes[] = {
+    {
+        "mozc-mode-direct",
+        "mozc-direct.png",
+        "A",
+        N_("Direct"),
+        mozc::commands::DIRECT,
+    },
+    {
+        "mozc-mode-hiragana",
+        "mozc-hiragana.png",
+        "\xe3\x81\x82",  // Hiragana letter A in UTF-8.
+        N_("Hiragana"),
+        mozc::commands::HIRAGANA,
+    },
+    {
+        "mozc-mode-katakana_full",
+        "mozc-katakana_full.png",
+        "\xe3\x82\xa2",  // Katakana letter A.
+        N_("Full Katakana"),
+        mozc::commands::FULL_KATAKANA,
+    },
+    {
+
+        "mozc-mode-alpha_half",
+        "mozc-alpha_half.png",
+        "A",
+        N_("Half ASCII"),
+        mozc::commands::HALF_ASCII,
+    },
+    {
+
+        "mozc-mode-alpha_full",
+        "mozc-alpha_full.png",
+        "\xef\xbc\xa1",  // Full width ASCII letter A.
+        N_("Full ASCII"),
+        mozc::commands::FULL_ASCII,
+    },
+    {
+        "mozc-mode-katakana_full",
+        "mozc-katakana_half.png",
+        "\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 *ic) 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 stringutils::joinPath(
+      StandardPath::global().fcitxPath("pkgdatadir"), "mozc/icon",
+      kPropCompositionModes[mozc_state->GetCompositionMode()].icon);
+}
+
+MozcModeSubAction::MozcModeSubAction(MozcEngine *engine,
+                                     mozc::commands::CompositionMode mode)
+    : engine_(engine), mode_(mode) {
+  setShortText(kPropCompositionModes[mode].label);
+  setLongText(_(kPropCompositionModes[mode].description));
+  setIcon(stringutils::joinPath(StandardPath::global().fcitxPath("pkgdatadir"),
+                                "mozc/icon", 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, true);
+  return instance;
+}
+
+MozcEngine::MozcEngine(Instance *instance)
+    : instance_(Init(instance)),
+      connection_(std::make_unique<MozcConnection>()),
+      factory_([this](InputContext &ic) {
+        return new MozcState(&ic, connection_->CreateClient(), this);
+      }),
+      modeAction_(this) {
+  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(
+      stringutils::joinPath(StandardPath::global().fcitxPath("pkgdatadir"),
+                            "mozc/icon", "mozc-tool.png"));
+
+  int i = 0;
+  for (auto &modeAction : modeActions_) {
+    instance_->userInterfaceManager().registerAction(
+        kPropCompositionModes[i].name, &modeAction);
+    modeMenu_.addAction(&modeAction);
+    i++;
+  }
+
+  instance_->userInterfaceManager().registerAction("mozc-tool-config",
+                                                   &configToolAction_);
+  configToolAction_.setShortText(_("Configuration Tool"));
+  configToolAction_.connect<SimpleAction::Activated>([](InputContext *) {
+    mozc::Process::SpawnMozcProcess("mozc_tool", "--mode=config_dialog");
+  });
+
+  instance_->userInterfaceManager().registerAction("mozc-tool-dict",
+                                                   &dictionaryToolAction_);
+  dictionaryToolAction_.setShortText(_("Dictionary Tool"));
+  dictionaryToolAction_.connect<SimpleAction::Activated>([](InputContext *) {
+    mozc::Process::SpawnMozcProcess("mozc_tool", "--mode=dictionary_tool");
+  });
+
+  instance_->userInterfaceManager().registerAction("mozc-tool-handwriting",
+                                                   &handWritingAction_);
+  handWritingAction_.setShortText(_("Hand Writing"));
+  handWritingAction_.connect<SimpleAction::Activated>([](InputContext *) {
+    mozc::Process::SpawnMozcProcess("mozc_tool", "--mode=hand_writing");
+  });
+
+  instance_->userInterfaceManager().registerAction("mozc-tool-character",
+                                                   &characterPaletteAction_);
+  characterPaletteAction_.setShortText(_("Character Palette"));
+  characterPaletteAction_.connect<SimpleAction::Activated>([](InputContext *) {
+    mozc::Process::SpawnMozcProcess("mozc_tool", "--mode=character_palette");
+  });
+
+  instance_->userInterfaceManager().registerAction("mozc-tool-add",
+                                                   &addWordAction_);
+  addWordAction_.setShortText("Add Word");
+  addWordAction_.connect<SimpleAction::Activated>([](InputContext *) {
+    mozc::Process::SpawnMozcProcess("mozc_tool", "--mode=word_register_dialog");
+  });
+
+  instance_->userInterfaceManager().registerAction("mozc-tool-about",
+                                                   &aboutAction_);
+  aboutAction_.setShortText("About Mozc");
+  aboutAction_.connect<SimpleAction::Activated>([](InputContext *) {
+    mozc::Process::SpawnMozcProcess("mozc_tool", "--mode=about_dialog");
+  });
+
+  toolMenu_.addAction(&configToolAction_);
+  toolMenu_.addAction(&dictionaryToolAction_);
+  toolMenu_.addAction(&handWritingAction_);
+  toolMenu_.addAction(&characterPaletteAction_);
+  toolMenu_.addAction(&addWordAction_);
+  toolMenu_.addAction(&aboutAction_);
+
+  modeAction_.setMenu(&modeMenu_);
+  toolAction_.setMenu(&toolMenu_);
+}
+
+MozcEngine::~MozcEngine() {}
+
+void MozcEngine::reloadConfig() {}
+void MozcEngine::activate(const fcitx::InputMethodEntry &,
+                          fcitx::InputContextEvent &event) {
+  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 &entry,
+                            fcitx::InputContextEvent &event) {
+  auto ic = event.inputContext();
+  auto mozc_state = mozcState(ic);
+  mozc_state->FocusOut();
+  ic->statusArea().clearGroup(StatusGroup::InputMethod);
+}
+void MozcEngine::keyEvent(const InputMethodEntry &, KeyEvent &event) {
+  auto mozc_state = mozcState(event.inputContext());
+
+  // TODO: check layout
+  if (mozc_state->ProcessKeyEvent(event.rawKey().sym(), event.rawKey().code(),
+                                  event.rawKey().states(), false,
+                                  event.isRelease())) {
+    event.filterAndAccept();
+  }
+}
+
+void MozcEngine::reset(const InputMethodEntry &, InputContextEvent &event) {
+  auto mozc_state = mozcState(event.inputContext());
+  mozc_state->Reset();
+}
+
+void MozcEngine::save() {}
+
+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 (auto &modeAction : modeActions_) {
+    modeAction.update(ic);
+  }
+}
+
+AddonInstance *MozcEngine::clipboardAddon() { return clipboard(); }
+}  // namespace fcitx
+
+FCITX_ADDON_FACTORY(fcitx::MozcEngineFactory)
diff --git a/src/unix/fcitx5/mozc_engine.h b/src/unix/fcitx5/mozc_engine.h
new file mode 100644
index 00000000..d75c8dba
--- /dev/null
+++ b/src/unix/fcitx5/mozc_engine.h
@@ -0,0 +1,112 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+#ifndef _FCITX_UNIX_FCITX5_MOZC_ENGINE_H_
+#define _FCITX_UNIX_FCITX5_MOZC_ENGINE_H_
+
+#include <fcitx/action.h>
+#include <fcitx/addonfactory.h>
+#include <fcitx/addonmanager.h>
+#include <fcitx/inputmethodengine.h>
+#include <fcitx/instance.h>
+#include <fcitx/menu.h>
+
+#include "unix/fcitx5/mozc_state.h"
+
+namespace fcitx {
+
+class MozcConnection;
+class MozcResponseParser;
+class MozcEngine;
+
+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;
+
+  MozcState *mozcState(InputContext *ic);
+  AddonInstance *clipboardAddon();
+
+  void compositionModeUpdated(InputContext *ic);
+
+ private:
+  Instance *instance_;
+  std::unique_ptr<MozcConnection> connection_;
+  FactoryFor<MozcState> factory_;
+  MozcModeAction modeAction_;
+  SimpleAction toolAction_;
+  MozcModeSubAction modeActions_[mozc::commands::NUM_OF_COMPOSITIONS] = {
+      {this, mozc::commands::DIRECT},
+      {this, mozc::commands::HIRAGANA},
+      {this, mozc::commands::FULL_KATAKANA},
+      {this, mozc::commands::FULL_ASCII},
+      {this, mozc::commands::HALF_ASCII},
+      {this, mozc::commands::HALF_KATAKANA},
+  };
+
+  SimpleAction configToolAction_, dictionaryToolAction_, handWritingAction_,
+      characterPaletteAction_, addWordAction_, aboutAction_;
+  Menu toolMenu_;
+  Menu modeMenu_;
+
+  FCITX_ADDON_DEPENDENCY_LOADER(clipboard, instance_->addonManager());
+};
+
+class MozcEngineFactory : public AddonFactory {
+ public:
+  AddonInstance *create(AddonManager *manager) override {
+    return new MozcEngine(manager->instance());
+  }
+};
+}  // namespace fcitx
+
+#endif  // _FCITX_UNIX_FCITX5_MOZC_ENGINE_H_
diff --git a/src/unix/fcitx5/mozc_response_parser.cc b/src/unix/fcitx5/mozc_response_parser.cc
new file mode 100644
index 00000000..248416ed
--- /dev/null
+++ b/src/unix/fcitx5/mozc_response_parser.cc
@@ -0,0 +1,483 @@
+// Copyright 2010-2012, Google Inc.
+// Copyright 2012~2013, Weng Xuetian <wengxt@gmail.com>
+// 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 <fcitx-utils/i18n.h>
+#include <fcitx-utils/utf8.h>
+#include <fcitx/candidatelist.h>
+#include <fcitx/inputcontext.h>
+#include <fcitx/inputpanel.h>
+#include <string>
+#include <vector>
+
+#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();
+}
+
+string CreateDescriptionString(const string &description) {
+  return " [" + description + "]";
+}
+
+class MozcCandidateWord final : public CandidateWord {
+ public:
+  MozcCandidateWord(int id, 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) {
+    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;
+      }
+    }
+    if (candidates.has_direction() &&
+        candidates.direction() == mozc::commands::Candidates::HORIZONTAL) {
+      layout_ = CandidateLayoutHint::Horizontal;
+    }
+
+    int focused_index = -1;
+    cursor_ = -1;
+    if (candidates.has_focused_index()) {
+      focused_index = candidates.focused_index();
+    }
+
+    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();
+
+      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());
+      }
+
+      if (use_annotation && candidates.has_focused_index() &&
+          index == focused_index) {
+        if (candidate.has_information_id()) {
+          value +=
+              CreateDescriptionString(_("Press Ctrl+Alt+H to show usages."));
+        }
+        cursor_ = i;
+      }
+
+      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_shared<MozcCandidateWord>(id, value, engine));
+    }
+  }
+
+  const Text &label(int idx) const override {
+    checkIndex(idx);
+    return labels_[idx];
+  }
+
+  std::shared_ptr<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<Text> labels_;
+  bool hasPrev_ = false;
+  bool hasNext_ = false;
+  CandidateLayoutHint layout_ = CandidateLayoutHint::Vertical;
+  int cursor_ = -1;
+  std::vector<std::shared_ptr<CandidateWord>> candidateWords_;
+};
+
+}  // namespace
+
+MozcResponseParser::MozcResponseParser(MozcEngine *engine)
+    : engine_(engine), use_annotation_(false) {}
+
+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 string &url = response.url();
+    mozc_state->SetUrl(url);
+  }
+  LaunchTool(response, ic);
+  ExecuteCallback(response, ic);
+
+  return true;  // mozc consumed the key.
+}
+
+void MozcResponseParser::SetUseAnnotation(bool use_annotation) {
+  use_annotation_ = use_annotation;
+}
+
+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()) {
+    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<MozcCandidateList>(
+      candidates, ic, engine_, use_annotation_));
+
+  int focused_index = -1;
+  if (candidates.has_focused_index()) {
+    focused_index = candidates.focused_index();
+  }
+
+  if (focused_index >= 0) {
+    std::map<int32, std::pair<string, string>> 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();
+      }
+    }
+
+    for (int i = 0; i < candidates.candidate_size(); ++i) {
+      const mozc::commands::Candidates::Candidate &candidate =
+          candidates.candidate(i);
+      const uint32 index = candidate.index();
+      if (use_annotation_ && index == focused_index &&
+          candidate.has_information_id()) {
+        std::map<int32, std::pair<string, string>>::iterator it =
+            usage_map.find(candidate.information_id());
+        if (it != usage_map.end()) {
+          mozc_state->SetUsage(it->second.first, it->second.second);
+        }
+      }
+    }
+  }
+}
+
+void MozcResponseParser::ParsePreedit(const mozc::commands::Preedit &preedit,
+                                      uint32 position, InputContext *ic) const {
+  auto mozc_state = engine_->mozcState(ic);
+  Text preedit_text;
+  string s;
+
+  for (int i = 0; i < preedit.segment_size(); ++i) {
+    const mozc::commands::Preedit_Segment &segment = preedit.segment(i);
+    const 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 --git a/src/unix/fcitx5/mozc_response_parser.h b/src/unix/fcitx5/mozc_response_parser.h
new file mode 100644
index 00000000..8bb8366b
--- /dev/null
+++ b/src/unix/fcitx5/mozc_response_parser.h
@@ -0,0 +1,93 @@
+// Copyright 2010-2012, Google Inc.
+// Copyright 2012~2013, Weng Xuetian <wengxt@gmail.com>
+// 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;
+
+  // Setter for use_annotation_. If use_annotation_ is true, ParseCandidates()
+  // uses annotation infomation.
+  void SetUseAnnotation(bool use_annotation);
+
+ 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_;
+  bool use_annotation_;
+
+  DISALLOW_COPY_AND_ASSIGN(MozcResponseParser);
+};
+
+}  // namespace fcitx
+
+#endif  // MOZC_UNIX_FCITX_MOZC_RESPONSE_PARSER_H_
diff --git a/src/unix/fcitx5/mozc_state.cc b/src/unix/fcitx5/mozc_state.cc
new file mode 100644
index 00000000..3dc3bdd2
--- /dev/null
+++ b/src/unix/fcitx5/mozc_state.cc
@@ -0,0 +1,441 @@
+// Copyright 2012~2013, Weng Xuetian <wengxt@gmail.com>
+// 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 <fcitx-utils/i18n.h>
+#include <fcitx-utils/log.h>
+#include <fcitx-utils/stringutils.h>
+#include <fcitx/candidatelist.h>
+#include <fcitx/inputpanel.h>
+#include <string>
+
+#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 {
+
+const struct CompositionMode {
+  const char* icon;
+  const char* label;
+  const char* description;
+  mozc::commands::CompositionMode mode;
+} kPropCompositionModes[] = {
+    {
+        "mozc-direct.png",
+        "A",
+        N_("Direct"),
+        mozc::commands::DIRECT,
+    },
+    {
+        "mozc-hiragana.png",
+        "\xe3\x81\x82",  // Hiragana letter A in UTF-8.
+        N_("Hiragana"),
+        mozc::commands::HIRAGANA,
+    },
+    {
+        "mozc-katakana_full.png",
+        "\xe3\x82\xa2",  // Katakana letter A.
+        N_("Full Katakana"),
+        mozc::commands::FULL_KATAKANA,
+    },
+    {
+        "mozc-alpha_half.png",
+        "A",
+        N_("Half ASCII"),
+        mozc::commands::HALF_ASCII,
+    },
+    {
+        "mozc-alpha_full.png",
+        "\xef\xbc\xa1",  // Full width ASCII letter A.
+        N_("Full ASCII"),
+        mozc::commands::FULL_ASCII,
+    },
+    {
+        "mozc-katakana_half.png",
+        "\xef\xbd\xb1",  // Half width Katakana letter A.
+        N_("Half Katakana"),
+        mozc::commands::HALF_KATAKANA,
+    },
+};
+const size_t kNumCompositionModes = arraysize(kPropCompositionModes);
+
+// This array must correspond with the CompositionMode enum in the
+// mozc/session/command.proto file.
+static_assert(mozc::commands::NUM_OF_COMPOSITIONS ==
+                  arraysize(kPropCompositionModes),
+              "number of modes must match");
+
+}  // namespace
+
+namespace fcitx {
+
+// For unittests.
+MozcState::MozcState(InputContext* ic, mozc::client::ClientInterface* client,
+                     MozcEngine* engine)
+    : ic_(ic),
+      client_(client),
+      engine_(engine),
+      handler_(std::make_unique<KeyEventHandler>()),
+      parser_(std::make_unique<MozcResponseParser>(engine_)) {
+  // mozc::Logging::SetVerboseLevel(1);
+  VLOG(1) << "MozcState created.";
+  const bool is_vertical = true;
+  parser_->SetUseAnnotation(is_vertical);
+
+  if (client_->EnsureConnection()) {
+    UpdatePreeditMethod();
+  }
+}
+
+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, 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,
+                             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,
+                                       string* out_error) const {
+  DCHECK(out);
+  DCHECK(out_error);
+
+  mozc::commands::SessionCommand command;
+  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,
+                               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,
+                                  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::None, layout_is_jp,
+                      false);
+    }
+    return true;
+  }
+
+  if (normalized_key.check(Key(FcitxKey_H, KeyState::Ctrl_Alt))) {
+    if (!title_.empty() || !description_.empty()) {
+      DisplayUsage();
+      return true;
+    }
+  }
+
+  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;
+
+  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";
+  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";
+  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()";
+  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();
+  // TODO(yusukes): Call client::SyncData() like ibus-mozc.
+}
+
+bool MozcState::ParseResponse(const mozc::commands::Output& raw_response) {
+  ClearAll();
+  const bool consumed = parser_->ParseResponse(raw_response, ic_);
+  if (!consumed) {
+    VLOG(1) << "The input was not consumed by Mozc.";
+  }
+  OpenUrl();
+  DrawAll();
+  return consumed;
+}
+
+void MozcState::SetResultString(const string& result_string) {
+  ic_->commitString(result_string);
+}
+
+void MozcState::SetPreeditInfo(Text preedit_info) {
+  preedit_ = std::move(preedit_info);
+}
+
+void MozcState::SetAuxString(const string& str) { aux_ = str; }
+
+void MozcState::SetCompositionMode(mozc::commands::CompositionMode mode) {
+  composition_mode_ = mode;
+  DCHECK(composition_mode_ < kNumCompositionModes);
+  engine_->compositionModeUpdated(ic_);
+}
+
+void MozcState::SendCompositionMode(mozc::commands::CompositionMode mode) {
+  // Send the SWITCH_INPUT_MODE command.
+  string error;
+  mozc::commands::Output raw_response;
+  if (TrySendCompositionMode(kPropCompositionModes[mode].mode, &raw_response,
+                             &error)) {
+    auto oldMode = composition_mode_;
+    parser_->ParseResponse(raw_response, ic_);
+    if (oldMode != composition_mode_) {
+      engine_->instance()->showInputMethodInformation(ic_);
+    }
+  }
+}
+
+void MozcState::SetUrl(const string& url) { url_ = url; }
+
+void MozcState::ClearAll() {
+  SetPreeditInfo(Text());
+  SetAuxString("");
+  ic_->inputPanel().reset();
+  url_.clear();
+}
+
+void MozcState::DrawAll() {
+  Text preedit = preedit_;
+  if (!aux_.empty()) {
+    string aux;
+    if (preedit.size()) {
+      aux += " ";
+    }
+    aux += "[";
+    aux += aux_;
+    aux += "]";
+    preedit.append(aux);
+  }
+  ic_->inputPanel().setPreedit(std::move(preedit));
+  ic_->inputPanel().setClientPreedit(preedit_);
+  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) {
+  string error;
+  return TrySendRawCommand(session_command, new_output, &error);
+}
+
+void MozcState::SetUsage(const string& title, const string& description) {
+  title_ = title;
+  description_ = description;
+}
+
+void MozcState::DisplayUsage() {
+  displayUsage_ = true;
+
+  ic_->inputPanel().reset();
+  auto candidateList = std::make_unique<DisplayOnlyCandidateList>();
+
+  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 --git a/src/unix/fcitx5/mozc_state.h b/src/unix/fcitx5/mozc_state.h
new file mode 100644
index 00000000..01eb59a1
--- /dev/null
+++ b/src/unix/fcitx5/mozc_state.h
@@ -0,0 +1,165 @@
+// Copyright 2012~2013, Weng Xuetian <wengxt@gmail.com>
+// 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 <memory>
+
+#include <fcitx-utils/key.h>
+#include <fcitx/inputcontextproperty.h>
+#include <fcitx/text.h>
+
+#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 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 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 string& url);
+
+  const string& GetIconFile(const 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 string& title, const 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, string* out_error) const;
+
+  // Sends 'mouse click on the candidate window' event to the server.
+  bool TrySendClick(int32 unique_id, mozc::commands::Output* out,
+                    string* out_error) const;
+
+  // Sends composition mode to the server.
+  bool TrySendCompositionMode(mozc::commands::CompositionMode mode,
+                              mozc::commands::Output* out,
+                              string* out_error) const;
+
+  // Sends a command to the server.
+  bool TrySendCommand(mozc::commands::SessionCommand::CommandType type,
+                      mozc::commands::Output* out, string* out_error) const;
+
+  bool TrySendRawCommand(const mozc::commands::SessionCommand& command,
+                         mozc::commands::Output* out, 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<mozc::client::ClientInterface> 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<KeyEventHandler> handler_;
+  const std::unique_ptr<MozcResponseParser> parser_;
+
+  bool displayUsage_ = false;
+  Text preedit_;
+  string aux_;  // error tooltip, or candidate window title.
+  string url_;  // URL to be opened by a browser.
+  string description_;
+  string title_;
+
+  DISALLOW_COPY_AND_ASSIGN(MozcState);
+};
+
+}  // namespace fcitx
+
+#endif  // MOZC_UNIX_FCITX_FCITX_MOZC_H_
diff --git a/src/unix/fcitx5/po/LINGUAS b/src/unix/fcitx5/po/LINGUAS
new file mode 100644
index 00000000..68faae50
--- /dev/null
+++ b/src/unix/fcitx5/po/LINGUAS
@@ -0,0 +1,9 @@
+
+ca
+da
+de
+ja
+ko
+ru
+zh_CN
+zh_TW
diff --git a/src/unix/fcitx5/po/ca.po b/src/unix/fcitx5/po/ca.po
new file mode 100644
index 00000000..29dc3af8
--- /dev/null
+++ b/src/unix/fcitx5/po/ca.po
@@ -0,0 +1,80 @@
+# 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:
+# Robert Antoni Buj Gelonch <rbuj@fedoraproject.org>, 2017
+# csslayer <wengxt@gmail.com>, 2017
+msgid ""
+msgstr ""
+"Project-Id-Version: fcitx5-mozc\n"
+"Report-Msgid-Bugs-To: fcitx-dev@googlegroups.com\n"
+"POT-Creation-Date: 2017-12-20 00:01-0800\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: csslayer <wengxt@gmail.com>, 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.cc:174
+msgid "Character Palette"
+msgstr "Paleta de caràcters"
+
+#: mozc_engine.cc:78
+msgid "Composition Mode"
+msgstr "Mode de composició"
+
+#: mozc_engine.cc:153
+msgid "Configuration Tool"
+msgstr "Eina de configuració"
+
+#: mozc_engine.cc:160
+msgid "Dictionary Tool"
+msgstr "Eina de diccionari"
+
+#: mozc_state.cc:61 mozc_engine.cc:45
+msgid "Direct"
+msgstr "Directe"
+
+#. Full width ASCII letter A.
+#: mozc_state.cc:80 mozc_engine.cc:67
+msgid "Full ASCII"
+msgstr "ASCII complet"
+
+#. Katakana letter A.
+#: mozc_state.cc:71 mozc_engine.cc:56
+msgid "Full Katakana"
+msgstr "Katakana complet"
+
+#: mozc_state.cc:74 mozc_engine.cc:60
+msgid "Half ASCII"
+msgstr "ASCII mig"
+
+#. Half width Katakana letter A.
+#: mozc_state.cc:85 mozc_engine.cc:72
+msgid "Half Katakana"
+msgstr "Mig katakana"
+
+#: mozc_engine.cc:167
+msgid "Hand Writing"
+msgstr "Escriptura a mà"
+
+#. Hiragana letter A in UTF-8.
+#: mozc_state.cc:66 mozc_engine.cc:51
+msgid "Hiragana"
+msgstr "Hiragana"
+
+#: mozc_response_parser.cc:144
+msgid "Press Ctrl+Alt+H to show usages."
+msgstr "Premeu Ctrl+Alt+H per mostrar els usos."
+
+#: mozc_state.cc:426
+msgid "Press Escape to go back"
+msgstr "Premeu Esc per tornar"
+
+#: mozc_engine.cc:137 mozc_engine.cc:138
+msgid "Tool"
+msgstr "Eina"
diff --git a/src/unix/fcitx5/po/da.po b/src/unix/fcitx5/po/da.po
new file mode 100644
index 00000000..679bce1f
--- /dev/null
+++ b/src/unix/fcitx5/po/da.po
@@ -0,0 +1,79 @@
+# 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 <scootergrisen@gmail.com>, 2017
+msgid ""
+msgstr ""
+"Project-Id-Version: fcitx5-mozc\n"
+"Report-Msgid-Bugs-To: fcitx-dev@googlegroups.com\n"
+"POT-Creation-Date: 2017-12-12 09:52-0800\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: scootergrisen <scootergrisen@gmail.com>, 2017\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.cc:174
+msgid "Character Palette"
+msgstr "Tegnpalet"
+
+#: mozc_engine.cc:78
+msgid "Composition Mode"
+msgstr "Kompositionstilstand"
+
+#: mozc_engine.cc:153
+msgid "Configuration Tool"
+msgstr "Konfigurationsværktøj"
+
+#: mozc_engine.cc:160
+msgid "Dictionary Tool"
+msgstr "Ordbogsværktøj"
+
+#: mozc_state.cc:61 mozc_engine.cc:45
+msgid "Direct"
+msgstr "Direkte"
+
+#. Full width ASCII letter A.
+#: mozc_state.cc:80 mozc_engine.cc:67
+msgid "Full ASCII"
+msgstr "Fuld ASCII"
+
+#. Katakana letter A.
+#: mozc_state.cc:71 mozc_engine.cc:56
+msgid "Full Katakana"
+msgstr "Fuld Katakana"
+
+#: mozc_state.cc:74 mozc_engine.cc:60
+msgid "Half ASCII"
+msgstr "Halv ASCII"
+
+#. Half width Katakana letter A.
+#: mozc_state.cc:85 mozc_engine.cc:72
+msgid "Half Katakana"
+msgstr "Halv Katakana"
+
+#: mozc_engine.cc:167
+msgid "Hand Writing"
+msgstr "Håndskrift"
+
+#. Hiragana letter A in UTF-8.
+#: mozc_state.cc:66 mozc_engine.cc:51
+msgid "Hiragana"
+msgstr "Hiragana"
+
+#: mozc_response_parser.cc:144
+msgid "Press Ctrl+Alt+H to show usages."
+msgstr "Tryk på Ctrl+Alt+H for at vise anvendelser."
+
+#: mozc_state.cc:426
+msgid "Press Escape to go back"
+msgstr "Tryk på Escape for at gå tilbage"
+
+#: mozc_engine.cc:137 mozc_engine.cc:138
+msgid "Tool"
+msgstr "Værktøj"
diff --git a/src/unix/fcitx5/po/de.po b/src/unix/fcitx5/po/de.po
new file mode 100644
index 00000000..e13a6852
--- /dev/null
+++ b/src/unix/fcitx5/po/de.po
@@ -0,0 +1,79 @@
+# 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 <wengxt@gmail.com>, 2017
+msgid ""
+msgstr ""
+"Project-Id-Version: fcitx5-mozc\n"
+"Report-Msgid-Bugs-To: fcitx-dev@googlegroups.com\n"
+"POT-Creation-Date: 2017-12-12 09:52-0800\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: csslayer <wengxt@gmail.com>, 2017\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.cc:174
+msgid "Character Palette"
+msgstr "Palette Symbole"
+
+#: mozc_engine.cc:78
+msgid "Composition Mode"
+msgstr "Kompositionsmodus"
+
+#: mozc_engine.cc:153
+msgid "Configuration Tool"
+msgstr "Konfigurationswerkzeug"
+
+#: mozc_engine.cc:160
+msgid "Dictionary Tool"
+msgstr "Wörterbuchwerkzeug"
+
+#: mozc_state.cc:61 mozc_engine.cc:45
+msgid "Direct"
+msgstr "Direkt"
+
+#. Full width ASCII letter A.
+#: mozc_state.cc:80 mozc_engine.cc:67
+msgid "Full ASCII"
+msgstr "7-Bit ASCII (Full ASCII)"
+
+#. Katakana letter A.
+#: mozc_state.cc:71 mozc_engine.cc:56
+msgid "Full Katakana"
+msgstr "Normalbreite Katakana"
+
+#: mozc_state.cc:74 mozc_engine.cc:60
+msgid "Half ASCII"
+msgstr "6-Bit ASCII (Half ASCII)"
+
+#. Half width Katakana letter A.
+#: mozc_state.cc:85 mozc_engine.cc:72
+msgid "Half Katakana"
+msgstr "Halbbreite Katakana"
+
+#: mozc_engine.cc:167
+msgid "Hand Writing"
+msgstr "Eingabe Handschrift"
+
+#. Hiragana letter A in UTF-8.
+#: mozc_state.cc:66 mozc_engine.cc:51
+msgid "Hiragana"
+msgstr "Hiragana"
+
+#: mozc_response_parser.cc:144
+msgid "Press Ctrl+Alt+H to show usages."
+msgstr "Ctrl+Alt+H um die Hilfe anzuzeigen"
+
+#: mozc_state.cc:426
+msgid "Press Escape to go back"
+msgstr "ESC drücken um zurück zu kehren"
+
+#: mozc_engine.cc:137 mozc_engine.cc:138
+msgid "Tool"
+msgstr "Werkzeug"
diff --git a/src/unix/fcitx5/po/fcitx5-mozc.pot b/src/unix/fcitx5/po/fcitx5-mozc.pot
new file mode 100644
index 00000000..c18c29ac
--- /dev/null
+++ b/src/unix/fcitx5/po/fcitx5-mozc.pot
@@ -0,0 +1,76 @@
+# 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: 2017-12-12 09:52-0800\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: LANG\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: mozc_engine.cc:174
+msgid "Character Palette"
+msgstr ""
+
+#: mozc_engine.cc:78
+msgid "Composition Mode"
+msgstr ""
+
+#: mozc_engine.cc:153
+msgid "Configuration Tool"
+msgstr ""
+
+#: mozc_engine.cc:160
+msgid "Dictionary Tool"
+msgstr ""
+
+#: mozc_state.cc:61 mozc_engine.cc:45
+msgid "Direct"
+msgstr ""
+
+#. Full width ASCII letter A.
+#: mozc_state.cc:80 mozc_engine.cc:67
+msgid "Full ASCII"
+msgstr ""
+
+#. Katakana letter A.
+#: mozc_state.cc:71 mozc_engine.cc:56
+msgid "Full Katakana"
+msgstr ""
+
+#: mozc_state.cc:74 mozc_engine.cc:60
+msgid "Half ASCII"
+msgstr ""
+
+#. Half width Katakana letter A.
+#: mozc_state.cc:85 mozc_engine.cc:72
+msgid "Half Katakana"
+msgstr ""
+
+#: mozc_engine.cc:167
+msgid "Hand Writing"
+msgstr ""
+
+#. Hiragana letter A in UTF-8.
+#: mozc_state.cc:66 mozc_engine.cc:51
+msgid "Hiragana"
+msgstr ""
+
+#: mozc_response_parser.cc:144
+msgid "Press Ctrl+Alt+H to show usages."
+msgstr ""
+
+#: mozc_state.cc:426
+msgid "Press Escape to go back"
+msgstr ""
+
+#: mozc_engine.cc:137 mozc_engine.cc:138
+msgid "Tool"
+msgstr ""
diff --git a/src/unix/fcitx5/po/ja.po b/src/unix/fcitx5/po/ja.po
new file mode 100644
index 00000000..03dcef0b
--- /dev/null
+++ b/src/unix/fcitx5/po/ja.po
@@ -0,0 +1,79 @@
+# 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 <wengxt@gmail.com>, 2017
+msgid ""
+msgstr ""
+"Project-Id-Version: fcitx5-mozc\n"
+"Report-Msgid-Bugs-To: fcitx-dev@googlegroups.com\n"
+"POT-Creation-Date: 2017-12-12 09:52-0800\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: csslayer <wengxt@gmail.com>, 2017\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.cc:174
+msgid "Character Palette"
+msgstr "文字パレット"
+
+#: mozc_engine.cc:78
+msgid "Composition Mode"
+msgstr "変換モード"
+
+#: mozc_engine.cc:153
+msgid "Configuration Tool"
+msgstr "設定ツール"
+
+#: mozc_engine.cc:160
+msgid "Dictionary Tool"
+msgstr "辞書ツール"
+
+#: mozc_state.cc:61 mozc_engine.cc:45
+msgid "Direct"
+msgstr "直接入力"
+
+#. Full width ASCII letter A.
+#: mozc_state.cc:80 mozc_engine.cc:67
+msgid "Full ASCII"
+msgstr "全角英数"
+
+#. Katakana letter A.
+#: mozc_state.cc:71 mozc_engine.cc:56
+msgid "Full Katakana"
+msgstr "全角カタカナ"
+
+#: mozc_state.cc:74 mozc_engine.cc:60
+msgid "Half ASCII"
+msgstr "半角英数"
+
+#. Half width Katakana letter A.
+#: mozc_state.cc:85 mozc_engine.cc:72
+msgid "Half Katakana"
+msgstr "半角カタカナ"
+
+#: mozc_engine.cc:167
+msgid "Hand Writing"
+msgstr "手書き文字認識"
+
+#. Hiragana letter A in UTF-8.
+#: mozc_state.cc:66 mozc_engine.cc:51
+msgid "Hiragana"
+msgstr "ひらがな"
+
+#: mozc_response_parser.cc:144
+msgid "Press Ctrl+Alt+H to show usages."
+msgstr "Ctrl+Alt+H キーを押して用例を表示"
+
+#: mozc_state.cc:426
+msgid "Press Escape to go back"
+msgstr "Escキーを押して戻る"
+
+#: mozc_engine.cc:137 mozc_engine.cc:138
+msgid "Tool"
+msgstr "ツール"
diff --git a/src/unix/fcitx5/po/ko.po b/src/unix/fcitx5/po/ko.po
new file mode 100644
index 00000000..f6c6c78c
--- /dev/null
+++ b/src/unix/fcitx5/po/ko.po
@@ -0,0 +1,79 @@
+# 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 <wengxt@gmail.com>, 2017
+msgid ""
+msgstr ""
+"Project-Id-Version: fcitx5-mozc\n"
+"Report-Msgid-Bugs-To: fcitx-dev@googlegroups.com\n"
+"POT-Creation-Date: 2017-12-12 09:52-0800\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: csslayer <wengxt@gmail.com>, 2017\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.cc:174
+msgid "Character Palette"
+msgstr "글자 팔레트"
+
+#: mozc_engine.cc:78
+msgid "Composition Mode"
+msgstr "조합 모드"
+
+#: mozc_engine.cc:153
+msgid "Configuration Tool"
+msgstr "설정 도구"
+
+#: mozc_engine.cc:160
+msgid "Dictionary Tool"
+msgstr "사전 도구"
+
+#: mozc_state.cc:61 mozc_engine.cc:45
+msgid "Direct"
+msgstr "직접입력"
+
+#. Full width ASCII letter A.
+#: mozc_state.cc:80 mozc_engine.cc:67
+msgid "Full ASCII"
+msgstr "전각 아스키"
+
+#. Katakana letter A.
+#: mozc_state.cc:71 mozc_engine.cc:56
+msgid "Full Katakana"
+msgstr "전각 가타가나"
+
+#: mozc_state.cc:74 mozc_engine.cc:60
+msgid "Half ASCII"
+msgstr "반각 아스키"
+
+#. Half width Katakana letter A.
+#: mozc_state.cc:85 mozc_engine.cc:72
+msgid "Half Katakana"
+msgstr "반각 가타가나"
+
+#: mozc_engine.cc:167
+msgid "Hand Writing"
+msgstr "손 글씨"
+
+#. Hiragana letter A in UTF-8.
+#: mozc_state.cc:66 mozc_engine.cc:51
+msgid "Hiragana"
+msgstr "히라가나"
+
+#: mozc_response_parser.cc:144
+msgid "Press Ctrl+Alt+H to show usages."
+msgstr "사용법을 보려면 Ctrl+Alt+H를 누르세요."
+
+#: mozc_state.cc:426
+msgid "Press Escape to go back"
+msgstr "돌아가려면 ESC를 누르세요"
+
+#: mozc_engine.cc:137 mozc_engine.cc:138
+msgid "Tool"
+msgstr "도구"
diff --git a/src/unix/fcitx5/po/ru.po b/src/unix/fcitx5/po/ru.po
new file mode 100644
index 00000000..22c312dd
--- /dev/null
+++ b/src/unix/fcitx5/po/ru.po
@@ -0,0 +1,81 @@
+# 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 <wengxt@gmail.com>, 2017
+msgid ""
+msgstr ""
+"Project-Id-Version: fcitx5-mozc\n"
+"Report-Msgid-Bugs-To: fcitx-dev@googlegroups.com\n"
+"POT-Creation-Date: 2017-12-12 09:52-0800\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: csslayer <wengxt@gmail.com>, 2017\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.cc:174
+msgid "Character Palette"
+msgstr "Палитра символов"
+
+#: mozc_engine.cc:78
+msgid "Composition Mode"
+msgstr "Режим композиции"
+
+#: mozc_engine.cc:153
+msgid "Configuration Tool"
+msgstr "Инструмент настройки"
+
+#: mozc_engine.cc:160
+msgid "Dictionary Tool"
+msgstr "Инструмент словаря"
+
+#: mozc_state.cc:61 mozc_engine.cc:45
+msgid "Direct"
+msgstr "Прямой"
+
+#. Full width ASCII letter A.
+#: mozc_state.cc:80 mozc_engine.cc:67
+msgid "Full ASCII"
+msgstr "Полный "
+
+#. Katakana letter A.
+#: mozc_state.cc:71 mozc_engine.cc:56
+msgid "Full Katakana"
+msgstr "Полная катакана"
+
+#: mozc_state.cc:74 mozc_engine.cc:60
+msgid "Half ASCII"
+msgstr "Половинный "
+
+#. Half width Katakana letter A.
+#: mozc_state.cc:85 mozc_engine.cc:72
+msgid "Half Katakana"
+msgstr "Половинная катакана"
+
+#: mozc_engine.cc:167
+msgid "Hand Writing"
+msgstr "Ручное письмо"
+
+#. Hiragana letter A in UTF-8.
+#: mozc_state.cc:66 mozc_engine.cc:51
+msgid "Hiragana"
+msgstr "Хирагана"
+
+#: mozc_response_parser.cc:144
+msgid "Press Ctrl+Alt+H to show usages."
+msgstr "Нажмите Ctrl+Alt+H, чтобы показать использование."
+
+#: mozc_state.cc:426
+msgid "Press Escape to go back"
+msgstr "Нажмите  для перехода назад"
+
+#: mozc_engine.cc:137 mozc_engine.cc:138
+msgid "Tool"
+msgstr "Инструмент"
diff --git a/src/unix/fcitx5/po/zh_CN.po b/src/unix/fcitx5/po/zh_CN.po
new file mode 100644
index 00000000..90d282cf
--- /dev/null
+++ b/src/unix/fcitx5/po/zh_CN.po
@@ -0,0 +1,80 @@
+# 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 <wengxt@gmail.com>, 2017
+msgid ""
+msgstr ""
+"Project-Id-Version: fcitx5-mozc\n"
+"Report-Msgid-Bugs-To: fcitx-dev@googlegroups.com\n"
+"POT-Creation-Date: 2017-12-12 09:52-0800\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: csslayer <wengxt@gmail.com>, 2017\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.cc:174
+msgid "Character Palette"
+msgstr "字符映射表"
+
+#: mozc_engine.cc:78
+msgid "Composition Mode"
+msgstr "编辑模式"
+
+#: mozc_engine.cc:153
+msgid "Configuration Tool"
+msgstr "配置工具"
+
+#: mozc_engine.cc:160
+msgid "Dictionary Tool"
+msgstr "词典工具"
+
+#: mozc_state.cc:61 mozc_engine.cc:45
+msgid "Direct"
+msgstr "直接键盘输入"
+
+#. Full width ASCII letter A.
+#: mozc_state.cc:80 mozc_engine.cc:67
+msgid "Full ASCII"
+msgstr "全角 ASCII"
+
+#. Katakana letter A.
+#: mozc_state.cc:71 mozc_engine.cc:56
+msgid "Full Katakana"
+msgstr "全角片假名"
+
+#: mozc_state.cc:74 mozc_engine.cc:60
+msgid "Half ASCII"
+msgstr "半角 ASCII"
+
+#. Half width Katakana letter A.
+#: mozc_state.cc:85 mozc_engine.cc:72
+msgid "Half Katakana"
+msgstr "半角片假名"
+
+#: mozc_engine.cc:167
+msgid "Hand Writing"
+msgstr "手写输入"
+
+#. Hiragana letter A in UTF-8.
+#: mozc_state.cc:66 mozc_engine.cc:51
+msgid "Hiragana"
+msgstr "平假名"
+
+#: mozc_response_parser.cc:144
+msgid "Press Ctrl+Alt+H to show usages."
+msgstr "按下 Ctrl+Alt+H 显示用法。"
+
+#: mozc_state.cc:426
+msgid "Press Escape to go back"
+msgstr "按下 Escape 返回"
+
+#: mozc_engine.cc:137 mozc_engine.cc:138
+msgid "Tool"
+msgstr "工具"
diff --git a/src/unix/fcitx5/po/zh_TW.po b/src/unix/fcitx5/po/zh_TW.po
new file mode 100644
index 00000000..5b58a31e
--- /dev/null
+++ b/src/unix/fcitx5/po/zh_TW.po
@@ -0,0 +1,80 @@
+# 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 <wengxt@gmail.com>, 2017
+msgid ""
+msgstr ""
+"Project-Id-Version: fcitx5-mozc\n"
+"Report-Msgid-Bugs-To: fcitx-dev@googlegroups.com\n"
+"POT-Creation-Date: 2017-12-12 09:52-0800\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: csslayer <wengxt@gmail.com>, 2017\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.cc:174
+msgid "Character Palette"
+msgstr "字符映射表"
+
+#: mozc_engine.cc:78
+msgid "Composition Mode"
+msgstr "編輯模式"
+
+#: mozc_engine.cc:153
+msgid "Configuration Tool"
+msgstr "設定工具"
+
+#: mozc_engine.cc:160
+msgid "Dictionary Tool"
+msgstr "字典工具"
+
+#: mozc_state.cc:61 mozc_engine.cc:45
+msgid "Direct"
+msgstr "直接鍵盤輸入"
+
+#. Full width ASCII letter A.
+#: mozc_state.cc:80 mozc_engine.cc:67
+msgid "Full ASCII"
+msgstr "全形 ASCII"
+
+#. Katakana letter A.
+#: mozc_state.cc:71 mozc_engine.cc:56
+msgid "Full Katakana"
+msgstr "全形片假名"
+
+#: mozc_state.cc:74 mozc_engine.cc:60
+msgid "Half ASCII"
+msgstr "半形 ASCII"
+
+#. Half width Katakana letter A.
+#: mozc_state.cc:85 mozc_engine.cc:72
+msgid "Half Katakana"
+msgstr "半形片假名"
+
+#: mozc_engine.cc:167
+msgid "Hand Writing"
+msgstr "手寫輸入"
+
+#. Hiragana letter A in UTF-8.
+#: mozc_state.cc:66 mozc_engine.cc:51
+msgid "Hiragana"
+msgstr "平假名"
+
+#: mozc_response_parser.cc:144
+msgid "Press Ctrl+Alt+H to show usages."
+msgstr "按下 Ctrl+Alt+H 顯示用法。"
+
+#: mozc_state.cc:426
+msgid "Press Escape to go back"
+msgstr "按下 Escape 返回"
+
+#: mozc_engine.cc:137 mozc_engine.cc:138
+msgid "Tool"
+msgstr "工具"
diff --git a/src/unix/fcitx5/surrounding_text_util.cc b/src/unix/fcitx5/surrounding_text_util.cc
new file mode 100644
index 00000000..b4847fc2
--- /dev/null
+++ b/src/unix/fcitx5/surrounding_text_util.cc
@@ -0,0 +1,220 @@
+// 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 <fcitx-module/clipboard/clipboard_public.h>
+#include <fcitx/inputcontext.h>
+#include <limits>
+#include <string>
+
+#include "base/logging.h"
+#include "base/port.h"
+#include "base/util.h"
+
+namespace fcitx {
+
+using namespace mozc;
+
+bool SurroundingTextUtil::GetSafeDelta(uint from, uint to, int32 *delta) {
+  DCHECK(delta);
+
+  static_assert(sizeof(int64) >= sizeof(uint),
+                "int64 must be sufficient to store a guint value.");
+  static_assert(sizeof(int64) == sizeof(llabs(0)),
+                "|llabs(0)| must returns a 64-bit integer.");
+  const int64 kInt32AbsMax =
+      llabs(static_cast<int64>(std::numeric_limits<int32>::max()));
+  const int64 kInt32AbsMin =
+      llabs(static_cast<int64>(std::numeric_limits<int32>::min()));
+  const int64 kInt32SafeAbsMax = std::min(kInt32AbsMax, kInt32AbsMin);
+
+  const int64 diff = static_cast<int64>(from) - static_cast<int64>(to);
+  if (llabs(diff) > kInt32SafeAbsMax) {
+    return false;
+  }
+
+  *delta = static_cast<int32>(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 string &surrounding_text,
+                            const string &selected_text,
+                            size_t selected_chars_len, uint cursor_pos,
+                            uint *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 string &surrounding_text,
+                             const string &selected_text,
+                             size_t selected_chars_len, uint cursor_pos,
+                             uint *anchor_pos) {
+  if (cursor_pos < selected_chars_len) {
+    return false;
+  }
+
+  ConstChar32Iterator iter(surrounding_text);
+  // Skip |iter| to (potential) anchor pos.
+  const uint 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 string &surrounding_text, const string &selected_text,
+    uint cursor_pos, uint *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();
+  uint cursor_pos = ic->surroundingText().cursor();
+  uint anchor_pos = ic->surroundingText().anchor();
+
+  if (cursor_pos == anchor_pos && clipboard) {
+    string primary = clipboard->call<IClipboard::primary>(ic);
+    if (!primary.empty()) {
+      uint 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);
+  Util::SubStringPiece(surrounding_text, 0, selection_start)
+      .CopyToString(&info->preceding_text);
+  Util::SubStringPiece(surrounding_text, selection_start, selection_length)
+      .CopyToString(&info->selection_text);
+  Util::SubStringPiece(surrounding_text, selection_start + selection_length)
+      .CopyToString(&info->following_text);
+  return true;
+}
+
+}  // namespace fcitx
diff --git a/src/unix/fcitx5/surrounding_text_util.h b/src/unix/fcitx5/surrounding_text_util.h
new file mode 100644
index 00000000..68a23b46
--- /dev/null
+++ b/src/unix/fcitx5/surrounding_text_util.h
@@ -0,0 +1,84 @@
+// 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 <fcitx/inputcontext.h>
+#include <string>
+
+#include "base/port.h"
+
+namespace fcitx {
+
+class AddonInstance;
+
+struct SurroundingTextInfo {
+  SurroundingTextInfo() : relative_selected_length(0) {}
+
+  int32 relative_selected_length;
+  string preceding_text;
+  string selection_text;
+  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(uint from, uint 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 string &surrounding_text,
+                                        const string &selected_text,
+                                        uint cursor_pos, uint *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_
openSUSE Build Service is sponsored by