1
/***************************************************************************
2
* Copyright (C) 2010~2010 by CSSlayer *
5
* This program is free software; you can redistribute it and/or modify *
6
* it under the terms of the GNU General Public License as published by *
7
* the Free Software Foundation; either version 2 of the License, or *
8
* (at your option) any later version. *
10
* This program is distributed in the hope that it will be useful, *
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13
* GNU General Public License for more details. *
15
* You should have received a copy of the GNU General Public License *
16
* along with this program; if not, write to the *
17
* Free Software Foundation, Inc., *
18
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
19
***************************************************************************/
25
#include <ime-core/imi_view.h>
26
#include <ime-core/imi_options.h>
27
#include <ime-core/utils.h>
28
#include <fcitx/ime.h>
29
#include <fcitx-config/hotkey.h>
30
#include <fcitx-config/xdg.h>
31
#include <fcitx-utils/log.h>
32
#include <fcitx-config/fcitx-config.h>
33
#include <fcitx-utils/utils.h>
34
#include <fcitx/instance.h>
35
#include <fcitx/keys.h>
36
#include <fcitx/module.h>
37
#include <fcitx/context.h>
44
#define FCITX_SUNPINYIN_MAX(x, y) ((x) > (y)? (x) : (y))
56
int ABI_VERSION = FCITX_ABI_VERSION;
61
CONFIG_DESC_DEFINE(GetSunpinyinConfigDesc, "fcitx-sunpinyin.desc")
63
boolean LoadSunpinyinConfig(FcitxSunpinyinConfig* fs);
64
static void SaveSunpinyinConfig(FcitxSunpinyinConfig* fs);
65
static void ConfigSunpinyin(FcitxSunpinyin* sunpinyin);
66
static void* SunpinyinGetFullPinyin(void* arg, FcitxModuleFunctionArg args);
67
static INPUT_RETURN_VALUE FcitxSunpinyinDeleteCandidate (FcitxSunpinyin* sunpinyin, FcitxCandidateWord* candWord);
70
static const char* fuzzyPairs[][2] = {
87
static const char *correctionPairs[][2] = {
97
* @brief Reset the status.
101
void FcitxSunpinyinReset (void* arg)
103
FcitxSunpinyin* sunpinyin = (FcitxSunpinyin*) arg;
104
FcitxUIStatus* puncStatus = FcitxUIGetStatusByName(sunpinyin->owner, "punc");
105
FcitxUIStatus* fullwidthStatus = FcitxUIGetStatusByName(sunpinyin->owner, "fullwidth");
106
sunpinyin->view->setStatusAttrValue(CIMIWinHandler::STATUS_ID_FULLSYMBOL, fullwidthStatus->getCurrentStatus(fullwidthStatus->arg));
107
sunpinyin->view->setStatusAttrValue(CIMIWinHandler::STATUS_ID_FULLPUNC, puncStatus->getCurrentStatus(puncStatus->arg));
108
sunpinyin->view->clearIC();
112
* @brief Process Key Input and return the status
114
* @param keycode keycode from XKeyEvent
115
* @param state state from XKeyEvent
116
* @param count count from XKeyEvent
117
* @return INPUT_RETURN_VALUE
120
INPUT_RETURN_VALUE FcitxSunpinyinDoInput(void* arg, FcitxKeySym sym, unsigned int state)
122
FcitxSunpinyin* sunpinyin = (FcitxSunpinyin*) arg;
123
FcitxInputState* input = FcitxInstanceGetInputState(sunpinyin->owner);
124
CIMIView* view = sunpinyin->view;
125
FcitxWindowHandler* windowHandler = sunpinyin->windowHandler;
126
FcitxSunpinyinConfig* fs = &sunpinyin->fs;
127
FcitxGlobalConfig* config = FcitxInstanceGetGlobalConfig(sunpinyin->owner);
128
FcitxCandidateWordSetChoose(FcitxInputStateGetCandidateList(input), DIGIT_STR_CHOOSE);
130
int chooseKey = FcitxHotkeyCheckChooseKey(sym, FcitxKeyState_None, DIGIT_STR_CHOOSE);
131
if (state == FcitxKeyState_Ctrl_Alt && chooseKey >= 0)
133
FcitxCandidateWord* candidateWord = FcitxCandidateWordGetByIndex(FcitxInputStateGetCandidateList(input), chooseKey);
134
return FcitxSunpinyinDeleteCandidate(sunpinyin, candidateWord);
137
if ( (!FcitxHotkeyIsHotKeySimple(sym, state) || FcitxHotkeyIsHotKey(sym, state, FCITX_SPACE)) && view->getIC()->isEmpty())
138
return IRV_TO_PROCESS;
140
/* there is some special case that ';' is used */
141
if (FcitxHotkeyIsHotKey(sym, state, FCITX_SEMICOLON) &&
142
!(!view->getIC()->isEmpty() && fs->bUseShuangpin && (fs->SPScheme == MS2003 || fs->SPScheme == ZIGUANG)))
143
return IRV_TO_PROCESS;
145
if (FcitxHotkeyIsHotKey(sym, state, FCITX_SEPARATOR) &&
146
view->getIC()->isEmpty())
147
return IRV_TO_PROCESS;
149
if (sym == FcitxKey_KP_Enter)
150
sym = FcitxKey_Return;
152
if (FcitxHotkeyIsHotKeyDigit(sym, state))
153
return IRV_TO_PROCESS;
155
if (FcitxHotkeyIsHotKey(sym, state, FCITX_SPACE))
156
return FcitxCandidateWordChooseByIndex(FcitxInputStateGetCandidateList(input), 0);
158
if (!FcitxHotkeyIsHotKeyUAZ(sym, state)
159
&& !FcitxHotkeyIsHotKeyLAZ(sym, state)
160
&& !FcitxHotkeyIsHotKey(sym, state, FCITX_SEMICOLON)
161
&& !FcitxHotkeyIsHotKey(sym, state, FCITX_BACKSPACE)
162
&& !FcitxHotkeyIsHotKey(sym, state, FCITX_DELETE)
163
&& !FcitxHotkeyIsHotKey(sym, state, FCITX_ENTER)
164
&& !FcitxHotkeyIsHotKey(sym, state, FCITX_LEFT)
165
&& !FcitxHotkeyIsHotKey(sym, state, FCITX_RIGHT)
166
&& !FcitxHotkeyIsHotKey(sym, state, FCITX_HOME)
167
&& !FcitxHotkeyIsHotKey(sym, state, FCITX_END)
168
&& !FcitxHotkeyIsHotKey(sym, state, FCITX_SEPARATOR)
170
return IRV_TO_PROCESS;
172
if (FcitxHotkeyIsHotKey(sym, state, config->hkPrevPage) || FcitxHotkeyIsHotKey(sym, state, config->hkNextPage))
173
return IRV_TO_PROCESS;
175
windowHandler->commit_flag = false;
176
windowHandler->candidate_flag = false;
177
unsigned int changeMasks = view->onKeyEvent(CKeyEvent(sym, sym, state));
179
if (windowHandler->commit_flag)
180
return IRV_COMMIT_STRING;
181
if (!(changeMasks & CIMIView::KEYEVENT_USED))
182
return IRV_TO_PROCESS;
184
if (view->getIC()->isEmpty())
187
if (windowHandler->candidate_flag)
189
return IRV_DISPLAY_CANDWORDS;
192
return IRV_DO_NOTHING;
195
boolean FcitxSunpinyinInit(void* arg)
197
FcitxSunpinyin* sunpinyin = (FcitxSunpinyin* )arg;
198
FcitxInstanceSetContext(sunpinyin->owner, CONTEXT_IM_KEYBOARD_LAYOUT, "us");
204
* @brief function DoInput has done everything for us.
207
* @return INPUT_RETURN_VALUE
210
INPUT_RETURN_VALUE FcitxSunpinyinGetCandWords(void* arg)
212
FcitxSunpinyin* sunpinyin = (FcitxSunpinyin* )arg;
213
FcitxInstance* instance = sunpinyin->owner;
214
FcitxInputState* input = FcitxInstanceGetInputState(instance);
215
FcitxGlobalConfig* config = FcitxInstanceGetGlobalConfig(sunpinyin->owner);
216
FcitxCandidateWordSetPageSize(FcitxInputStateGetCandidateList(input), config->iMaxCandWord);
219
sunpinyin->view->getPreeditString(ppd);
220
TIConvSrcPtr src = (TIConvSrcPtr) (ppd.string());
223
while (hzlen < ppd.charTypeSize())
225
if ((ppd.charTypeAt(hzlen) & IPreeditString::HANZI_CHAR) != IPreeditString::HANZI_CHAR)
230
FcitxInstanceCleanInputWindowUp(instance);
232
memcpy(sunpinyin->front_src, src, ppd.caret() * sizeof(TWCHAR));
233
memcpy(sunpinyin->end_src, src + ppd.caret() * sizeof(TWCHAR),
234
(ppd.size() - ppd.caret() + 1) * sizeof(TWCHAR));
235
memcpy(sunpinyin->input_src, src, hzlen * sizeof(TWCHAR));
237
sunpinyin->front_src[ppd.caret()] = 0;
238
sunpinyin->end_src[ppd.size() - ppd.caret() + 1] = 0;
239
sunpinyin->input_src[hzlen] = 0;
241
memset(sunpinyin->clientpreedit, 0, FCITX_SUNPINYIN_MAX(hzlen * UTF8_MAX_LENGTH + 1, MAX_USER_INPUT + 1));
242
WCSTOMBS(sunpinyin->clientpreedit, sunpinyin->input_src, MAX_USER_INPUT);
243
FcitxMessagesAddMessageAtLast(FcitxInputStateGetClientPreedit(input), MSG_INPUT, "%s", sunpinyin->clientpreedit);
244
FcitxInputStateSetClientCursorPos(input, 0);
246
memset(sunpinyin->preedit, 0, FCITX_SUNPINYIN_MAX(ppd.size() * UTF8_MAX_LENGTH + 1, MAX_USER_INPUT + 1));
247
WCSTOMBS(sunpinyin->preedit, sunpinyin->front_src, MAX_USER_INPUT);
248
FcitxInputStateSetCursorPos(input, strlen(sunpinyin->preedit));
249
WCSTOMBS(&sunpinyin->preedit[strlen(sunpinyin->preedit)], sunpinyin->end_src, MAX_USER_INPUT);
251
FcitxInputStateSetShowCursor(input, true);
253
FcitxMessagesAddMessageAtLast(FcitxInputStateGetPreedit(input), MSG_INPUT, "%s", sunpinyin->preedit);
256
sunpinyin->view->getCandidateList(pcl, 0, sunpinyin->candNum);
257
for (int i = 0; i < pcl.size(); i ++ )
259
const TWCHAR* pcand = pcl.candiString(i);
263
int *index = (int*) fcitx_utils_malloc0(sizeof(int));
265
FcitxCandidateWord candWord;
266
candWord.callback = FcitxSunpinyinGetCandWord;
267
candWord.owner = sunpinyin;
268
candWord.priv = index;
269
candWord.strExtra = NULL;
271
wstring cand_str = pcand;
272
TIConvSrcPtr src = (TIConvSrcPtr)(cand_str.c_str());
273
WCSTOMBS(sunpinyin->ubuf, (const TWCHAR*) src, MAX_CAND_LEN);
275
candWord.strWord = strdup(sunpinyin->ubuf);
276
candWord.wordType = MSG_OTHER;
278
FcitxCandidateWordAppend(FcitxInputStateGetCandidateList(input), &candWord);
282
FcitxMessagesAddMessageAtLast(FcitxInputStateGetClientPreedit(input), MSG_INPUT, "%s", candWord.strWord);
286
return IRV_DISPLAY_CANDWORDS;
290
* @brief get the candidate word by index
292
* @param iIndex index of candidate word
293
* @return the string of canidate word
296
INPUT_RETURN_VALUE FcitxSunpinyinGetCandWord (void* arg, FcitxCandidateWord* candWord)
298
FcitxSunpinyin* sunpinyin = (FcitxSunpinyin* )arg;
299
sunpinyin->windowHandler->commit_flag = false;
300
sunpinyin->windowHandler->candidate_flag = false;
301
int* index = (int*) candWord->priv;
302
sunpinyin->view->onCandidateSelectRequest(*index);
304
if (sunpinyin->windowHandler->commit_flag)
305
return IRV_COMMIT_STRING;
307
if (sunpinyin->windowHandler->candidate_flag)
308
return IRV_DISPLAY_CANDWORDS;
310
return IRV_DO_NOTHING;
314
* @brief initialize the extra input method
317
* @return successful or not
320
void* FcitxSunpinyinCreate (FcitxInstance* instance)
322
FcitxSunpinyin* sunpinyin = (FcitxSunpinyin*) fcitx_utils_malloc0(sizeof(FcitxSunpinyin));
323
FcitxAddon* addon = FcitxAddonsGetAddonByName(FcitxInstanceGetAddons(instance), "fcitx-sunpinyin");
324
bindtextdomain("fcitx-sunpinyin", LOCALEDIR);
325
sunpinyin->owner = instance;
326
FcitxSunpinyinConfig* fs = &sunpinyin->fs;
328
if (!LoadSunpinyinConfig(&sunpinyin->fs))
333
CSunpinyinSessionFactory& fac = CSunpinyinSessionFactory::getFactory();
335
if (fs->bUseShuangpin)
336
fac.setPinyinScheme(CSunpinyinSessionFactory::SHUANGPIN);
338
fac.setPinyinScheme(CSunpinyinSessionFactory::QUANPIN);
340
ConfigSunpinyin(sunpinyin);
341
sunpinyin->bShuangpin = fs->bUseShuangpin;
343
sunpinyin->view = fac.createSession();
345
if (sunpinyin->view == NULL)
351
FcitxWindowHandler* windowHandler = new FcitxWindowHandler();
352
sunpinyin->windowHandler = windowHandler;
353
sunpinyin->view->getIC()->setCharsetLevel(3);
355
sunpinyin->view->attachWinHandler(windowHandler);
356
sunpinyin->windowHandler->SetOwner(sunpinyin);
357
ConfigSunpinyin(sunpinyin);
359
FcitxInstanceRegisterIM(instance,
366
FcitxSunpinyinDoInput,
367
FcitxSunpinyinGetCandWords,
370
ReloadConfigFcitxSunpinyin,
372
fs->iSunpinyinPriority,
376
AddFunction(addon, (void*) SunpinyinGetFullPinyin);
382
* @brief Destroy the input method while unload it.
387
void FcitxSunpinyinDestroy (void* arg)
389
FcitxSunpinyin* sunpinyin = (FcitxSunpinyin*) arg;
390
CSunpinyinSessionFactory& fac = CSunpinyinSessionFactory::getFactory();
391
fac.destroySession(sunpinyin->view);
392
if (sunpinyin->shuangpin_data)
393
delete sunpinyin->shuangpin_data;
395
if (sunpinyin->windowHandler)
396
delete sunpinyin->windowHandler;
401
INPUT_RETURN_VALUE FcitxSunpinyinDeleteCandidate (FcitxSunpinyin* sunpinyin, FcitxCandidateWord* candWord)
403
if (candWord->owner == sunpinyin)
406
sunpinyin->view->getCandidateList(pcl, 0, sunpinyin->candNum);
407
int* index = (int*) candWord->priv;
408
CIMIClassicView* classicView = (CIMIClassicView*) sunpinyin->view;
410
classicView->deleteCandidate(*index, mask);
411
return IRV_DISPLAY_CANDWORDS;
413
return IRV_TO_PROCESS;
417
* @brief Load the config file for fcitx-sunpinyin
419
* @param Bool is reload or not
421
boolean LoadSunpinyinConfig(FcitxSunpinyinConfig* fs)
423
FcitxConfigFileDesc *configDesc = GetSunpinyinConfigDesc();
427
FILE *fp = FcitxXDGGetFileUserWithPrefix("conf", "fcitx-sunpinyin.config", "rt", NULL);
432
SaveSunpinyinConfig(fs);
434
FcitxConfigFile *cfile = FcitxConfigParseConfigFileFp(fp, configDesc);
436
FcitxSunpinyinConfigConfigBind(fs, cfile, configDesc);
437
FcitxConfigBindSync(&fs->gconfig);
444
void ConfigSunpinyin(FcitxSunpinyin* sunpinyin)
446
FcitxInstance* instance = sunpinyin->owner;
447
FcitxGlobalConfig* config = FcitxInstanceGetGlobalConfig(instance);
448
FcitxSunpinyinConfig *fs = &sunpinyin->fs;
453
sunpinyin->view->setCandiWindowSize(2048);
455
CHotkeyProfile* prof = sunpinyin->view->getHotkeyProfile();
458
for (i = 0 ; i < 2; i++)
460
if (config->hkPrevPage[i].sym)
461
prof->addPageUpKey(CKeyEvent(config->hkPrevPage[i].sym, 0, config->hkPrevPage[i].state));
462
if (config->hkNextPage[i].sym)
463
prof->addPageDownKey(CKeyEvent(config->hkNextPage[i].sym, 0, config->hkNextPage[i].state));
465
sunpinyin->view->setCancelOnBackspace(1);
468
string_pairs fuzzy, correction;
469
for (i = 0; i < FUZZY_SIZE; i++)
471
fuzzy.push_back(std::make_pair<std::string, std::string>(fuzzyPairs[i][0], fuzzyPairs[i][1]));
473
for (i = 0; i < CORRECT_SIZE; i++)
474
if (fs->bAutoCorrecting[i])
475
correction.push_back(std::make_pair<std::string, std::string>(correctionPairs[i][0], correctionPairs[i][1]));
477
if (fuzzy.size() != 0)
479
AQuanpinSchemePolicy::instance().setFuzzyForwarding(true);
480
AQuanpinSchemePolicy::instance().setFuzzyPinyinPairs(fuzzy);
481
AShuangpinSchemePolicy::instance().setFuzzyForwarding(true);
482
AShuangpinSchemePolicy::instance().setFuzzyPinyinPairs(fuzzy);
486
AQuanpinSchemePolicy::instance().setFuzzyForwarding(false);
487
AQuanpinSchemePolicy::instance().clearFuzzyPinyinPairs();
488
AShuangpinSchemePolicy::instance().setFuzzyForwarding(false);
489
AShuangpinSchemePolicy::instance().clearFuzzyPinyinPairs();
492
if (correction.size() != 0)
494
AQuanpinSchemePolicy::instance().setAutoCorrecting(true);
495
AQuanpinSchemePolicy::instance().setAutoCorrectionPairs(correction);
498
AQuanpinSchemePolicy::instance().setAutoCorrecting(false);
500
if (sunpinyin->shuangpin_data == NULL)
501
sunpinyin->shuangpin_data = new CShuangpinData(fs->SPScheme);
502
AShuangpinSchemePolicy::instance().setShuangpinType(fs->SPScheme);
503
AQuanpinSchemePolicy::instance().setFuzzySegmentation(fs->bFuzzySegmentation);
504
AQuanpinSchemePolicy::instance().setInnerFuzzySegmentation(fs->bFuzzyInnerSegmentation);
507
__EXPORT_API void ReloadConfigFcitxSunpinyin(void* arg)
509
FcitxSunpinyin* sunpinyin = (FcitxSunpinyin*) arg;
510
LoadSunpinyinConfig(&sunpinyin->fs);
511
ConfigSunpinyin(sunpinyin);
515
* @brief Save the config
519
void SaveSunpinyinConfig(FcitxSunpinyinConfig* fs)
521
FcitxConfigFileDesc *configDesc = GetSunpinyinConfigDesc();
522
FILE *fp = FcitxXDGGetFileUserWithPrefix("conf", "fcitx-sunpinyin.config", "wt", NULL);
523
FcitxConfigSaveConfigFileFp(fp, &fs->gconfig, configDesc);
528
void* SunpinyinGetFullPinyin(void* arg, FcitxModuleFunctionArg args)
530
FcitxSunpinyin* sunpinyin = (FcitxSunpinyin*) arg;
531
char* pinyin = (char*) args.args[0];
532
boolean *issp = (boolean*) args.args[1];
533
*issp = sunpinyin->bShuangpin;
535
if (sunpinyin->bShuangpin)
537
sunpinyin->shuangpin_data->getMapString(pinyin, syls);
538
if (syls.size() == 0)
541
return strdup(syls[0].c_str());
547
// kate: indent-mode cstyle; space-indent on; indent-width 0;