1 /***************************************************************************
2 * Copyright (C) 2012~2012 by CSSlayer *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
18 ***************************************************************************/
19
20 #include <libintl.h>
21
22 #include "fcitx/instance.h"
23 #include "fcitx/module.h"
24 #include "fcitx/hook.h"
25 #include "fcitx/context.h"
26 #include "fcitx/candidate.h"
27 #include <fcitx/keys.h>
28 #include "fcitx-config/xdg.h"
29 #include "charselectdata.h"
30
31 typedef struct _UnicodeModule {
32 FcitxGenericConfig gconfig;
33 FcitxHotkey key[2];
34 boolean enable;
35 CharSelectData* charselectdata;
36 char buffer[MAX_USER_INPUT * UTF8_MAX_LENGTH + 1];
37 FcitxInstance* owner;
38 boolean loaded;
39 } UnicodeModule;
40
41 static void* UnicodeCreate(FcitxInstance* instance);
42 boolean UnicodePreFilter(void* arg, FcitxKeySym sym, unsigned int state,
43 INPUT_RETURN_VALUE *r);
44 void UnicodeReloadConfig(void* arg);
45 void UnicodeReset(void* arg);
46 INPUT_RETURN_VALUE UnicodeHotkey(void* arg);
47 INPUT_RETURN_VALUE UnicodeGetCandWords(UnicodeModule* uni);
48
49 FCITX_DEFINE_PLUGIN(fcitx_unicode, module, FcitxModule) = {
50 UnicodeCreate,
51 NULL,
52 NULL,
53 NULL,
54 UnicodeReloadConfig
55 };
56
57 CONFIG_BINDING_BEGIN(UnicodeModule)
58 CONFIG_BINDING_REGISTER("Unicode", "Key", key)
CONFIG_BINDING_END()59 CONFIG_BINDING_END()
60
61 CONFIG_DEFINE_LOAD_AND_SAVE(Unicode, UnicodeModule, "fcitx-unicode")
62
63 void* UnicodeCreate(FcitxInstance* instance)
64 {
65 UnicodeModule* uni = fcitx_utils_new(UnicodeModule);
66 uni->owner = instance;
67 if (!UnicodeLoadConfig(uni)) {
68 free(uni);
69 return NULL;
70 }
71
72 FcitxIMEventHook imhk;
73 imhk.arg = uni;
74 imhk.func = UnicodeReset;
75 FcitxInstanceRegisterResetInputHook(instance, imhk);
76
77 FcitxKeyFilterHook kfhk;
78 kfhk.arg = uni;
79 kfhk.func = UnicodePreFilter;
80 FcitxInstanceRegisterPreInputFilter(instance, kfhk);
81
82 kfhk.arg = &uni->enable;
83 kfhk.func = FcitxDummyReleaseInputHook;
84 FcitxInstanceRegisterPreReleaseInputFilter(instance, kfhk);
85
86 FcitxHotkeyHook hkhk;
87 hkhk.arg = uni;
88 hkhk.hotkey = uni->key;
89 hkhk.hotkeyhandle = UnicodeHotkey;
90 FcitxInstanceRegisterHotkeyFilter(instance, hkhk);
91
92 return uni;
93 }
94
UnicodePreFilter(void * arg,FcitxKeySym sym,unsigned int state,INPUT_RETURN_VALUE * r)95 boolean UnicodePreFilter(void* arg, FcitxKeySym sym, unsigned int state,
96 INPUT_RETURN_VALUE *r)
97 {
98 INPUT_RETURN_VALUE retVal = IRV_TO_PROCESS;
99 do {
100 UnicodeModule *uni = arg;
101 if (!uni->enable) {
102 return false;
103 }
104 FcitxInstance *instance = uni->owner;
105 FcitxInputState *input = FcitxInstanceGetInputState(instance);
106 FcitxGlobalConfig *fc = FcitxInstanceGetGlobalConfig(instance);
107 FcitxCandidateWordList *candList;
108 FcitxCandidateWord *candWord;
109 candList = FcitxInputStateGetCandidateList(input);
110
111 FcitxCandidateWordSetPageSize(candList, fc->iMaxCandWord);
112 FcitxCandidateWordSetChooseAndModifier(candList, DIGIT_STR_CHOOSE,
113 FcitxKeyState_Alt);
114 if (FcitxHotkeyIsHotKey(sym, state,
115 FcitxConfigPrevPageKey(instance, fc))) {
116 if (FcitxCandidateWordGoPrevPage(candList))
117 retVal = IRV_DISPLAY_MESSAGE;
118 else
119 retVal = IRV_DO_NOTHING;
120 } else if (FcitxHotkeyIsHotKey(sym, state,
121 FcitxConfigNextPageKey(instance, fc))) {
122 if (FcitxCandidateWordGoNextPage(candList))
123 retVal = IRV_DISPLAY_MESSAGE;
124 else
125 retVal = IRV_DO_NOTHING;
126 } else if (FcitxHotkeyIsHotKey(sym, state, FCITX_BACKSPACE)) {
127 size_t len = strlen(uni->buffer);
128 if (len > 0)
129 uni->buffer[--len] = '\0';
130 if (len == 0) {
131 retVal = IRV_CLEAN;
132 } else {
133 retVal = UnicodeGetCandWords(uni);
134 }
135 } else if (FcitxHotkeyIsHotKey(sym, state, FCITX_ESCAPE)) {
136 retVal = IRV_CLEAN;
137 } else if (FcitxHotkeyIsHotKey(sym, state, fc->nextWord)) {
138 candWord = FcitxCandidateWordGetFocus(candList, true);
139 candWord = FcitxCandidateWordGetNext(candList, candWord);
140 if (!candWord) {
141 FcitxCandidateWordSetPage(candList, 0);
142 candWord = FcitxCandidateWordGetFirst(candList);
143 } else {
144 FcitxCandidateWordSetFocus(
145 candList, FcitxCandidateWordGetIndex(candList, candWord));
146 }
147 if (candWord) {
148 FcitxCandidateWordSetType(candWord, MSG_CANDIATE_CURSOR);
149 retVal = IRV_FLAG_UPDATE_INPUT_WINDOW;
150 }
151 } else if (FcitxHotkeyIsHotKey(sym, state, fc->prevWord)) {
152 candWord = FcitxCandidateWordGetFocus(candList, true);
153 candWord = FcitxCandidateWordGetPrev(candList, candWord);
154 if (!candWord) {
155 FcitxCandidateWordSetPage(
156 candList, FcitxCandidateWordPageCount(candList) - 1);
157 candWord = FcitxCandidateWordGetLast(candList);
158 } else {
159 FcitxCandidateWordSetFocus(
160 candList, FcitxCandidateWordGetIndex(candList, candWord));
161 }
162 if (candWord) {
163 FcitxCandidateWordSetType(candWord, MSG_CANDIATE_CURSOR);
164 retVal = IRV_FLAG_UPDATE_INPUT_WINDOW;
165 }
166 } else if (FcitxHotkeyIsHotKey(sym, state, FCITX_ENTER)) {
167 candWord = FcitxCandidateWordGetFocus(candList, true);
168 if (candWord) {
169 retVal = FcitxCandidateWordChooseByTotalIndex(
170 candList, FcitxCandidateWordGetIndex(candList, candWord));
171 }
172 }
173
174 if (retVal == IRV_TO_PROCESS) {
175 int index = FcitxCandidateWordCheckChooseKey(candList, sym, state);
176 if (index >= 0)
177 retVal = FcitxCandidateWordChooseByIndex(candList, index);
178 }
179
180 FcitxKeySym keymain = FcitxHotkeyPadToMain(sym);
181 if (retVal == IRV_TO_PROCESS && FcitxHotkeyIsHotKeySimple(keymain, state)) {
182 char buf[2];
183 buf[0] = keymain;
184 buf[1] = '\0';
185 if (strlen(uni->buffer) < MAX_USER_INPUT)
186 strcat(uni->buffer, buf);
187 retVal = UnicodeGetCandWords(uni);
188 }
189 } while(0);
190
191 if (retVal == IRV_TO_PROCESS) {
192 retVal = IRV_DO_NOTHING;
193 }
194 *r = retVal;
195 return true;
196 }
197
UnicodeGetCandWord(void * arg,FcitxCandidateWord * candWord)198 INPUT_RETURN_VALUE UnicodeGetCandWord(void* arg, FcitxCandidateWord* candWord)
199 {
200 UnicodeModule* uni = arg;
201 FcitxInputState *input = FcitxInstanceGetInputState(uni->owner);
202 strcpy(FcitxInputStateGetOutputString(input), candWord->strWord);
203 return IRV_COMMIT_STRING;
204 }
205
UnicodeGetCandWords(UnicodeModule * uni)206 INPUT_RETURN_VALUE UnicodeGetCandWords(UnicodeModule* uni)
207 {
208 FcitxInputState *input = FcitxInstanceGetInputState(uni->owner);
209 FcitxInstanceCleanInputWindow(uni->owner);
210 FcitxMessagesAddMessageStringsAtLast(FcitxInputStateGetPreedit(input),
211 MSG_INPUT, uni->buffer);
212 FcitxInputStateSetShowCursor(input, true);
213 FcitxInputStateSetCursorPos(input, strlen(uni->buffer));
214
215 FcitxCandidateWordList* candList = FcitxInputStateGetCandidateList(input);
216 FcitxCandidateWordSetLayoutHint(candList, CLH_Vertical);
217
218 UT_array* result = CharSelectDataFind(uni->charselectdata, uni->buffer);
219 utarray_foreach(c, result, uint32_t) {
220 char* s = fcitx_utils_malloc0(sizeof(char) * (UTF8_MAX_LENGTH + 1));
221 fcitx_ucs4_to_utf8(*c, s);
222 FcitxCandidateWord candWord;
223 candWord.callback = UnicodeGetCandWord;
224 candWord.owner = uni;
225 candWord.priv = NULL;
226 candWord.extraType = MSG_OTHER;
227 candWord.wordType = MSG_CODE;
228 candWord.strWord = s;
229 char* name = CharSelectDataName(uni->charselectdata, *c);
230 fcitx_utils_alloc_cat_str(candWord.strExtra, " ", name);
231 free(name);
232 FcitxCandidateWordAppend(candList, &candWord);
233 }
234 utarray_free(result);
235 if (FcitxCandidateWordGetListSize(candList)) {
236 FcitxCandidateWordSetType(FcitxCandidateWordGetFirst(candList),
237 MSG_CANDIATE_CURSOR);
238 }
239 return IRV_FLAG_UPDATE_INPUT_WINDOW;
240 }
241
UnicodeReloadConfig(void * arg)242 void UnicodeReloadConfig(void* arg)
243 {
244 UnicodeModule* uni = arg;
245 UnicodeLoadConfig(uni);
246 }
247
UnicodeReset(void * arg)248 void UnicodeReset(void* arg)
249 {
250 UnicodeModule* uni = arg;
251 uni->enable = false;
252 uni->buffer[0] = '\0';
253 }
254
UnicodeHotkey(void * arg)255 INPUT_RETURN_VALUE UnicodeHotkey(void* arg)
256 {
257 UnicodeModule* uni = arg;
258
259 if (!uni->loaded) {
260 uni->charselectdata = CharSelectDataCreate();
261 uni->loaded = true;
262 }
263
264 if (!uni->charselectdata)
265 return IRV_TO_PROCESS;
266 uni->enable = true;
267
268 FcitxInstanceCleanInputWindow(uni->owner);
269 FcitxInputState *input = FcitxInstanceGetInputState(uni->owner);
270 FcitxInputStateSetShowCursor(input, false);
271 FcitxMessagesAddMessageStringsAtLast(FcitxInputStateGetAuxUp(input),
272 MSG_TIPS, _("Search unicode"));
273 return IRV_DISPLAY_MESSAGE;
274 }
275