1 // Copyright 2012~2013, Weng Xuetian <wengxt@gmail.com>
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 //     * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 //     * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 //     * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 
30 #include <fcitx/instance.h>
31 #include <fcitx/ime.h>
32 #include <fcitx/hook.h>
33 #include <fcitx/module.h>
34 #include <fcitx/keys.h>
35 #include <fcitx-config/xdg.h>
36 #include "fcitx_mozc.h"
37 #include "mozc_connection.h"
38 #include "mozc_response_parser.h"
39 #include "base/init_mozc.h"
40 
41 typedef struct _FcitxMozcState {
42     mozc::fcitx::FcitxMozc* mozc;
43     int inUsageState;
44 } FcitxMozcState;
45 
46 
47 static void* FcitxMozcCreate(FcitxInstance* instance);
48 static void FcitxMozcDestroy(void *arg);
49 static boolean FcitxMozcInit(void *arg); /**< FcitxMozcInit */
50 static void FcitxMozcResetIM(void *arg); /**< FcitxMozcResetIM */
51 static void FcitxMozcReset(void *arg); /**< FcitxMozcResetIM */
52 static INPUT_RETURN_VALUE FcitxMozcDoInput(void *arg, FcitxKeySym, unsigned int); /**< FcitxMozcDoInput */
53 static INPUT_RETURN_VALUE FcitxMozcDoReleaseInput(void *arg, FcitxKeySym, unsigned int); /**< FcitxMozcDoInput */
54 static void FcitxMozcSave(void *arg); /**< FcitxMozcSave */
55 static void FcitxMozcReloadConfig(void *arg); /**< FcitxMozcReloadConfig */
56 
57 extern "C" {
58 
59 FCITX_EXPORT_API
60 FcitxIMClass ime = {
61     FcitxMozcCreate,
62     FcitxMozcDestroy
63 };
64 FCITX_EXPORT_API
65 int ABI_VERSION = FCITX_ABI_VERSION;
66 
67 }
68 
CheckLayout(FcitxInstance * instance)69 static inline bool CheckLayout(FcitxInstance* instance)
70 {
71     char *layout = NULL, *variant = NULL;
72     FcitxModuleFunctionArg args;
73     args.args[0] = &layout;
74     args.args[1] = &variant;
75     bool layout_is_jp = false;
76     FcitxModuleInvokeFunctionByName(instance, "fcitx-xkb", 1, args);
77     if (layout && strcmp(layout, "jp") == 0)
78         layout_is_jp = true;
79 
80     fcitx_utils_free(layout);
81     fcitx_utils_free(variant);
82 
83 
84     return layout_is_jp;
85 }
86 
FcitxMozcCreate(FcitxInstance * instance)87 static void* FcitxMozcCreate(FcitxInstance* instance)
88 {
89     FcitxMozcState* mozcState = (FcitxMozcState*) fcitx_utils_malloc0(sizeof(FcitxMozcState));
90     bindtextdomain("fcitx-mozc", LOCALEDIR);
91     bind_textdomain_codeset("fcitx-mozc", "UTF-8");
92 
93     int argc = 1;
94     char argv0[] = "fcitx_mozc";
95     char *_argv[] = {  argv0 };
96     char **argv = _argv;
97     mozc::InitMozc(argv[0], &argc, &argv, true);
98     mozcState->mozc = new mozc::fcitx::FcitxMozc(
99         instance,
100         mozc::fcitx::MozcConnection::CreateMozcConnection(),
101         new mozc::fcitx::MozcResponseParser
102     );
103 
104     mozcState->mozc->SetCompositionMode(mozc::commands::HIRAGANA);
105 
106     FcitxIMEventHook hk;
107     hk.arg = mozcState;
108     hk.func = FcitxMozcReset;
109 
110     FcitxInstanceRegisterResetInputHook(instance, hk);
111 
112     FcitxIMIFace iface;
113     memset(&iface, 0, sizeof(FcitxIMIFace));
114     iface.Init = FcitxMozcInit;
115     iface.ResetIM = FcitxMozcResetIM;
116     iface.DoInput = FcitxMozcDoInput;
117     iface.DoReleaseInput = FcitxMozcDoReleaseInput;
118     iface.ReloadConfig = FcitxMozcReloadConfig;
119     iface.Save = FcitxMozcSave;
120 
121 
122     FcitxInstanceRegisterIMv2(
123         instance,
124         mozcState,
125         "mozc",
126         "Mozc",
127         mozcState->mozc->GetIconFile("mozc.png").c_str(),
128         iface,
129         1,
130         "ja"
131     );
132 
133     return mozcState;
134 }
135 
FcitxMozcDestroy(void * arg)136 static void FcitxMozcDestroy(void *arg)
137 {
138     FcitxMozcState* mozcState = (FcitxMozcState*) arg;
139     delete mozcState->mozc;
140     free(mozcState);
141 }
142 
143 static const FcitxHotkey MOZC_CTRL_ALT_H[2] = {
144     {NULL, FcitxKey_H, FcitxKeyState_Ctrl_Alt},
145     {NULL, FcitxKey_None, 0}
146 };
147 
FcitxMozcDoInput(void * arg,FcitxKeySym _sym,unsigned int _state)148 INPUT_RETURN_VALUE FcitxMozcDoInput(void* arg, FcitxKeySym _sym, unsigned int _state)
149 {
150     FcitxMozcState* mozcState = (FcitxMozcState*) arg;
151     FcitxInstance* instance = mozcState->mozc->GetInstance();
152     FcitxInputState* input = FcitxInstanceGetInputState(mozcState->mozc->GetInstance());
153 
154     if (mozcState->inUsageState) {
155         if (FcitxHotkeyIsHotKey(_sym, _state, FCITX_ESCAPE)) {
156             mozcState->inUsageState = false;
157             // send a dummy key to let server send us the candidate info back without side effect
158             mozcState->mozc->process_key_event(FcitxKey_VoidSymbol, 0, 0, CheckLayout(instance), false);
159             return IRV_DISPLAY_CANDWORDS;
160         } else {
161             return IRV_DO_NOTHING;
162         }
163     }
164 
165     if (FcitxHotkeyIsHotKey(_sym, _state, MOZC_CTRL_ALT_H)) {
166         std::pair< string, string > usage = mozcState->mozc->GetUsage();
167         if (usage.first.size() != 0 || usage.second.size() != 0) {
168             mozcState->inUsageState = true;
169             FcitxCandidateWordList* candList = FcitxInputStateGetCandidateList(mozcState->mozc->GetInputState());
170 
171             // clear preedit, but keep client preedit
172             FcitxMessages* preedit = FcitxInputStateGetPreedit(input);
173             FcitxMessagesSetMessageCount(preedit, 0);
174             FcitxInputStateSetShowCursor(input, false);
175 
176             // clear aux
177             FcitxMessages* auxUp = FcitxInputStateGetAuxUp(input);
178             FcitxMessages* auxDown = FcitxInputStateGetAuxDown(input);
179             FcitxMessagesSetMessageCount(auxUp, 0);
180             FcitxMessagesSetMessageCount(auxDown, 0);
181 
182             // clear candidate table
183             FcitxCandidateWordReset(candList);
184             FcitxCandidateWordSetPageSize(candList, 9);
185 #if 0
186             FcitxCandidateWordSetLayoutHint(candList, CLH_Vertical);
187 #endif
188             FcitxCandidateWordSetChoose(candList, "\0\0\0\0\0\0\0\0\0\0");
189             FcitxMessagesAddMessageAtLast(preedit, MSG_TIPS, "%s [%s]", usage.first.c_str(), _("Press Escape to go back"));
190 
191             UT_array* lines = fcitx_utils_split_string(usage.second.c_str(), '\n');
192             utarray_foreach(line, lines, char*) {
193                 FcitxCandidateWord candWord;
194                 candWord.callback = NULL;
195                 candWord.extraType = MSG_OTHER;
196                 candWord.strExtra = NULL;
197                 candWord.priv = NULL;
198                 candWord.strWord = strdup(*line);
199                 candWord.wordType = MSG_OTHER;
200                 candWord.owner = NULL;
201                 FcitxCandidateWordAppend(candList, &candWord);
202             }
203             utarray_free(lines);
204             return IRV_DISPLAY_MESSAGE;
205         }
206     }
207 
208     FCITX_UNUSED(_sym);
209     FCITX_UNUSED(_state);
210     FcitxKeySym sym = (FcitxKeySym) FcitxInputStateGetKeySym(input);
211     uint32 keycode = FcitxInputStateGetKeyCode(input);
212     uint32 state = FcitxInputStateGetKeyState(input);
213     bool result = mozcState->mozc->process_key_event(sym, keycode, state, CheckLayout(instance), false);
214     if (!result)
215         return IRV_TO_PROCESS;
216     else
217         return IRV_DISPLAY_CANDWORDS;
218 }
219 
FcitxMozcDoReleaseInput(void * arg,FcitxKeySym _sym,unsigned int _state)220 INPUT_RETURN_VALUE FcitxMozcDoReleaseInput(void* arg, FcitxKeySym _sym, unsigned int _state)
221 {
222     FcitxMozcState* mozcState = (FcitxMozcState*) arg;
223     FcitxInstance* instance = mozcState->mozc->GetInstance();
224     FcitxInputState* input = FcitxInstanceGetInputState(mozcState->mozc->GetInstance());
225     FCITX_UNUSED(_sym);
226     FCITX_UNUSED(_state);
227 
228     if (mozcState->inUsageState) {
229         return IRV_DONOT_PROCESS;
230     }
231 
232     FcitxKeySym sym = (FcitxKeySym) FcitxInputStateGetKeySym(input);
233     uint32 keycode = FcitxInputStateGetKeyCode(input);
234     uint32 state = FcitxInputStateGetKeyState(input);
235     bool result = mozcState->mozc->process_key_event(sym, keycode, state, CheckLayout(instance), true);
236     if (!result)
237         return IRV_TO_PROCESS;
238     else
239         return IRV_DISPLAY_CANDWORDS;
240 }
241 
242 
243 
FcitxMozcInit(void * arg)244 boolean FcitxMozcInit(void* arg)
245 {
246     FcitxMozcState* mozcState = (FcitxMozcState*) arg;
247     mozcState->mozc->init();
248     return true;
249 }
250 
FcitxMozcReloadConfig(void * arg)251 void FcitxMozcReloadConfig(void* arg)
252 {
253 
254 }
255 
FcitxMozcSave(void * arg)256 void FcitxMozcSave(void* arg)
257 {
258     FCITX_UNUSED(arg);
259 }
260 
FcitxMozcResetIM(void * arg)261 void FcitxMozcResetIM(void* arg)
262 {
263     FcitxMozcState* mozcState = (FcitxMozcState*) arg;
264     mozcState->inUsageState = false;
265     mozcState->mozc->resetim();
266 }
267 
FcitxMozcReset(void * arg)268 void FcitxMozcReset(void* arg)
269 {
270     FcitxMozcState* mozcState = (FcitxMozcState*) arg;
271     mozcState->mozc->reset();
272 
273 }
274