diff --git a/src/unix/fcitx/eim.cc b/src/unix/fcitx/eim.cc
new file mode 100644
index 0000000..99cab07
--- /dev/null
+++ b/src/unix/fcitx/eim.cc
@@ -0,0 +1,138 @@
+/***************************************************************************
+ *   Copyright (C) 2012~2012 by CSSlayer                                   *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.              *
+ ***************************************************************************/
+
+#include <fcitx/instance.h>
+#include <fcitx/ime.h>
+#include <fcitx/hook.h>
+#include <fcitx-config/xdg.h>
+#include "fcitx_mozc.h"
+#include "mozc_connection.h"
+#include "mozc_response_parser.h"
+
+typedef struct _FcitxMozcState {
+    mozc::fcitx::FcitxMozc* mozc;
+} 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 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 void* FcitxMozcCreate(FcitxInstance* instance)
+{
+    FcitxMozcState* mozcState = (FcitxMozcState*) fcitx_utils_malloc0(sizeof(FcitxMozcState));
+    bindtextdomain("fcitx-keyboard", LOCALEDIR);
+
+    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);
+
+    FcitxInstanceRegisterIM(instance,
+        mozcState,
+        "mozc",
+        "Mozc",
+        mozcState->mozc->GetIconFile("mozc.png").c_str(),
+        FcitxMozcInit,
+        FcitxMozcResetIM,
+        FcitxMozcDoInput,
+        NULL,
+        NULL,
+        FcitxMozcSave,
+        FcitxMozcReloadConfig,
+        NULL,
+        5,
+        "ja"
+    );
+
+    return mozcState;
+}
+
+static void FcitxMozcDestroy(void *arg)
+{
+    FcitxMozcState* mozcState = (FcitxMozcState*) arg;
+    delete mozcState->mozc;
+    free(mozcState);
+}
+
+INPUT_RETURN_VALUE FcitxMozcDoInput(void* arg, FcitxKeySym sym, unsigned int state)
+{
+    FcitxMozcState* mozcState = (FcitxMozcState*) arg;
+    bool result = mozcState->mozc->process_key_event(sym, state);
+    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->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 0000000..bcce806
--- /dev/null
+++ b/src/unix/fcitx/fcitx-mozc.conf
@@ -0,0 +1,10 @@
+[Addon]
+Name=fcitx-mozc
+GeneralName=Mozc
+Comment=Mozc support for Fcitx
+Category=InputMethod
+Enabled=True
+Library=fcitx-mozc.so
+Type=SharedLibrary
+SubConfig=
+IMRegisterMethod=ConfigFile
diff --git a/src/unix/fcitx/fcitx-mozc.desc b/src/unix/fcitx/fcitx-mozc.desc
new file mode 100644
index 0000000..c30420c
--- /dev/null
+++ b/src/unix/fcitx/fcitx-mozc.desc
@@ -0,0 +1,6 @@
+[Mozc/KeyboardLayout]
+Type=Enum
+Enum0=Japanese
+Enum1=America
+DefaultValue=Japanese
+Description=Keyboard layout while using Mozc
\ No newline at end of file
diff --git a/src/unix/fcitx/fcitx.gyp b/src/unix/fcitx/fcitx.gyp
new file mode 100644
index 0000000..4cf7f86
--- /dev/null
+++ b/src/unix/fcitx/fcitx.gyp
@@ -0,0 +1,107 @@
+#
+# 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': {
+    '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',
+        '../../session/session_base.gyp:session_protocol',
+    ],
+    'fcitx_defines': [
+      'LOCALEDIR="<!@(fcitx4-config --prefix)/share/locale/"',
+    ]
+  },
+  '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',
+          ],
+          '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',
+        'mozc_connection.cc',
+        'mozc_response_parser.cc',
+        'eim.cc',
+      ],
+      'dependencies': [
+        '<@(fcitx_dependencies)',
+        'gen_fcitx_mozc_i18n',
+      ],
+      'cflags': [
+        '<!@(pkg-config --cflags <@(pkg_config_libs))',
+      ],
+      'include_dirs': [
+        '<@(fcitx_dep_include_dirs)',
+      ],
+      'libraries': [
+        '<!@(pkg-config --libs-only-l <@(pkg_config_libs))',
+      ],
+      'ldflags': [
+        '<!@(pkg-config --libs-only-L <@(pkg_config_libs))',
+      ],
+      'defines': [
+        '<@(fcitx_defines)',
+      ],
+    },
+  ],
+}
diff --git a/src/unix/fcitx/fcitx_config.cc b/src/unix/fcitx/fcitx_config.cc
new file mode 100644
index 0000000..e69de29
diff --git a/src/unix/fcitx/fcitx_config.h b/src/unix/fcitx/fcitx_config.h
new file mode 100644
index 0000000..ddf9548
--- /dev/null
+++ b/src/unix/fcitx/fcitx_config.h
@@ -0,0 +1,28 @@
+/***************************************************************************
+ *   Copyright (C) 2012~2012 by CSSlayer                                   *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.              *
+ ***************************************************************************/
+
+#ifndef MOZC_UNIX_FCITX_FCITX_CONFIG_H_
+#define MOZC_UNIX_FCITX_FCITX_CONFIG_H_
+
+typedef enum _FcitxMozcLayout {
+    FcitxMozcLayout_Japanese,
+    FcitxMozcLayout_America,
+} FcitxMozcLayout;
+
+#endif
\ No newline at end of file
diff --git a/src/unix/fcitx/fcitx_key_translator.cc b/src/unix/fcitx/fcitx_key_translator.cc
new file mode 100644
index 0000000..aaece04
--- /dev/null
+++ b/src/unix/fcitx/fcitx_key_translator.cc
@@ -0,0 +1,581 @@
+/***************************************************************************
+ *   Copyright (C) 2012~2012 by CSSlayer                                   *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.              *
+ ***************************************************************************/
+
+#include "unix/fcitx/fcitx_key_translator.h"
+
+#include "base/logging.h"
+#include <fcitx/ime.h>
+
+namespace {
+
+const FcitxKeySym modifier_keys[] = {
+    FcitxKey_Alt_L,
+    FcitxKey_Alt_R,
+    FcitxKey_Caps_Lock,
+    FcitxKey_Control_L,
+    FcitxKey_Control_R,
+    FcitxKey_Hyper_L,
+    FcitxKey_Hyper_R,
+    FcitxKey_Meta_L,
+    FcitxKey_Meta_R,
+    FcitxKey_Shift_L,
+    FcitxKey_Shift_Lock,
+    FcitxKey_Shift_R,
+    FcitxKey_Super_L,
+    FcitxKey_Super_R,
+};
+
+const struct SpecialKeyMap {
+    FcitxKeySym from;
+    mozc::commands::KeyEvent::SpecialKey to;
+} sp_key_map[] = {
+    {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 requires special treatment.
+    // See FcitxKeyTranslator::NormalizeHiraganaKatakanaKeyWithShift.
+    {FcitxKey_Hiragana_Katakana, mozc::commands::KeyEvent::KANA},
+    {FcitxKey_Katakana, mozc::commands::KeyEvent::KATAKANA},
+    {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},
+
+    // Shift+TAB.
+    {FcitxKey_ISO_Left_Tab, mozc::commands::KeyEvent::TAB},
+
+    //   - FcitxKey_Kana_Lock? FcitxKey_Kana_Shift?
+};
+
+const struct SpecialAsciiMap {
+    uint32 from;
+    uint32 to;
+} sp_ascii_map[] = {
+    {FcitxKey_KP_Equal, '='},
+};
+
+const struct KanaMap {
+    uint32 keysym;
+    const char *kana;
+} kKanaMapJp[] = {
+    { '1' , "\xe3\x81\xac" },  // "ぬ"
+    { '!' , "\xe3\x81\xac" },  // "ぬ"
+    { '2' , "\xe3\x81\xb5" },  // "ふ"
+    { '\"', "\xe3\x81\xb5" },  // "ふ"
+    { '3' , "\xe3\x81\x82" },  // "あ"
+    { '#' , "\xe3\x81\x81" },  // "ぁ"
+    { '4' , "\xe3\x81\x86" },  // "う"
+    { '$' , "\xe3\x81\x85" },  // "ぅ"
+    { '5' , "\xe3\x81\x88" },  // "え"
+    { '%' , "\xe3\x81\x87" },  // "ぇ"
+    { '6' , "\xe3\x81\x8a" },  // "お"
+    { '&' , "\xe3\x81\x89" },  // "ぉ"
+    { '7' , "\xe3\x82\x84" },  // "や"
+    { '\'', "\xe3\x82\x83" },  // "ゃ"
+    { '8' , "\xe3\x82\x86" },  // "ゆ"
+    { '(' , "\xe3\x82\x85" },  // "ゅ"
+    { '9' , "\xe3\x82\x88" },  // "よ"
+    { ')' , "\xe3\x82\x87" },  // "ょ"
+    { '0' , "\xe3\x82\x8f" },  // "わ"
+    // Shift+0 is usually mapped to tilde by XKB.
+    { '-' , "\xe3\x81\xbb" },  // "ほ"
+    { '=' , "\xe3\x81\xbb" },  // "ほ"
+    { '^' , "\xe3\x81\xb8" },  // "へ"
+    { '~' , "\xe3\x82\x92" },  // "を"
+    { '|' , "\xe3\x83\xbc" },  // "ー"
+    { 'q' , "\xe3\x81\x9f" },  // "た"
+    { 'Q' , "\xe3\x81\x9f" },  // "た"
+    { 'w' , "\xe3\x81\xa6" },  // "て"
+    { 'W' , "\xe3\x81\xa6" },  // "て"
+    { 'e' , "\xe3\x81\x84" },  // "い"
+    { 'E' , "\xe3\x81\x83" },  // "ぃ"
+    { 'r' , "\xe3\x81\x99" },  // "す"
+    { 'R' , "\xe3\x81\x99" },  // "す"
+    { 't' , "\xe3\x81\x8b" },  // "か"
+    { 'T' , "\xe3\x81\x8b" },  // "か"
+    { 'y' , "\xe3\x82\x93" },  // "ん"
+    { 'Y' , "\xe3\x82\x93" },  // "ん"
+    { 'u' , "\xe3\x81\xaa" },  // "な"
+    { 'U' , "\xe3\x81\xaa" },  // "な"
+    { 'i' , "\xe3\x81\xab" },  // "に"
+    { 'I' , "\xe3\x81\xab" },  // "に"
+    { 'o' , "\xe3\x82\x89" },  // "ら"
+    { 'O' , "\xe3\x82\x89" },  // "ら"
+    { 'p' , "\xe3\x81\x9b" },  // "せ"
+    { 'P' , "\xe3\x81\x9b" },  // "せ"
+    { '@' , "\xe3\x82\x9b" },  // "゛"
+    { '`' , "\xe3\x82\x9b" },  // "゛"
+    { '[' , "\xe3\x82\x9c" },  // "゜"
+    { '{' , "\xe3\x80\x8c" },  // "「"
+    { 'a' , "\xe3\x81\xa1" },  // "ち"
+    { 'A' , "\xe3\x81\xa1" },  // "ち"
+    { 's' , "\xe3\x81\xa8" },  // "と"
+    { 'S' , "\xe3\x81\xa8" },  // "と"
+    { 'd' , "\xe3\x81\x97" },  // "し"
+    { 'D' , "\xe3\x81\x97" },  // "し"
+    { 'f' , "\xe3\x81\xaf" },  // "は"
+    { 'F' , "\xe3\x81\xaf" },  // "は"
+    { 'g' , "\xe3\x81\x8d" },  // "き"
+    { 'G' , "\xe3\x81\x8d" },  // "き"
+    { 'h' , "\xe3\x81\x8f" },  // "く"
+    { 'H' , "\xe3\x81\x8f" },  // "く"
+    { 'j' , "\xe3\x81\xbe" },  // "ま"
+    { 'J' , "\xe3\x81\xbe" },  // "ま"
+    { 'k' , "\xe3\x81\xae" },  // "の"
+    { 'K' , "\xe3\x81\xae" },  // "の"
+    { 'l' , "\xe3\x82\x8a" },  // "り"
+    { 'L' , "\xe3\x82\x8a" },  // "り"
+    { ';' , "\xe3\x82\x8c" },  // "れ"
+    { '+' , "\xe3\x82\x8c" },  // "れ"
+    { ':' , "\xe3\x81\x91" },  // "け"
+    { '*' , "\xe3\x81\x91" },  // "け"
+    { ']' , "\xe3\x82\x80" },  // "む"
+    { '}' , "\xe3\x80\x8d" },  // "」"
+    { 'z' , "\xe3\x81\xa4" },  // "つ"
+    { 'Z' , "\xe3\x81\xa3" },  // "っ"
+    { 'x' , "\xe3\x81\x95" },  // "さ"
+    { 'X' , "\xe3\x81\x95" },  // "さ"
+    { 'c' , "\xe3\x81\x9d" },  // "そ"
+    { 'C' , "\xe3\x81\x9d" },  // "そ"
+    { 'v' , "\xe3\x81\xb2" },  // "ひ"
+    { 'V' , "\xe3\x81\xb2" },  // "ひ"
+    { 'b' , "\xe3\x81\x93" },  // "こ"
+    { 'B' , "\xe3\x81\x93" },  // "こ"
+    { 'n' , "\xe3\x81\xbf" },  // "み"
+    { 'N' , "\xe3\x81\xbf" },  // "み"
+    { 'm' , "\xe3\x82\x82" },  // "も"
+    { 'M' , "\xe3\x82\x82" },  // "も"
+    { ',' , "\xe3\x81\xad" },  // "ね"
+    { '<' , "\xe3\x80\x81" },  // "、"
+    { '.' , "\xe3\x82\x8b" },  // "る"
+    { '>' , "\xe3\x80\x82" },  // "。"
+    { '/' , "\xe3\x82\x81" },  // "め"
+    { '?' , "\xe3\x83\xbb" },  // "・"
+    { '_' , "\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).
+    { '\\', "" },
+}, kKanaMapUs[] = {
+    { '`' , "\xe3\x82\x8d" },  // "ろ" - Different from the Jp mapping.
+    { '~' , "\xe3\x82\x8d" },  // "ろ" - Different from the Jp mapping.
+    { '1' , "\xe3\x81\xac" },  // "ぬ"
+    { '!' , "\xe3\x81\xac" },  // "ぬ"
+    { '2' , "\xe3\x81\xb5" },  // "ふ"
+    { '@' , "\xe3\x81\xb5" },  // "ふ"
+    { '3' , "\xe3\x81\x82" },  // "あ"
+    { '#' , "\xe3\x81\x81" },  // "ぁ"
+    { '4' , "\xe3\x81\x86" },  // "う"
+    { '$' , "\xe3\x81\x85" },  // "ぅ"
+    { '5' , "\xe3\x81\x88" },  // "え"
+    { '%' , "\xe3\x81\x87" },  // "ぇ"
+    { '6' , "\xe3\x81\x8a" },  // "お"
+    { '^' , "\xe3\x81\x89" },  // "ぉ"
+    { '7' , "\xe3\x82\x84" },  // "や"
+    { '&' , "\xe3\x82\x83" },  // "ゃ"
+    { '8' , "\xe3\x82\x86" },  // "ゆ"
+    { '*' , "\xe3\x82\x85" },  // "ゅ"
+    { '9' , "\xe3\x82\x88" },  // "よ"
+    { '(' , "\xe3\x82\x87" },  // "ょ"
+    { '0' , "\xe3\x82\x8f" },  // "わ"
+    { ')' , "\xe3\x82\x92" },  // "を"
+    { '-' , "\xe3\x81\xbb" },  // "ほ"
+    { '_' , "\xe3\x83\xbc" },  // "ー" - Different from the Jp mapping.
+    { '=' , "\xe3\x81\xb8" },  // "へ"
+    { '+' , "\xe3\x81\xb8" },  // "へ"
+    { 'q' , "\xe3\x81\x9f" },  // "た"
+    { 'Q' , "\xe3\x81\x9f" },  // "た"
+    { 'w' , "\xe3\x81\xa6" },  // "て"
+    { 'W' , "\xe3\x81\xa6" },  // "て"
+    { 'e' , "\xe3\x81\x84" },  // "い"
+    { 'E' , "\xe3\x81\x83" },  // "ぃ"
+    { 'r' , "\xe3\x81\x99" },  // "す"
+    { 'R' , "\xe3\x81\x99" },  // "す"
+    { 't' , "\xe3\x81\x8b" },  // "か"
+    { 'T' , "\xe3\x81\x8b" },  // "か"
+    { 'y' , "\xe3\x82\x93" },  // "ん"
+    { 'Y' , "\xe3\x82\x93" },  // "ん"
+    { 'u' , "\xe3\x81\xaa" },  // "な"
+    { 'U' , "\xe3\x81\xaa" },  // "な"
+    { 'i' , "\xe3\x81\xab" },  // "に"
+    { 'I' , "\xe3\x81\xab" },  // "に"
+    { 'o' , "\xe3\x82\x89" },  // "ら"
+    { 'O' , "\xe3\x82\x89" },  // "ら"
+    { 'p' , "\xe3\x81\x9b" },  // "せ"
+    { 'P' , "\xe3\x81\x9b" },  // "せ"
+    { '[' , "\xe3\x82\x9b" },  // "゛"
+    { '{' , "\xe3\x82\x9b" },  // "゛"
+    { ']' , "\xe3\x82\x9c" },  // "゜"
+    { '}' , "\xe3\x80\x8c" },  // "「"
+    { '\\', "\xe3\x82\x80" },  // "む" - Different from the Jp mapping.
+    { '|' , "\xe3\x80\x8d" },  // "」" - Different from the Jp mapping.
+    { 'a' , "\xe3\x81\xa1" },  // "ち"
+    { 'A' , "\xe3\x81\xa1" },  // "ち"
+    { 's' , "\xe3\x81\xa8" },  // "と"
+    { 'S' , "\xe3\x81\xa8" },  // "と"
+    { 'd' , "\xe3\x81\x97" },  // "し"
+    { 'D' , "\xe3\x81\x97" },  // "し"
+    { 'f' , "\xe3\x81\xaf" },  // "は"
+    { 'F' , "\xe3\x81\xaf" },  // "は"
+    { 'g' , "\xe3\x81\x8d" },  // "き"
+    { 'G' , "\xe3\x81\x8d" },  // "き"
+    { 'h' , "\xe3\x81\x8f" },  // "く"
+    { 'H' , "\xe3\x81\x8f" },  // "く"
+    { 'j' , "\xe3\x81\xbe" },  // "ま"
+    { 'J' , "\xe3\x81\xbe" },  // "ま"
+    { 'k' , "\xe3\x81\xae" },  // "の"
+    { 'K' , "\xe3\x81\xae" },  // "の"
+    { 'l' , "\xe3\x82\x8a" },  // "り"
+    { 'L' , "\xe3\x82\x8a" },  // "り"
+    { ';' , "\xe3\x82\x8c" },  // "れ"
+    { ':' , "\xe3\x82\x8c" },  // "れ"
+    { '\'', "\xe3\x81\x91" },  // "け"
+    { '\"', "\xe3\x81\x91" },  // "け"
+    { 'z' , "\xe3\x81\xa4" },  // "つ"
+    { 'Z' , "\xe3\x81\xa3" },  // "っ"
+    { 'x' , "\xe3\x81\x95" },  // "さ"
+    { 'X' , "\xe3\x81\x95" },  // "さ"
+    { 'c' , "\xe3\x81\x9d" },  // "そ"
+    { 'C' , "\xe3\x81\x9d" },  // "そ"
+    { 'v' , "\xe3\x81\xb2" },  // "ひ"
+    { 'V' , "\xe3\x81\xb2" },  // "ひ"
+    { 'b' , "\xe3\x81\x93" },  // "こ"
+    { 'B' , "\xe3\x81\x93" },  // "こ"
+    { 'n' , "\xe3\x81\xbf" },  // "み"
+    { 'N' , "\xe3\x81\xbf" },  // "み"
+    { 'm' , "\xe3\x82\x82" },  // "も"
+    { 'M' , "\xe3\x82\x82" },  // "も"
+    { ',' , "\xe3\x81\xad" },  // "ね"
+    { '<' , "\xe3\x80\x81" },  // "、"
+    { '.' , "\xe3\x82\x8b" },  // "る"
+    { '>' , "\xe3\x80\x82" },  // "。"
+    { '/' , "\xe3\x82\x81" },  // "め"
+    { '?' , "\xe3\x83\xbb" },  // "・"
+};
+
+}  // namespace
+
+static inline char get_ascii_code(FcitxKeySym sym)
+{
+    if (sym >= FcitxKey_space && sym <= FcitxKey_asciitilde)
+        return (char) (sym & 0xff);
+
+    if (sym >= FcitxKey_KP_0 && sym <= FcitxKey_KP_9)
+        return (char) ((sym - FcitxKey_KP_0 + FcitxKey_0) & 0xff);
+
+    if (sym == FcitxKey_Return)
+        return 0x0d;
+    if (sym == FcitxKey_Linefeed)
+        return 0x0a;
+    if (sym == FcitxKey_Tab)
+        return 0x09;
+    if (sym == FcitxKey_BackSpace)
+        return 0x08;
+    if (sym == FcitxKey_Escape)
+        return 0x1b;
+
+    return 0;
+}
+
+namespace mozc {
+
+namespace fcitx {
+
+KeyTranslator::KeyTranslator() {
+    InitializeKeyMaps();
+    input = 0;
+    layout = FcitxMozcLayout_Japanese;
+}
+
+KeyTranslator::~KeyTranslator() {
+}
+
+void KeyTranslator::Translate(
+    FcitxKeySym origsym, unsigned int origstate, mozc::config::Config::PreeditMethod method,
+    mozc::commands::KeyEvent *out_event) const {
+    FcitxKeySym sym;
+    unsigned int state;
+    NormalizeHiraganaKatakanaKeyWithShift(origsym, origstate, &sym, &state);
+    DCHECK(CanConvert(sym, state));
+    if (!CanConvert(sym, state)) {
+        LOG(ERROR) << "Can't handle the key: " << sym;
+        return;
+    }
+    DCHECK(out_event);
+    if (!out_event) {
+        return;
+    }
+    out_event->Clear();
+
+
+    if ((state & FcitxKeyState_Ctrl) != 0) {
+        out_event->add_modifier_keys(mozc::commands::KeyEvent::CTRL);
+    }
+    if ((state & FcitxKeyState_Alt) != 0) {
+        out_event->add_modifier_keys(mozc::commands::KeyEvent::ALT);
+    }
+    if (!IsAscii(sym, state) && (state & FcitxKeyState_Shift) != 0) {
+        out_event->add_modifier_keys(mozc::commands::KeyEvent::SHIFT);
+    }
+
+    mozc::commands::KeyEvent::SpecialKey sp_key;
+    uint32 sp_ascii;
+    string key_string;
+
+    if (IsSpecialKey(sym, state, &sp_key)) {
+        out_event->set_special_key(sp_key);
+    } else if (IsSpecialAscii(sym, state, &sp_ascii)) {
+        out_event->set_key_code(sp_ascii);
+    } else if (method == mozc::config::Config::KANA &&
+               IsKanaAvailable(sym, state, &key_string)) {
+        DCHECK(IsAscii(sym, state));
+        out_event->set_key_code(get_ascii_code(sym));
+        out_event->set_key_string(key_string);
+    } else {
+        DCHECK(IsAscii(sym, state));
+        out_event->set_key_code(get_ascii_code(sym));
+    }
+    return;
+}
+
+void KeyTranslator::TranslateClick(
+    int32 unique_id, mozc::commands::SessionCommand *out_command) const {
+    DCHECK(out_command);
+    if (out_command) {
+        out_command->set_type(mozc::commands::SessionCommand::SELECT_CANDIDATE);
+        out_command->set_id(unique_id);
+    }
+    return;
+}
+
+bool KeyTranslator::CanConvert(FcitxKeySym sym, unsigned int state) const {
+    if (IsModifierKey(sym, state)) {
+        VLOG(1) << "modifier key";
+        return false;
+    }
+    if (IsAscii(sym, state) || IsSpecialKey(sym, state, NULL) || IsSpecialAscii(sym, state, NULL)) {
+        return true;
+    }
+
+    char buf[64];
+    ::snprintf(
+        buf, sizeof(buf), "Key code Mozc doesn't know (0x%08x).", sym);
+    LOG(ERROR) << buf;
+    return false;
+}
+
+void KeyTranslator::InitializeKeyMaps() {
+    for (int i = 0; i < arraysize(sp_key_map); ++i) {
+        CHECK(special_key_map_.insert(make_pair(sp_key_map[i].from,
+                                                sp_key_map[i].to)).second);
+    }
+    for (int i = 0; i < arraysize(sp_ascii_map); ++i) {
+        CHECK(special_ascii_map_.insert(make_pair(sp_ascii_map[i].from,
+                                        sp_ascii_map[i].to)).second);
+    }
+    for (int i = 0; i < arraysize(modifier_keys); ++i) {
+        CHECK(modifier_keys_.insert(modifier_keys[i]).second);
+    }
+    for (int i = 0; i < arraysize(kKanaMapJp); ++i) {
+        CHECK(kana_map_jp_.insert(
+                  make_pair(kKanaMapJp[i].keysym, kKanaMapJp[i].kana)).second);
+    }
+    for (int i = 0; i < arraysize(kKanaMapUs); ++i) {
+        CHECK(kana_map_us_.insert(
+                  make_pair(kKanaMapUs[i].keysym, kKanaMapUs[i].kana)).second);
+    }
+}
+
+bool KeyTranslator::IsModifierKey(FcitxKeySym sym, unsigned int state) const {
+    return modifier_keys_.find(sym) != modifier_keys_.end();
+}
+
+bool KeyTranslator::IsSpecialKey(
+    FcitxKeySym sym, unsigned int state,
+    mozc::commands::KeyEvent::SpecialKey *out) const {
+    map<uint32, mozc::commands::KeyEvent::SpecialKey>::const_iterator iter =
+        special_key_map_.find(sym);
+    if (iter == special_key_map_.end()) {
+        return false;
+    }
+    if (out) {
+        *out = iter->second;
+    }
+    return true;
+}
+
+// static
+void KeyTranslator::NormalizeHiraganaKatakanaKeyWithShift(
+    FcitxKeySym origsym, unsigned int origstate, FcitxKeySym* sym, unsigned int* state) {
+    if (origsym == FcitxKey_Hiragana_Katakana) {
+        *sym = FcitxKey_Katakana;
+        *state = origstate & ~FcitxKeyState_Shift;
+    }
+    else {
+        *sym = origsym;
+        *state = origstate;
+    }
+}
+
+
+
+bool KeyTranslator::IsSpecialAscii(
+    FcitxKeySym sym, unsigned int state, uint32 *out) const {
+    map<uint32, uint32>::const_iterator iter = special_ascii_map_.find(sym);
+    if (iter == special_ascii_map_.end()) {
+        return false;
+    }
+    if (out) {
+        *out = iter->second;
+    }
+    return true;
+}
+
+void KeyTranslator::SetLayout(FcitxMozcLayout l)
+{
+    layout = l;
+}
+
+void KeyTranslator::SetInputState(FcitxInputState* i)
+{
+    input = i;
+}
+
+
+bool KeyTranslator::IsKanaAvailable(
+    FcitxKeySym sym, unsigned int state, string *out) const {
+    if ((state & FcitxKeyState_Ctrl) != 0 || (state & FcitxKeyState_Alt) != 0) {
+        return false;
+    }
+    const map<uint32, const char *> &kana_map =
+        IsJapaneseLayout(layout) ? kana_map_jp_ : kana_map_us_;
+
+    // We call get_ascii_code() to support clients that does not send the shift
+    // modifier. By calling the function, both "Shift + 3" and "#" would be
+    // normalized to '#'.
+    const char ascii_code = get_ascii_code(sym);
+
+    map<uint32, const char *>::const_iterator iter = kana_map.find(ascii_code);
+    if (iter == kana_map.end()) {
+        return false;
+    }
+    if (out) {
+        if (ascii_code == '\\' && IsJapaneseLayout(layout)) {
+            uint32_t keycode = 0;
+            if (input)
+                keycode = FcitxInputStateGetKeyCode(input);
+            if (keycode == FcitxKey_bar) {
+                *out = "\xe3\x83\xbc";  // "ー"
+            } else {
+                *out = "\xe3\x82\x8d";  // "ろ"
+            }
+        } else {
+            *out = iter->second;
+        }
+    }
+    return true;
+}
+
+/* static */
+bool KeyTranslator::IsAscii(FcitxKeySym sym, unsigned int state) {
+    // get_ascii_code(sym) returns non-zero value for SPACE, ENTER, LineFeed,
+    // TAB, BACKSPACE, ESCAPE, and Keypad codes. So we don't use it here.
+    return (sym > FcitxKey_space &&
+            // Note: Space key (0x20) is a special key in Mozc.
+            sym <= FcitxKey_asciitilde);  // 0x7e.
+}
+
+/* static */
+bool KeyTranslator::IsJapaneseLayout(FcitxMozcLayout layout) {
+    // We guess that most people using the Kana input mode uses Japanese
+    // keyboards, so we prefer applying the Japanese layout.
+    return layout == FcitxMozcLayout_Japanese;
+}
+
+} // namespace fcitx
+
+}  // 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 0000000..c337974
--- /dev/null
+++ b/src/unix/fcitx/fcitx_key_translator.h
@@ -0,0 +1,114 @@
+/***************************************************************************
+ *   Copyright (C) 2012~2012 by CSSlayer                                   *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.              *
+ ***************************************************************************/
+
+#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/base.h"  // for DISALLOW_COPY_AND_ASSIGN.
+#include "session/commands.pb.h"
+#include "unix/fcitx/fcitx_config.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();
+    ~KeyTranslator();
+
+    // Converts scim_key into Mozc key code and stores them on out_translated.
+    // scim_key must satisfy the following precondition: CanConvert(scim_key)
+    void Translate(FcitxKeySym sym,
+                   unsigned int state,
+                   mozc::config::Config::PreeditMethod method,
+                   mozc::commands::KeyEvent *out_event) const;
+
+    // Converts 'left click on a candidate window' into Mozc message.
+    // unique_id: Unique identifier of the clicked candidate.
+    void TranslateClick(int32 unique_id,
+                        mozc::commands::SessionCommand *out_command) const;
+
+    // Returns true iff scim_key can be converted to mozc::commands::Input.
+    // Note: some keys and key events, such as 'key released', 'modifier key
+    // pressed', or 'special key that Mozc doesn't know pressed' cannot be
+    // converted to mozc::commands::Input.
+    bool CanConvert(FcitxKeySym sym, unsigned int state) const;
+
+    void SetLayout(FcitxMozcLayout l);
+
+    void SetInputState(FcitxInputState* i);
+
+private:
+    // Returns true iff scim_key is modifier key such as SHIFT, ALT, or CAPSLOCK.
+    bool IsModifierKey(FcitxKeySym sym, unsigned int state) const;
+
+    // Returns true iff scim_key is special key such as ENTER, ESC, or PAGE_UP.
+    bool IsSpecialKey(FcitxKeySym sym, unsigned int state,
+                      mozc::commands::KeyEvent::SpecialKey *out) const;
+
+    // Returns a normalized key event iff key is HiraganaKatakana with shift
+    // modifier. See http://code.google.com/p/mozc/issues/detail?id=136 for
+    // the background information.
+    // Otherwire returns the original key.
+    static void NormalizeHiraganaKatakanaKeyWithShift(
+        FcitxKeySym origsym, unsigned int origstate, FcitxKeySym* sym, unsigned int* state);
+
+    // Returns true iff scim_key is special key that can be converted to ASCII.
+    // For example, scim::FCITX_KEY_KP_0 (numeric keypad zero) in FCITX can be
+    // treated as ASCII code '0' in Mozc.
+    bool IsSpecialAscii(FcitxKeySym sym, unsigned int state, uint32 *out) const;
+
+    // Returns true iff scim_key is key with a kana assigned.
+    bool IsKanaAvailable(FcitxKeySym sym, unsigned int state, string *out) const;
+
+    // Returns true iff scim_key is ASCII such as '0', 'A', or '!'.
+    static bool IsAscii(FcitxKeySym sym, unsigned int state);
+
+    // Returns true iff kana_map_jp_ is to be used.
+    static bool IsJapaneseLayout(FcitxMozcLayout layout);
+
+    // Initializes private fields.
+    void InitializeKeyMaps();
+
+    map<uint32, mozc::commands::KeyEvent::SpecialKey> special_key_map_;
+    set<uint32> modifier_keys_;
+    map<uint32, uint32> special_ascii_map_;
+    map<uint32, const char *> kana_map_jp_;
+    map<uint32, const char *> kana_map_us_;
+    FcitxInputState* input;
+    FcitxMozcLayout layout;
+
+    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 0000000..4906e9d
--- /dev/null
+++ b/src/unix/fcitx/fcitx_mozc.cc
@@ -0,0 +1,522 @@
+/***************************************************************************
+ *   Copyright (C) 2012~2012 by CSSlayer                                   *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.              *
+ ***************************************************************************/
+
+#include "unix/fcitx/fcitx_mozc.h"
+
+#include <string>
+#include <fcitx/candidate.h>
+#include <fcitx-config/xdg.h>
+
+#include "base/const.h"
+#include "base/logging.h"
+#include "base/process.h"
+#include "base/util.h"
+#include "unix/fcitx/mozc_connection.h"
+#include "unix/fcitx/mozc_response_parser.h"
+#include "unix/fcitx/fcitx_key_translator.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.
+COMPILE_ASSERT (
+    mozc::commands::NUM_OF_COMPOSITIONS == arraysize ( kPropCompositionModes ),
+    bad_number_of_modes );
+
+}  // 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 )
+{
+    VLOG ( 1 ) << "FcitxMozc created.";
+    const bool is_vertical
+    = false;
+    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, unsigned int state )
+{
+
+    if ( !connection_->CanSend ( sym, state ) )
+    {
+        VLOG ( 1 ) << "Mozc doesn't handle the key. Not consumed.";
+        return false;  // not consumed.
+    }
+
+    string error;
+    mozc::commands::Output raw_response;
+    if ( !connection_->TrySendKeyEvent (
+                sym, state, composition_mode_, &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);
+    }
+}
+
+
+// This function is called from SCIM framework when the ic gets focus.
+void FcitxMozc::init()
+{
+    VLOG ( 1 ) << "focus_in";
+    boolean flag = false;
+    FcitxInstanceSetContext(instance, CONTEXT_DISABLE_AUTOENG, &flag);
+    FcitxInstanceSetContext(instance, CONTEXT_DISABLE_QUICKPHRASE, &flag);
+    FcitxInstanceSetContext(instance, CONTEXT_IM_KEYBOARD_LAYOUT, "jp");
+    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()
+{
+    FcitxProfile* profile = FcitxInstanceGetProfile(instance);
+    FcitxMessages* preedit = FcitxInputStateGetPreedit(input);
+    FcitxMessages* clientpreedit = FcitxInputStateGetClientPreedit(input);
+    FcitxMessagesSetMessageCount(preedit, 0);
+    FcitxMessagesSetMessageCount(clientpreedit, 0);
+    FcitxInputContext* ic = FcitxInstanceGetCurrentIC(instance);
+    if ( preedit_info_.get() )
+    {
+        VLOG ( 1 ) << "DrawPreeditInfo: cursor=" << preedit_info_->cursor_pos;
+
+        if (ic && ((ic->contextCaps & CAPACITY_PREEDIT) == 0 || !profile->bUsePreedit))
+            FcitxInputStateSetShowCursor(input, true);
+
+        for (int i = 0; i < preedit_info_->preedit.size(); i ++) {
+            if (ic && ((ic->contextCaps & CAPACITY_PREEDIT) == 0 || !profile->bUsePreedit))
+                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 (ic && ((ic->contextCaps & CAPACITY_PREEDIT) == 0 || !profile->bUsePreedit))
+            FcitxInputStateSetCursorPos(input, preedit_info_->cursor_pos);
+        FcitxInputStateSetClientCursorPos(input, preedit_info_->cursor_pos);
+    }
+    else {
+        FcitxInputStateSetShowCursor(input, true);
+    }
+}
+
+void FcitxMozc::DrawAux()
+{
+    FcitxMessages* auxUp = FcitxInputStateGetAuxUp(input);
+    FcitxMessages* auxDown = FcitxInputStateGetAuxDown(input);
+    FcitxMessagesSetMessageCount(auxUp, 0);
+    FcitxMessagesSetMessageCount(auxDown, 0);
+    if ( !aux_.empty() ) {
+        FcitxMessagesAddMessageAtLast(auxUp, MSG_TIPS, "%s ", aux_.c_str());
+    }
+}
+
+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::Util::FileExists ( mozc::Util::JoinPath (
+                                      mozc::Util::GetServerDirectory(), mozc::kMozcTool ) ) )
+    {
+        FcitxUIRegisterComplexStatus(instance, this,
+            "mozc-tool",
+            _("Tool"),
+            _("Tool"),
+            NULL,
+            GetMozcToolIcon
+        );
+    }
+    FcitxUISetStatusVisable(instance, "mozc-tool", false);
+    FcitxUISetStatusVisable(instance, "mozc-composition-mode", false);
+}
+
+FcitxMozc::FcitxMozc(const mozc::fcitx::FcitxMozc& )
+{
+
+}
+
+boolean CompositionMenuAction(struct _FcitxUIMenu *menu, int index)
+{
+    FcitxMozc* mozc = (FcitxMozc*) menu->priv;
+    if (index == mozc::commands::DIRECT) {
+        FcitxInstanceCloseIM(mozc->GetInstance(), FcitxInstanceGetCurrentIC(mozc->GetInstance()));
+    }
+    else {
+        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);
+}
+
+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;
+}
+
+}  // 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 0000000..3c0dfb4
--- /dev/null
+++ b/src/unix/fcitx/fcitx_mozc.h
@@ -0,0 +1,150 @@
+/***************************************************************************
+ *   Copyright (C) 2012~2012 by CSSlayer                                   *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.              *
+ ***************************************************************************/
+
+
+#ifndef MOZC_UNIX_FCITX_FCITX_MOZC_H_
+#define MOZC_UNIX_FCITX_FCITX_MOZC_H_
+
+#include <fcitx/instance.h>
+#include <fcitx/candidate.h>
+#include <fcitx-config/hotkey.h>
+#include <libintl.h>
+#include "base/base.h"  // for DISALLOW_COPY_AND_ASSIGN.
+#include "base/run_level.h"
+#include "session/commands.pb.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, unsigned int state );
+    void select_candidate ( FcitxCandidateWord* candWord );
+    void resetim();
+    void reset();
+    void init();
+    void focus_out();
+
+    // 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();
+
+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 DrawAll();
+    void DrawPreeditInfo();
+    void DrawAux();
+
+    // Open url_ with a default browser.
+    void OpenUrl();
+
+    FcitxInstance* instance;
+    FcitxInputState* input;
+    const scoped_ptr<MozcConnectionInterface> connection_;
+    const scoped_ptr<MozcResponseParser> parser_;
+
+    // Strings and a window currently displayed on FCITX UI.
+    scoped_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;
+
+    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 0000000..b730b82
--- /dev/null
+++ b/src/unix/fcitx/gen_fcitx_mozc_i18n.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+objdir="$1"
+
+cd po || exit 1
+
+mkdir -p "$1"
+
+for pofile in *.po
+do
+  msgfmt "$pofile" -o "$1/${pofile/po/mo}"
+done
\ No newline at end of file
diff --git a/src/unix/fcitx/mozc.conf b/src/unix/fcitx/mozc.conf
new file mode 100644
index 0000000..ad19230
--- /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 0000000..cf19c66
--- /dev/null
+++ b/src/unix/fcitx/mozc_connection.cc
@@ -0,0 +1,174 @@
+// Copyright 2010-2012, 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/mozc_connection.h"
+
+#include <string>
+
+#include "base/logging.h"
+#include "base/util.h"
+#include "client/client.h"
+#include "ipc/ipc.h"
+#include "session/commands.pb.h"
+#include "session/ime_switch_util.h"
+#include "unix/fcitx/fcitx_key_translator.h"
+
+namespace mozc {
+namespace fcitx {
+
+MozcConnectionInterface::~MozcConnectionInterface() {
+}
+
+MozcConnection::MozcConnection(
+    mozc::client::ServerLauncherInterface *server_launcher,
+    mozc::IPCClientFactoryInterface *client_factory)
+    : translator_(new KeyTranslator),
+      preedit_method_(mozc::config::Config::ROMAN),
+      client_factory_(client_factory) {
+  VLOG(1) << "MozcConnection is created";
+  mozc::client::ClientInterface *client =
+      mozc::client::ClientFactory::NewClient();
+  client->SetServerLauncher(server_launcher);
+  client->SetIPCClientFactory(client_factory_.get());
+  client_.reset(client);
+
+  mozc::config::Config config;
+  if (client_->EnsureConnection() &&
+      client_->GetConfig(&config) && config.has_preedit_method()) {
+    preedit_method_ = config.preedit_method();
+  }
+  VLOG(1)
+      << "Current preedit method is "
+      << (preedit_method_ == mozc::config::Config::ROMAN ? "Roman" : "Kana");
+}
+
+MozcConnection::~MozcConnection() {
+  client_->SyncData();
+  VLOG(1) << "MozcConnection is destroyed";
+}
+
+bool MozcConnection::TrySendKeyEvent(
+    FcitxKeySym sym, unsigned int state,
+    mozc::commands::CompositionMode composition_mode,
+    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;
+  translator_->Translate(sym, state, preedit_method_, &event);
+
+  if ((composition_mode == mozc::commands::DIRECT) &&
+      !mozc::config::ImeSwitchUtil::IsDirectModeCommand(event)) {
+    VLOG(1) << "In DIRECT mode. Not consumed.";
+    return false;  // not consumed.
+  }
+
+  VLOG(1) << "TrySendKeyEvent: " << endl << event.DebugString();
+  if (!client_->SendKey(event, out)) {
+    *out_error = "SendKey failed";
+    VLOG(1) << "ERROR";
+    return false;
+  }
+  VLOG(1) << "OK: " << 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;
+  translator_->TranslateClick(unique_id, &command);
+  return TrySendCommandInternal(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 TrySendCommandInternal(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 TrySendCommandInternal(command, out, out_error);
+}
+
+bool MozcConnection::TrySendCommandInternal(
+    const mozc::commands::SessionCommand& command,
+    mozc::commands::Output *out,
+    string *out_error) const {
+  VLOG(1) << "TrySendCommandInternal: " << endl << command.DebugString();
+  if (!client_->SendCommand(command, out)) {
+    *out_error = "SendCommand failed";
+    VLOG(1) << "ERROR";
+    return false;
+  }
+  VLOG(1) << "OK: " << endl << out->DebugString();
+  return true;
+}
+
+bool MozcConnection::CanSend(FcitxKeySym sym, unsigned int state) const {
+  return translator_->CanConvert(sym, state);
+}
+
+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 0000000..a005e11
--- /dev/null
+++ b/src/unix/fcitx/mozc_connection.h
@@ -0,0 +1,136 @@
+// Copyright 2010-2012, 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_MOZC_CONNECTION_H_
+#define MOZC_UNIX_FCITX_MOZC_CONNECTION_H_
+
+#include <string>
+#include <fcitx-config/hotkey.h>
+
+#include "base/base.h"
+#include "session/commands.pb.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(FcitxKeySym sym, unsigned int state,
+                               mozc::commands::CompositionMode composition_mode,
+                               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 CanSend(FcitxKeySym sym, unsigned int state) const = 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(FcitxKeySym sym, unsigned int state,
+                               mozc::commands::CompositionMode composition_mode,
+                               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;
+
+  // Returns true iff TrySendKeyEvent() accepts the key.
+  virtual bool CanSend(FcitxKeySym sym, unsigned int state) const;
+
+ private:
+  friend class MozcConnectionTest;
+  MozcConnection(mozc::client::ServerLauncherInterface *server_launcher,
+                 mozc::IPCClientFactoryInterface *client_factory);
+
+  bool TrySendCommandInternal(
+      const mozc::commands::SessionCommand& command,
+      mozc::commands::Output *out,
+      string *out_error) const;
+
+  const scoped_ptr<KeyTranslator> translator_;
+  mozc::config::Config::PreeditMethod preedit_method_;
+  // Keep definition order of client_factory_ and client_.
+  // We should delete client_ before deleting client_factory_.
+  scoped_ptr<mozc::IPCClientFactoryInterface> client_factory_;
+  scoped_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 0000000..ff2e3e3
--- /dev/null
+++ b/src/unix/fcitx/mozc_response_parser.cc
@@ -0,0 +1,281 @@
+// Copyright 2010-2012, 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/mozc_response_parser.h"
+
+#include <string>
+#include <vector>
+
+#include "base/logging.h"
+#include "session/commands.pb.h"
+#include "unix/fcitx/fcitx_mozc.h"
+#include <fcitx/candidate.h>
+
+namespace {
+
+// Returns true if the candidate window contains only suggestions.
+bool IsSuggestion(const mozc::commands::Candidates &candidates) {
+    return !candidates.has_focused_index();
+}
+
+// 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() {
+}
+
+bool MozcResponseParser::ParseResponse(const mozc::commands::Output &response,
+                                       FcitxMozc *fcitx_mozc) const {
+    DCHECK(fcitx_mozc);
+    if (!fcitx_mozc) {
+        return false;
+    }
+
+    // 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);
+    }
+
+    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;
+    }
+    }
+}
+
+void MozcResponseParser::ParseCandidates(
+    const mozc::commands::Candidates &candidates, FcitxMozc *fcitx_mozc) const {
+    const 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()) {
+            // 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;
+        }
+        fcitx_mozc->SetAuxString(auxString);
+    }
+    
+    FcitxCandidateWordList* candList = FcitxInputStateGetCandidateList(fcitx_mozc->GetInputState());
+    FcitxCandidateWordReset(candList);
+    FcitxCandidateWordSetPageSize(candList, 9);
+    char strChoose[] = "\0\0\0\0\0\0\0\0\0\0\0";
+
+    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 uint32 index = candidates.candidate(i).index();
+        if (focused_index != -1 && index == focused_index) {
+            local_index = i;
+        }
+        int32* id = (int32*) fcitx_utils_malloc0(sizeof(int32));
+        FcitxCandidateWord candWord;
+        candWord.callback = FcitxMozcGetCandidateWord;
+        candWord.extraType = MSG_INPUT;
+        candWord.strExtra = NULL;
+        candWord.priv = id;
+        candWord.strWord = NULL;
+        candWord.wordType = MSG_INPUT;
+        candWord.owner = fcitx_mozc;
+
+        string value;
+        if (use_annotation_ &&
+                candidates.candidate(i).has_annotation() &&
+                candidates.candidate(i).annotation().has_prefix()) {
+            value = candidates.candidate(i).annotation().prefix();
+        }
+        value += candidates.candidate(i).value();
+        if (use_annotation_ &&
+                candidates.candidate(i).has_annotation() &&
+                candidates.candidate(i).annotation().has_suffix()) {
+            value += candidates.candidate(i).annotation().suffix();
+        }
+        if (use_annotation_ &&
+                candidates.candidate(i).has_annotation() &&
+                candidates.candidate(i).annotation().has_description()) {
+            // Display descriptions ([HALF][KATAKANA], [GREEK], [Black square], etc).
+            value += CreateDescriptionString(
+                         candidates.candidate(i).annotation().description());
+        }
+
+        candWord.strWord = strdup(value.c_str());
+        
+        if (candidates.candidate(i).has_id()) {
+            const int32 cid = candidates.candidate(i).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);
+    }
+    
+    if (footer.has_index_visible() && footer.index_visible())
+        FcitxCandidateWordSetChoose(candList, DIGIT_STR_CHOOSE);
+    else 
+        FcitxCandidateWordSetChoose(candList, strChoose);
+    FcitxCandidateWordSetFocus(candList, local_index);
+}
+
+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 0000000..f924816
--- /dev/null
+++ b/src/unix/fcitx/mozc_response_parser.h
@@ -0,0 +1,93 @@
+// Copyright 2010-2012, 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_MOZC_RESPONSE_PARSER_H_
+#define MOZC_UNIX_FCITX_MOZC_RESPONSE_PARSER_H_
+
+#include "base/base.h"  // for DISALLOW_COPY_AND_ASSIGN.
+
+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 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 0000000..be34171
--- /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/fcitx-mozc.pot b/src/unix/fcitx/po/fcitx-mozc.pot
new file mode 100644
index 0000000..7306c82
--- /dev/null
+++ b/src/unix/fcitx/po/fcitx-mozc.pot
@@ -0,0 +1,78 @@
+# 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: 2012-04-07 11:37+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: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../fcitx_mozc.cc:53
+msgid "Direct"
+msgstr ""
+
+#: ../fcitx_mozc.cc:58
+msgid "Hiragana"
+msgstr ""
+
+#: ../fcitx_mozc.cc:63
+msgid "Full Katakana"
+msgstr ""
+
+#: ../fcitx_mozc.cc:68
+msgid "Half ASCII"
+msgstr ""
+
+#: ../fcitx_mozc.cc:73
+msgid "Full ASCII"
+msgstr ""
+
+#: ../fcitx_mozc.cc:78
+msgid "Half Katakana"
+msgstr ""
+
+#: ../fcitx_mozc.cc:379 ../fcitx_mozc.cc:380 ../fcitx_mozc.cc:458
+msgid "Composition Mode"
+msgstr ""
+
+#: ../fcitx_mozc.cc:390 ../fcitx_mozc.cc:391
+msgid "Tool"
+msgstr ""
+
+#: ../fcitx_mozc.cc:471
+msgid "Mozc Tool"
+msgstr ""
+
+#: ../fcitx_mozc.cc:477
+msgid "Configuration Tool"
+msgstr ""
+
+#: ../fcitx_mozc.cc:478
+msgid "Dictionary Tool"
+msgstr ""
+
+#: ../fcitx_mozc.cc:479
+msgid "Hand Writing"
+msgstr ""
+
+#: ../fcitx_mozc.cc:480
+msgid "Character Palette"
+msgstr ""
+
+#: ../fcitx_mozc.cc:481
+msgid "Add Word"
+msgstr ""
+
+#: ../fcitx_mozc.cc:482
+msgid "About Mozc"
+msgstr ""
diff --git a/src/unix/fcitx/po/ja.po b/src/unix/fcitx/po/ja.po
new file mode 100644
index 0000000..0f1798c
--- /dev/null
+++ b/src/unix/fcitx/po/ja.po
@@ -0,0 +1,81 @@
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+#   <wengxt@gmail.com>, 2012.
+msgid ""
+msgstr ""
+"Project-Id-Version: fcitx\n"
+"Report-Msgid-Bugs-To: fcitx-dev@googlegroups.com\n"
+"POT-Creation-Date: 2012-04-07 11:37+0800\n"
+"PO-Revision-Date: 2012-04-07 11:45+0800\n"
+"Last-Translator: Weng Xuetian <wengxt@gmail.com>\n"
+"Language-Team: Chinese Traditional <fcitx-dev@googlegroups.com>\n"
+"language/ja_JP/)\n"
+"Language: ja_JP\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"
+"X-Generator: Lokalize 1.4\n"
+
+#: ../fcitx_mozc.cc:53
+msgid "Direct"
+msgstr "直接入力"
+
+#: ../fcitx_mozc.cc:58
+msgid "Hiragana"
+msgstr "ひらがな"
+
+#: ../fcitx_mozc.cc:63
+msgid "Full Katakana"
+msgstr "全角カタカナ"
+
+#: ../fcitx_mozc.cc:68
+msgid "Half ASCII"
+msgstr "半角英数"
+
+#: ../fcitx_mozc.cc:73
+msgid "Full ASCII"
+msgstr "全角英数"
+
+#: ../fcitx_mozc.cc:78
+msgid "Half Katakana"
+msgstr "半角カタカナ"
+
+#: ../fcitx_mozc.cc:379 ../fcitx_mozc.cc:380 ../fcitx_mozc.cc:458
+msgid "Composition Mode"
+msgstr "変換モード"
+
+#: ../fcitx_mozc.cc:390 ../fcitx_mozc.cc:391
+msgid "Tool"
+msgstr "ツールを"
+
+#: ../fcitx_mozc.cc:471
+msgid "Mozc Tool"
+msgstr "Mozc ツールを"
+
+#: ../fcitx_mozc.cc:477
+msgid "Configuration Tool"
+msgstr "設定ツールを"
+
+#: ../fcitx_mozc.cc:478
+msgid "Dictionary Tool"
+msgstr "辞書ツールを"
+
+#: ../fcitx_mozc.cc:479
+msgid "Hand Writing"
+msgstr "手書き文字認識"
+
+#: ../fcitx_mozc.cc:480
+msgid "Character Palette"
+msgstr "文字パレット"
+
+#: ../fcitx_mozc.cc:481
+msgid "Add Word"
+msgstr "単語登録"
+
+#: ../fcitx_mozc.cc:482
+msgid "About Mozc"
+msgstr "Mozc について"
+
diff --git a/src/unix/fcitx/po/zh_CN.po b/src/unix/fcitx/po/zh_CN.po
new file mode 100644
index 0000000..47612f6
--- /dev/null
+++ b/src/unix/fcitx/po/zh_CN.po
@@ -0,0 +1,79 @@
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Weng Xuetian <wengxt@gmail.com>, 2012.
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"Report-Msgid-Bugs-To: fcitx-dev@googlegroups.com\n"
+"POT-Creation-Date: 2012-04-07 11:37+0800\n"
+"PO-Revision-Date: 2012-04-07 11:39+0800\n"
+"Last-Translator: Weng Xuetian <wengxt@gmail.com>\n"
+"Language-Team: Chinese Simplified <fcitx-dev@googlegroups.com>\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=2; plural=n != 1;\n"
+"X-Generator: Lokalize 1.4\n"
+
+#: ../fcitx_mozc.cc:53
+msgid "Direct"
+msgstr "直接键盘输入"
+
+#: ../fcitx_mozc.cc:58
+msgid "Hiragana"
+msgstr "平假名"
+
+#: ../fcitx_mozc.cc:63
+msgid "Full Katakana"
+msgstr "全角片假名"
+
+#: ../fcitx_mozc.cc:68
+msgid "Half ASCII"
+msgstr "半角 ASCII"
+
+#: ../fcitx_mozc.cc:73
+msgid "Full ASCII"
+msgstr "全角 ASCII"
+
+#: ../fcitx_mozc.cc:78
+msgid "Half Katakana"
+msgstr "半角片假名"
+
+#: ../fcitx_mozc.cc:379 ../fcitx_mozc.cc:380 ../fcitx_mozc.cc:458
+msgid "Composition Mode"
+msgstr "编辑模式"
+
+#: ../fcitx_mozc.cc:390 ../fcitx_mozc.cc:391
+msgid "Tool"
+msgstr "工具"
+
+#: ../fcitx_mozc.cc:471
+msgid "Mozc Tool"
+msgstr "Mozc 工具"
+
+#: ../fcitx_mozc.cc:477
+msgid "Configuration Tool"
+msgstr "配置工具"
+
+#: ../fcitx_mozc.cc:478
+msgid "Dictionary Tool"
+msgstr "词典工具"
+
+#: ../fcitx_mozc.cc:479
+msgid "Hand Writing"
+msgstr "手写输入"
+
+#: ../fcitx_mozc.cc:480
+msgid "Character Palette"
+msgstr "字符映射表"
+
+#: ../fcitx_mozc.cc:481
+msgid "Add Word"
+msgstr "添加单词"
+
+#: ../fcitx_mozc.cc:482
+msgid "About Mozc"
+msgstr "关于 Mozc"
+
diff --git a/src/unix/fcitx/po/zh_TW.po b/src/unix/fcitx/po/zh_TW.po
new file mode 100644
index 0000000..fc40fb3
--- /dev/null
+++ b/src/unix/fcitx/po/zh_TW.po
@@ -0,0 +1,82 @@
+# 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.
+# Weng Xuetian <wengxt@gmail.com>, 2012.
+msgid ""
+msgstr ""
+"Project-Id-Version: fcitx\n"
+"Report-Msgid-Bugs-To: fcitx-dev@googlegroups.com\n"
+"POT-Creation-Date: 2012-04-07 11:37+0800\n"
+"PO-Revision-Date: 2012-04-07 11:46+0800\n"
+"Last-Translator: Weng Xuetian <wengxt@gmail.com>\n"
+"Language-Team: Chinese Traditional <fcitx-dev@googlegroups.com>\n"
+"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"
+"X-Generator: Lokalize 1.4\n"
+
+#: ../fcitx_mozc.cc:53
+msgid "Direct"
+msgstr "直接鍵盤輸入"
+
+#: ../fcitx_mozc.cc:58
+msgid "Hiragana"
+msgstr "平假名"
+
+#: ../fcitx_mozc.cc:63
+msgid "Full Katakana"
+msgstr "全形片假名"
+
+#: ../fcitx_mozc.cc:68
+msgid "Half ASCII"
+msgstr "半形 ASCII"
+
+#: ../fcitx_mozc.cc:73
+msgid "Full ASCII"
+msgstr "全形 ASCII"
+
+#: ../fcitx_mozc.cc:78
+msgid "Half Katakana"
+msgstr "半形片假名"
+
+#: ../fcitx_mozc.cc:379 ../fcitx_mozc.cc:380 ../fcitx_mozc.cc:458
+msgid "Composition Mode"
+msgstr "編輯模式"
+
+#: ../fcitx_mozc.cc:390 ../fcitx_mozc.cc:391
+msgid "Tool"
+msgstr "工具"
+
+#: ../fcitx_mozc.cc:471
+msgid "Mozc Tool"
+msgstr "Mozc 工具"
+
+#: ../fcitx_mozc.cc:477
+msgid "Configuration Tool"
+msgstr "設定工具"
+
+#: ../fcitx_mozc.cc:478
+msgid "Dictionary Tool"
+msgstr "字典工具"
+
+#: ../fcitx_mozc.cc:479
+msgid "Hand Writing"
+msgstr "手寫輸入"
+
+#: ../fcitx_mozc.cc:480
+msgid "Character Palette"
+msgstr "字符映射表"
+
+#: ../fcitx_mozc.cc:481
+msgid "Add Word"
+msgstr "添加單詞"
+
+#: ../fcitx_mozc.cc:482
+msgid "About Mozc"
+msgstr "關於 Mozc"
+
