1
/* Copyright (C) 2010~2010 by CSSlayer
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 3 of the License, or
7
(at your option) any later version.
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.
14
You should have received a copy of the GNU General Public License
15
along with this program. If not, see <http://www.gnu.org/licenses/>. */
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
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19
***************************************************************************/
17
21
#include <stdlib.h>
20
23
#include <string.h>
22
#include <fcitx-config/hotkey.h>
23
25
#include <ime-core/imi_view.h>
24
26
#include <ime-core/imi_options.h>
25
27
#include <ime-core/utils.h>
28
#include <fcitx/ime.h>
29
#include <fcitx-config/hotkey.h>
26
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>
28
38
#include <libintl.h>
30
40
#include "handler.h"
43
#define FCITX_SUNPINYIN_MAX(x, y) ((x) > (y)? (x) : (y))
39
_("Sunpinyin"), /* Name */
40
"fcitx-sunpinyin", /* IconName */
42
DoInput, /* DoInput */
43
GetCandWords, /* GetCandWords */
55
int ABI_VERSION = FCITX_ABI_VERSION;
66
static ConfigFileDesc* GetSunpinyinConfigDesc();
67
static void LoadConfig(Bool reload = False);
68
static void SaveConfig();
70
static FcitxWindowHandler* instance = NULL;
71
static CIMIView* view = NULL;
72
static ConfigFileDesc* sunpinyinConfigDesc;
73
static FcitxSunpinyinConfig fs;
60
CONFIG_DESC_DEFINE(GetSunpinyinConfigDesc, "fcitx-sunpinyin.desc")
62
boolean LoadSunpinyinConfig(FcitxSunpinyinConfig* fs);
63
static void SaveSunpinyinConfig(FcitxSunpinyinConfig* fs);
64
static void ConfigSunpinyin(FcitxSunpinyin* sunpinyin);
65
static void* SunpinyinGetFullPinyin(void* arg, FcitxModuleFunctionArg args);
66
static INPUT_RETURN_VALUE FcitxSunpinyinDeleteCandidate (FcitxSunpinyin* sunpinyin, CandidateWord* candWord);
75
69
static const char* fuzzyPairs[][2] = {
122
116
* @return INPUT_RETURN_VALUE
125
INPUT_RETURN_VALUE DoInput (unsigned int keycode, unsigned int state, int count)
119
INPUT_RETURN_VALUE FcitxSunpinyinDoInput(void* arg, FcitxKeySym sym, unsigned int state)
127
if ((keycode <= 0x20 || keycode > 0x7E) && view->getIC()->isEmpty())
128
return IRV_TO_PROCESS;
130
if (keycode == 0x003b && view->getIC()->isEmpty())
131
return IRV_TO_PROCESS;
133
if (keycode == 0xFF8D)
136
instance->commit_flag = false;
137
instance->candidate_flag = false;
138
unsigned int changeMasks = view->onKeyEvent(CKeyEvent(keycode, keycode, state));
140
if (instance->commit_flag)
141
return IRV_GET_CANDWORDS;
121
FcitxSunpinyin* sunpinyin = (FcitxSunpinyin*) arg;
122
FcitxInputState* input = FcitxInstanceGetInputState(sunpinyin->owner);
123
CIMIView* view = sunpinyin->view;
124
FcitxWindowHandler* windowHandler = sunpinyin->windowHandler;
125
FcitxSunpinyinConfig* fs = &sunpinyin->fs;
126
FcitxConfig* config = FcitxInstanceGetConfig(sunpinyin->owner);
127
CandidateWordSetChoose(FcitxInputStateGetCandidateList(input), DIGIT_STR_CHOOSE);
129
int chooseKey = CheckChooseKey(sym, KEY_NONE, DIGIT_STR_CHOOSE);
130
if (state == KEY_CTRL_ALT_COMP && chooseKey >= 0)
132
CandidateWord* candidateWord = CandidateWordGetByIndex(FcitxInputStateGetCandidateList(input), chooseKey);
133
return FcitxSunpinyinDeleteCandidate(sunpinyin, candidateWord);
136
if ( (!IsHotKeySimple(sym, state) || IsHotKey(sym, state, FCITX_SPACE)) && view->getIC()->isEmpty())
137
return IRV_TO_PROCESS;
139
/* there is some special case that ';' is used */
140
if (IsHotKey(sym, state, FCITX_SEMICOLON) &&
141
!(!view->getIC()->isEmpty() && fs->bUseShuangpin && (fs->SPScheme == MS2003 || fs->SPScheme == ZIGUANG)))
142
return IRV_TO_PROCESS;
144
if (IsHotKey(sym, state, FCITX_SEPARATOR) &&
145
view->getIC()->isEmpty())
146
return IRV_TO_PROCESS;
148
if (sym == Key_KP_Enter)
151
if (IsHotKeyDigit(sym, state))
152
return IRV_TO_PROCESS;
154
if (IsHotKey(sym, state, FCITX_SPACE))
155
return CandidateWordChooseByIndex(FcitxInputStateGetCandidateList(input), 0);
157
if (!IsHotKeyUAZ(sym, state)
158
&& !IsHotKeyLAZ(sym, state)
159
&& !IsHotKey(sym, state, FCITX_SEMICOLON)
160
&& !IsHotKey(sym, state, FCITX_BACKSPACE)
161
&& !IsHotKey(sym, state, FCITX_DELETE)
162
&& !IsHotKey(sym, state, FCITX_ENTER)
163
&& !IsHotKey(sym, state, FCITX_LEFT)
164
&& !IsHotKey(sym, state, FCITX_RIGHT)
165
&& !IsHotKey(sym, state, FCITX_HOME)
166
&& !IsHotKey(sym, state, FCITX_END)
167
&& !IsHotKey(sym, state, FCITX_SEPARATOR)
169
return IRV_TO_PROCESS;
171
if (IsHotKey(sym, state, config->hkPrevPage) || IsHotKey(sym, state, config->hkNextPage))
172
return IRV_TO_PROCESS;
174
windowHandler->commit_flag = false;
175
windowHandler->candidate_flag = false;
176
unsigned int changeMasks = view->onKeyEvent(CKeyEvent(sym, sym, state));
178
if (windowHandler->commit_flag)
179
return IRV_COMMIT_STRING;
142
180
if (!(changeMasks & CIMIView::KEYEVENT_USED))
143
181
return IRV_TO_PROCESS;
145
183
if (view->getIC()->isEmpty())
146
184
return IRV_CLEAN;
148
if (instance->candidate_flag)
186
if (windowHandler->candidate_flag)
150
188
return IRV_DISPLAY_CANDWORDS;
153
return IRV_TO_PROCESS;
191
return IRV_DO_NOTHING;
194
boolean FcitxSunpinyinInit(void* arg)
157
201
* @brief function DoInput has done everything for us.
160
204
* @return INPUT_RETURN_VALUE
163
INPUT_RETURN_VALUE GetCandWords(SEARCH_MODE searchMode)
207
INPUT_RETURN_VALUE FcitxSunpinyinGetCandWords(void* arg)
165
return IRV_DO_NOTHING;
209
FcitxSunpinyin* sunpinyin = (FcitxSunpinyin* )arg;
210
FcitxInstance* instance = sunpinyin->owner;
211
FcitxInputState* input = FcitxInstanceGetInputState(instance);
214
sunpinyin->view->getPreeditString(ppd);
215
TIConvSrcPtr src = (TIConvSrcPtr) (ppd.string());
218
while (hzlen < ppd.charTypeSize())
220
if (! (ppd.charTypeAt(hzlen) & IPreeditString::USER_CHOICE))
225
CleanInputWindowUp(instance);
227
memcpy(sunpinyin->front_src, src, ppd.caret() * sizeof(TWCHAR));
228
memcpy(sunpinyin->end_src, src + ppd.caret() * sizeof(TWCHAR),
229
(ppd.size() - ppd.caret() + 1) * sizeof(TWCHAR));
230
memcpy(sunpinyin->input_src, src, hzlen * sizeof(TWCHAR));
232
FcitxLog(INFO, "%d", ppd.candi_start());
234
sunpinyin->front_src[ppd.caret()] = 0;
235
sunpinyin->end_src[ppd.size() - ppd.caret() + 1] = 0;
236
sunpinyin->input_src[hzlen] = 0;
238
memset(sunpinyin->clientpreedit, 0, FCITX_SUNPINYIN_MAX(hzlen * UTF8_MAX_LENGTH + 1, MAX_USER_INPUT + 1));
239
WCSTOMBS(sunpinyin->clientpreedit, sunpinyin->input_src, MAX_USER_INPUT);
240
AddMessageAtLast(FcitxInputStateGetClientPreedit(input), MSG_INPUT, "%s", sunpinyin->clientpreedit);
241
FcitxInputStateSetClientCursorPos(input, 0);
243
memset(sunpinyin->preedit, 0, FCITX_SUNPINYIN_MAX(ppd.size() * UTF8_MAX_LENGTH + 1, MAX_USER_INPUT + 1));
244
WCSTOMBS(sunpinyin->preedit, sunpinyin->front_src, MAX_USER_INPUT);
245
FcitxInputStateSetCursorPos(input, strlen(sunpinyin->preedit));
246
WCSTOMBS(&sunpinyin->preedit[strlen(sunpinyin->preedit)], sunpinyin->end_src, MAX_USER_INPUT);
248
FcitxInputStateSetShowCursor(input, true);
250
AddMessageAtLast(FcitxInputStateGetPreedit(input), MSG_INPUT, "%s", sunpinyin->preedit);
253
sunpinyin->view->getCandidateList(pcl, 0, sunpinyin->candNum);
254
for (int i = 0; i < pcl.size(); i ++ )
256
const TWCHAR* pcand = pcl.candiString(i);
260
int *index = (int*) fcitx_malloc0(sizeof(int));
262
CandidateWord candWord;
263
candWord.callback = FcitxSunpinyinGetCandWord;
264
candWord.owner = sunpinyin;
265
candWord.priv = index;
266
candWord.strExtra = NULL;
268
wstring cand_str = pcand;
269
TIConvSrcPtr src = (TIConvSrcPtr)(cand_str.c_str());
270
WCSTOMBS(sunpinyin->ubuf, (const TWCHAR*) src, MAX_CAND_LEN);
272
candWord.strWord = strdup(sunpinyin->ubuf);
274
CandidateWordAppend(FcitxInputStateGetCandidateList(input), &candWord);
278
AddMessageAtLast(FcitxInputStateGetClientPreedit(input), MSG_INPUT, "%s", candWord.strWord);
282
return IRV_DISPLAY_CANDWORDS;
197
313
* @return successful or not
316
void* FcitxSunpinyinCreate (FcitxInstance* instance)
318
FcitxSunpinyin* sunpinyin = (FcitxSunpinyin*) fcitx_malloc0(sizeof(FcitxSunpinyin));
319
FcitxAddon* addon = GetAddonByName(FcitxInstanceGetAddons(instance), "fcitx-sunpinyin");
202
320
bindtextdomain("fcitx-sunpinyin", LOCALEDIR);
203
GenericConfig *fc = (GenericConfig*)EIM.fc;
204
ConfigValueType candword;
205
ConfigValueType prevpage;
206
ConfigValueType nextpage;
210
candword = ConfigGetBindValue(fc, "Appearance", "CandidateWordNumber");
211
prevpage = ConfigGetBindValue(fc, "Hotkey", "PrevPageKey");
212
nextpage = ConfigGetBindValue(fc, "Hotkey", "NextPageKey");
321
sunpinyin->owner = instance;
322
FcitxSunpinyinConfig* fs = &sunpinyin->fs;
324
if (!LoadSunpinyinConfig(&sunpinyin->fs))
214
329
CSunpinyinSessionFactory& fac = CSunpinyinSessionFactory::getFactory();
216
if (fs.bUseShuangpin)
331
if (fs->bUseShuangpin)
217
332
fac.setPinyinScheme(CSunpinyinSessionFactory::SHUANGPIN);
219
334
fac.setPinyinScheme(CSunpinyinSessionFactory::QUANPIN);
221
AShuangpinSchemePolicy::instance().setShuangpinType(fs.SPScheme);
222
AQuanpinSchemePolicy::instance().setFuzzySegmentation(fs.bFuzzySegmentation);
223
AQuanpinSchemePolicy::instance().setInnerFuzzySegmentation(fs.bFuzzyInnerSegmentation);
224
view = fac.createSession();
226
instance = new FcitxWindowHandler();
227
view->getIC()->setCharsetLevel(1);// GBK
229
view->setCandiWindowSize(*candword.integer);
230
view->attachWinHandler(instance);
232
CHotkeyProfile* prof = view->getHotkeyProfile();
336
ConfigSunpinyin(sunpinyin);
337
sunpinyin->bShuangpin = fs->bUseShuangpin;
339
sunpinyin->view = fac.createSession();
341
if (sunpinyin->view == NULL)
347
FcitxWindowHandler* windowHandler = new FcitxWindowHandler();
348
sunpinyin->windowHandler = windowHandler;
349
sunpinyin->view->getIC()->setCharsetLevel(3);
351
sunpinyin->view->attachWinHandler(windowHandler);
352
sunpinyin->windowHandler->SetOwner(sunpinyin);
353
ConfigSunpinyin(sunpinyin);
355
FcitxRegisterIMv2(instance,
362
FcitxSunpinyinDoInput,
363
FcitxSunpinyinGetCandWords,
366
ReloadConfigFcitxSunpinyin,
368
fs->iSunpinyinPriority,
372
AddFunction(addon, (void*) SunpinyinGetFullPinyin);
378
* @brief Destroy the input method while unload it.
383
void FcitxSunpinyinDestroy (void* arg)
385
FcitxSunpinyin* sunpinyin = (FcitxSunpinyin*) arg;
386
CSunpinyinSessionFactory& fac = CSunpinyinSessionFactory::getFactory();
387
fac.destroySession(sunpinyin->view);
388
if (sunpinyin->shuangpin_data)
389
delete sunpinyin->shuangpin_data;
391
if (sunpinyin->windowHandler)
392
delete sunpinyin->windowHandler;
397
INPUT_RETURN_VALUE FcitxSunpinyinDeleteCandidate (FcitxSunpinyin* sunpinyin, CandidateWord* candWord)
400
if (candWord->owner == sunpinyin)
403
sunpinyin->view->getCandidateList(pcl, 0, sunpinyin->candNum);
404
int* index = (int*) candWord->priv;
405
CIMIClassicView* classicView = (CIMIClassicView*) sunpinyin->view;
407
classicView->deleteCandidate(*index, mask);
408
return IRV_DISPLAY_CANDWORDS;
411
return IRV_TO_PROCESS;
415
* @brief Load the config file for fcitx-sunpinyin
417
* @param Bool is reload or not
419
boolean LoadSunpinyinConfig(FcitxSunpinyinConfig* fs)
421
ConfigFileDesc *configDesc = GetSunpinyinConfigDesc();
425
FILE *fp = GetXDGFileUserWithPrefix("conf", "fcitx-sunpinyin.config", "rt", NULL);
430
SaveSunpinyinConfig(fs);
432
ConfigFile *cfile = ParseConfigFileFp(fp, configDesc);
434
FcitxSunpinyinConfigConfigBind(fs, cfile, configDesc);
435
ConfigBindSync(&fs->gconfig);
442
void ConfigSunpinyin(FcitxSunpinyin* sunpinyin)
444
FcitxInstance* instance = sunpinyin->owner;
445
FcitxConfig* config = FcitxInstanceGetConfig(instance);
446
FcitxSunpinyinConfig *fs = &sunpinyin->fs;
236
for (i = 0 ; i < 2; i++)
238
if (prevpage.hotkey[i].sym)
239
prof->addPageUpKey(CKeyEvent(prevpage.hotkey[i].sym, 0, prevpage.hotkey[i].state));
240
if (nextpage.hotkey[i].sym)
241
prof->addPageDownKey(CKeyEvent(nextpage.hotkey[i].sym, 0, nextpage.hotkey[i].state));
451
sunpinyin->view->setCandiWindowSize(2048);
453
CHotkeyProfile* prof = sunpinyin->view->getHotkeyProfile();
456
for (i = 0 ; i < 2; i++)
458
if (config->hkPrevPage[i].sym)
459
prof->addPageUpKey(CKeyEvent(config->hkPrevPage[i].sym, 0, config->hkPrevPage[i].state));
460
if (config->hkNextPage[i].sym)
461
prof->addPageDownKey(CKeyEvent(config->hkNextPage[i].sym, 0, config->hkNextPage[i].state));
463
sunpinyin->view->setCancelOnBackspace(1);
244
466
string_pairs fuzzy, correction;
245
467
for (i = 0; i < FUZZY_SIZE; i++)
247
469
fuzzy.push_back(std::make_pair<std::string, std::string>(fuzzyPairs[i][0], fuzzyPairs[i][1]));
249
471
for (i = 0; i < CORRECT_SIZE; i++)
250
if (fs.bAutoCorrecting[i])
472
if (fs->bAutoCorrecting[i])
251
473
correction.push_back(std::make_pair<std::string, std::string>(correctionPairs[i][0], correctionPairs[i][1]));
253
475
if (fuzzy.size() != 0)
255
477
AQuanpinSchemePolicy::instance().setFuzzyForwarding(true);
256
478
AQuanpinSchemePolicy::instance().setFuzzyPinyinPairs(fuzzy);
479
AShuangpinSchemePolicy::instance().setFuzzyForwarding(true);
480
AShuangpinSchemePolicy::instance().setFuzzyPinyinPairs(fuzzy);
260
484
AQuanpinSchemePolicy::instance().setFuzzyForwarding(false);
261
485
AQuanpinSchemePolicy::instance().clearFuzzyPinyinPairs();
486
AShuangpinSchemePolicy::instance().setFuzzyForwarding(false);
487
AShuangpinSchemePolicy::instance().clearFuzzyPinyinPairs();
264
490
if (correction.size() != 0)
266
492
AQuanpinSchemePolicy::instance().setAutoCorrecting(true);
270
496
AQuanpinSchemePolicy::instance().setAutoCorrecting(false);
272
view->setCancelOnBackspace(1);
273
instance->set_eim(&EIM);
280
* @brief Destroy the input method while unload it.
287
CSunpinyinSessionFactory& fac = CSunpinyinSessionFactory::getFactory();
288
fac.destroySession(view);
297
* @brief Get the config description of fcitx-sunpinyin.
299
* @return ConfigFileDesc*
301
ConfigFileDesc* GetSunpinyinConfigDesc()
303
if (!sunpinyinConfigDesc)
306
tmpfp = GetXDGFileData("addon/fcitx-sunpinyin.desc", "r", NULL);
307
sunpinyinConfigDesc = ParseConfigFileDescFp(tmpfp);
311
return sunpinyinConfigDesc;
315
* @brief Load the config file for fcitx-sunpinyin
317
* @param Bool is reload or not
319
void LoadConfig(Bool reload)
321
ConfigFileDesc *configDesc = GetSunpinyinConfigDesc();
323
FILE *fp = GetXDGFileUser( "addon/fcitx-sunpinyin.config", "rt", NULL);
327
if (!reload && errno == ENOENT)
329
char *lastdomain = strdup(textdomain(NULL));
330
textdomain("fcitx-sunpinyin");
332
textdomain(lastdomain);
338
ConfigFile *cfile = ParseConfigFileFp(fp, configDesc);
342
FcitxSunpinyinConfigConfigBind(&fs, cfile, configDesc);
343
ConfigBindSync((GenericConfig*)&fs);
347
fs.bUseShuangpin = False;
348
fs.SPScheme = MS2003;
349
fs.bFuzzySegmentation = False;
350
fs.bFuzzyInnerSegmentation = False;
352
for (i = 0; i < FUZZY_SIZE; i ++)
353
fs.bFuzzy[i] = False;
355
for (i = 0; i < CORRECT_SIZE; i ++)
356
fs.bAutoCorrecting[i] = False;
498
if (sunpinyin->shuangpin_data == NULL)
499
sunpinyin->shuangpin_data = new CShuangpinData(fs->SPScheme);
500
AShuangpinSchemePolicy::instance().setShuangpinType(fs->SPScheme);
501
AQuanpinSchemePolicy::instance().setFuzzySegmentation(fs->bFuzzySegmentation);
502
AQuanpinSchemePolicy::instance().setInnerFuzzySegmentation(fs->bFuzzyInnerSegmentation);
505
__EXPORT_API void ReloadConfigFcitxSunpinyin(void* arg)
507
FcitxSunpinyin* sunpinyin = (FcitxSunpinyin*) arg;
508
LoadSunpinyinConfig(&sunpinyin->fs);
509
ConfigSunpinyin(sunpinyin);
517
void SaveSunpinyinConfig(FcitxSunpinyinConfig* fs)
368
519
ConfigFileDesc *configDesc = GetSunpinyinConfigDesc();
369
FILE *fp = GetXDGFileUser( "addon/fcitx-sunpinyin.config", "wt", NULL);
370
SaveConfigFileFp(fp, fs.gconfig.configFile, configDesc);
520
FILE *fp = GetXDGFileUserWithPrefix("conf", "fcitx-sunpinyin.config", "wt", NULL);
521
SaveConfigFileFp(fp, &fs->gconfig, configDesc);
526
void* SunpinyinGetFullPinyin(void* arg, FcitxModuleFunctionArg args)
528
FcitxSunpinyin* sunpinyin = (FcitxSunpinyin*) arg;
529
char* pinyin = (char*) args.args[0];
530
boolean *issp = (boolean*) args.args[1];
531
*issp = sunpinyin->bShuangpin;
533
if (sunpinyin->bShuangpin)
535
sunpinyin->shuangpin_data->getMapString(pinyin, syls);
536
if (syls.size() == 0)
539
return strdup(syls[0].c_str());
545
// kate: indent-mode cstyle; space-indent on; indent-width 0;