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 +#include +#include +#include +#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=" + +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::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::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 &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::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 +#include +#include + +#include + +#include "base/base.h" // for DISALLOW_COPY_AND_ASSIGN. +#include "session/commands.pb.h" +#include "unix/fcitx/fcitx_config.h" +#include + +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 special_key_map_; + set modifier_keys_; + map special_ascii_map_; + map kana_map_jp_; + map 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..c91c748 --- /dev/null +++ b/src/unix/fcitx/fcitx_mozc.cc @@ -0,0 +1,524 @@ +/*************************************************************************** + * 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 +#include +#include + +#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 + +#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 = true; + FcitxInstanceSetContext(instance, CONTEXT_DISABLE_AUTOENG, &flag); + FcitxInstanceSetContext(instance, CONTEXT_DISABLE_QUICKPHRASE, &flag); + FcitxInstanceSetContext(instance, CONTEXT_IM_KEYBOARD_LAYOUT, "jp"); + FcitxInstanceSetContext(instance, "CONTEXT_DISABLE_AUTO_FIRST_CANDIDATE_HIGHTLIGHT", &flag); + + 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 +#include +#include +#include +#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 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 connection_; + const scoped_ptr parser_; + + // Strings and a window currently displayed on FCITX UI. + scoped_ptr 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 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 + +#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 +#include + +#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 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 client_factory_; + scoped_ptr 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..42d13b5 --- /dev/null +++ b/src/unix/fcitx/mozc_response_parser.cc @@ -0,0 +1,285 @@ +// 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 +#include + +#include "base/logging.h" +#include "session/commands.pb.h" +#include "unix/fcitx/fcitx_mozc.h" +#include + +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(); + FcitxMessageType type; + if (focused_index != -1 && index == focused_index) { + local_index = i; + type = MSG_FIRSTCAND; + } + else + type = MSG_OTHER; + int32* id = (int32*) fcitx_utils_malloc0(sizeof(int32)); + FcitxCandidateWord candWord; + candWord.callback = FcitxMozcGetCandidateWord; + candWord.extraType = MSG_OTHER; + candWord.strExtra = NULL; + candWord.priv = id; + candWord.strWord = NULL; + candWord.wordType = type; + candWord.owner = fcitx_mozc; + + string value; + if (use_annotation_ && + 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 , 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 \n" +"Language-Team: LANGUAGE \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: +# , 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 \n" +"Language-Team: Chinese Traditional \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 , 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 \n" +"Language-Team: Chinese Simplified \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 , 2012. +# Weng Xuetian , 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 \n" +"Language-Team: Chinese Traditional \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" +