1 /***************************************************************************
2 * Copyright (C) 2002~2005 by Yuking *
3 * yuking_net@sohu.com *
4 * *
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. *
9 * *
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. *
14 * *
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 ***************************************************************************/
20 #include "config.h"
21
22 #include <libintl.h>
23 #include <stdio.h>
24 #include <limits.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <sys/stat.h>
29 #include <assert.h>
30 #include <ctype.h>
31
32 #include "fcitx/fcitx.h"
33 #include "fcitx-utils/utils.h"
34 #include "fcitx/ime.h"
35 #include "fcitx/keys.h"
36 #include "fcitx/ui.h"
37 #include "fcitx/frontend.h"
38 #include "fcitx/module.h"
39 #include "fcitx/context.h"
40 #include "fcitx/profile.h"
41 #include "fcitx/configfile.h"
42 #include "fcitx-config/xdg.h"
43 #include "fcitx-utils/utf8.h"
44 #include "fcitx-utils/log.h"
45 #include "py.h"
46 #include "PYFA.h"
47 #include "pyParser.h"
48 #include "sp.h"
49 #include "pyconfig.h"
50 #include "spdata.h"
51 #include "module/quickphrase/fcitx-quickphrase.h"
52
53 #define PY_INDEX_MAGIC_NUMBER 0xf7462e34
54 #define PINYIN_TEMP_FILE "pinyin_XXXXXX"
55
56 typedef struct {
57 PY_CAND_WORD_TYPE type;
58 ADJUSTORDER order;
59 FcitxPinyinState* pystate;
60 } PYCandWordSortContext;
61
62 static void LoadPYPhraseDict(FcitxPinyinState* pystate, FILE* fp,
63 boolean isSystem, boolean stripDup);
64 static void ReloadConfigPY(void* arg);
65 static void PinyinMigration();
66 static int PYCandWordCmp(const void* b, const void* a, void* arg);
67 static boolean PYGetPYMapByHZ(FcitxPinyinState*pystate, char *strHZ,
68 char* mapHint, char *strMap);
69
70 FCITX_DEFINE_PLUGIN(fcitx_pinyin, ime2, FcitxIMClass2) = {
71 PYCreate,
72 PYDestroy,
73 ReloadConfigPY,
74 NULL,
75 NULL,
76 NULL,
77 NULL,
78 NULL
79 };
80
DECLARE_ADDFUNCTIONS(Pinyin)81 DECLARE_ADDFUNCTIONS(Pinyin)
82
83 void *PYCreate(FcitxInstance* instance)
84 {
85 FcitxPinyinState *pystate = fcitx_utils_new(FcitxPinyinState);
86 InitMHPY(&pystate->pyconfig.MHPY_C, MHPY_C_TEMPLATE);
87 InitMHPY(&pystate->pyconfig.MHPY_S, MHPY_S_TEMPLATE);
88 InitPYTable(&pystate->pyconfig);
89 InitPYSplitData(&pystate->pyconfig);
90 if (!LoadPYConfig(&pystate->pyconfig)) {
91 free(pystate->pyconfig.MHPY_C);
92 free(pystate->pyconfig.MHPY_S);
93 free(pystate->pyconfig.PYTable);
94 FreePYSplitData(&pystate->pyconfig);
95 free(pystate);
96 return NULL;
97 }
98
99 PinyinMigration();
100
101 pystate->pool = fcitx_memory_pool_create();
102
103 FcitxInstanceRegisterIM(instance,
104 pystate,
105 "pinyin",
106 _("Pinyin"),
107 "pinyin",
108 PYInit,
109 ResetPYStatus,
110 DoPYInput,
111 PYGetCandWords,
112 NULL,
113 SavePY,
114 NULL,
115 NULL,
116 5,
117 "zh_CN");
118 FcitxInstanceRegisterIM(instance,
119 pystate,
120 "shuangpin",
121 _("Shuangpin"),
122 "shuangpin",
123 SPInit,
124 ResetPYStatus,
125 DoPYInput,
126 PYGetCandWords,
127 NULL,
128 SavePY,
129 NULL,
130 NULL,
131 5,
132 "zh_CN");
133 pystate->owner = instance;
134
135 FcitxPinyinAddFunctions(instance);
136 return pystate;
137 }
138
PYDestroy(void * arg)139 void PYDestroy(void* arg)
140 {
141 FcitxPinyinState *pystate = (FcitxPinyinState*)arg;
142 free(pystate->pyconfig.MHPY_C);
143 free(pystate->pyconfig.MHPY_S);
144 free(pystate->pyconfig.PYTable);
145 FreePYSplitData(&pystate->pyconfig);
146 FcitxConfigFree(&pystate->pyconfig.gconfig);
147 fcitx_memory_pool_destroy(pystate->pool);
148
149 int i, j, k;
150 PYFA *PYFAList = pystate->PYFAList;
151 for (i = 0; i < pystate->iPYFACount; i++) {
152 for (j = 0; j < PYFAList[i].iBase; j++) {
153 PyPhrase* phrase = USER_PHRASE_NEXT(PYFAList[i].pyBase[j].userPhrase);
154 for (k = 0; k < PYFAList[i].pyBase[j].iUserPhrase; k++) {
155 PyPhrase* cur = phrase;
156 fcitx_utils_free(cur->strPhrase);
157 fcitx_utils_free(cur->strMap);
158 phrase = USER_PHRASE_NEXT(phrase);
159 free(cur);
160 }
161
162 free(PYFAList[i].pyBase[j].userPhrase);
163 fcitx_utils_free(PYFAList[i].pyBase[j].phrase);
164 }
165 free(PYFAList[i].pyBase);
166 }
167 free(PYFAList);
168
169 while(pystate->pyFreq) {
170 PyFreq* pCurFreq = pystate->pyFreq;
171 pystate->pyFreq = pCurFreq->next;
172 while (pCurFreq->HZList) {
173 HZ* pHZ = pCurFreq->HZList;
174 pCurFreq->HZList = pHZ->next;
175 free(pHZ);
176 }
177 free(pCurFreq);
178 }
179
180 free(pystate);
181 }
182
PYInit(void * arg)183 boolean PYInit(void *arg)
184 {
185 FcitxPinyinState *pystate = (FcitxPinyinState*)arg;
186 boolean flag = true;
187 FcitxInstanceSetContext(pystate->owner, CONTEXT_IM_KEYBOARD_LAYOUT, "us");
188 FcitxInstanceSetContext(pystate->owner, CONTEXT_SHOW_REMIND_STATUS, &flag);
189 pystate->bSP = false;
190 return true;
191 }
192
SPInit(void * arg)193 boolean SPInit(void *arg)
194 {
195 FcitxPinyinState *pystate = (FcitxPinyinState*)arg;
196 boolean flag = true;
197 FcitxInstanceSetContext(pystate->owner, CONTEXT_IM_KEYBOARD_LAYOUT, "us");
198 FcitxInstanceSetContext(pystate->owner, CONTEXT_SHOW_REMIND_STATUS, &flag);
199 pystate->bSP = true;
200 FcitxPinyinConfig* pyconfig = &pystate->pyconfig;
201 pyconfig->cNonS = 'o';
202 memcpy(pyconfig->SPMap_S, SPMap_S_Ziranma, sizeof(SPMap_S_Ziranma));
203 memcpy(pyconfig->SPMap_C, SPMap_C_Ziranma, sizeof(SPMap_C_Ziranma));
204
205 LoadSPData(pystate);
206 return true;
207 }
208
LoadPYBaseDict(FcitxPinyinState * pystate)209 boolean LoadPYBaseDict(FcitxPinyinState *pystate)
210 {
211 FILE *fp;
212 int i, j;
213 int32_t iLen;
214
215 fp = FcitxXDGGetFileWithPrefix("pinyin", PY_BASE_FILE, "r", NULL);
216 if (!fp)
217 return false;
218
219 fcitx_utils_read_int32(fp, &pystate->iPYFACount);
220 pystate->PYFAList = (PYFA*)fcitx_utils_malloc0(sizeof(PYFA) * pystate->iPYFACount);
221 PYFA *PYFAList = pystate->PYFAList;
222 for (i = 0; i < pystate->iPYFACount; i++) {
223 fread(PYFAList[i].strMap, sizeof(char) * 2, 1, fp);
224 PYFAList[i].strMap[2] = '\0';
225
226 fcitx_utils_read_int32(fp, &PYFAList[i].iBase);
227 PYFAList[i].pyBase = (PyBase*)fcitx_utils_malloc0(sizeof(PyBase) * PYFAList[i].iBase);
228 for (j = 0; j < PYFAList[i].iBase; j++) {
229 int8_t len;
230 fread(&len, sizeof(char), 1, fp);
231 fread(PYFAList[i].pyBase[j].strHZ, sizeof(char) * len, 1, fp);
232 PYFAList[i].pyBase[j].strHZ[len] = '\0';
233 fcitx_utils_read_int32(fp, &iLen);
234 PYFAList[i].pyBase[j].iIndex = iLen;
235 PYFAList[i].pyBase[j].iHit = 0;
236 if (iLen > pystate->iCounter)
237 pystate->iCounter = iLen;
238 PYFAList[i].pyBase[j].iPhrase = 0;
239 PYFAList[i].pyBase[j].iUserPhrase = 0;
240 PYFAList[i].pyBase[j].userPhrase = fcitx_utils_new(PyUsrPhrase);
241 PYFAList[i].pyBase[j].userPhrase->next = PYFAList[i].pyBase[j].userPhrase;
242 }
243 }
244
245 fclose(fp);
246 pystate->bPYBaseDictLoaded = true;
247
248 pystate->iOrigCounter = pystate->iCounter;
249
250 pystate->pyFreq = fcitx_utils_new(PyFreq);
251 // pystate->pyFreq->next = NULL;
252
253 return true;
254 }
255
LoadPYPhraseDict(FcitxPinyinState * pystate,FILE * fp,boolean isSystem,boolean stripDup)256 void LoadPYPhraseDict(FcitxPinyinState* pystate, FILE *fp, boolean isSystem, boolean stripDup)
257 {
258 int j, k;
259 int32_t i, count, iLen;
260 char strBase[UTF8_MAX_LENGTH + 1];
261 PyPhrase *phrase = NULL, *temp;
262 PYFA* PYFAList = pystate->PYFAList;
263 while (!feof(fp)) {
264 int8_t clen;
265 if (!fcitx_utils_read_int32(fp, &i))
266 break;
267 if (!fread(&clen, sizeof(int8_t), 1, fp))
268 break;
269 if (clen <= 0 || clen > UTF8_MAX_LENGTH)
270 break;
271 if (!fread(strBase, sizeof(char) * clen, 1, fp))
272 break;
273 strBase[clen] = '\0';
274 if (!fcitx_utils_read_int32(fp, &count))
275 break;
276
277 j = GetBaseIndex(pystate, i, strBase);
278 if (j == -1)
279 break;
280
281 if (isSystem) {
282 phrase = (PyPhrase*)fcitx_utils_malloc0(sizeof(PyPhrase) * count);
283 temp = phrase;
284 } else {
285 PYFAList[i].pyBase[j].iUserPhrase = count;
286 temp = &PYFAList[i].pyBase[j].userPhrase->phrase;
287 }
288
289 for (k = 0; k < count; k++) {
290 if (!isSystem)
291 phrase = (PyPhrase*)fcitx_utils_malloc0(sizeof(PyUsrPhrase));
292
293 fcitx_utils_read_int32(fp, &iLen);
294
295 if (isSystem) {
296 phrase->strMap = (char*)fcitx_memory_pool_alloc(pystate->pool, sizeof(char) * (iLen + 1));
297 } else {
298 phrase->strMap = (char*)fcitx_utils_malloc0(sizeof(char) * (iLen + 1));
299 }
300 fread(phrase->strMap, sizeof(char) * iLen, 1, fp);
301 phrase->strMap[iLen] = '\0';
302
303 fcitx_utils_read_int32(fp, &iLen);
304
305 if (isSystem) {
306 phrase->strPhrase = (char*)fcitx_memory_pool_alloc(pystate->pool, sizeof(char) * (iLen + 1));
307 } else {
308 phrase->strPhrase = (char*)fcitx_utils_malloc0(sizeof(char) * (iLen + 1));
309 }
310 fread(phrase->strPhrase, sizeof(char) * iLen, 1, fp);
311 phrase->strPhrase[iLen] = '\0';
312
313 fcitx_utils_read_int32(fp, &iLen);
314 phrase->iIndex = iLen;
315 if (iLen > pystate->iCounter)
316 pystate->iCounter = iLen;
317 if (isSystem) {
318 phrase->iHit = 0;
319 phrase ++;
320 } else {
321 fcitx_utils_read_int32(fp, &iLen);
322 phrase->iHit = iLen;
323
324 ((PyUsrPhrase*)phrase)->next = ((PyUsrPhrase*) temp)->next;
325 ((PyUsrPhrase*)temp)->next = (PyUsrPhrase*) phrase;
326
327 temp = phrase;
328 }
329 }
330
331 if (isSystem) {
332 if (PYFAList[i].pyBase[j].iPhrase == 0) {
333 PYFAList[i].pyBase[j].iPhrase = count;
334 PYFAList[i].pyBase[j].phrase = temp;
335 } else {
336 int m, n;
337 boolean *flag = fcitx_utils_malloc0(sizeof(boolean) * count);
338 int left = count;
339 phrase = temp;
340 if (stripDup) {
341 for (m = 0; m < count; m++) {
342 for (n = 0; n < PYFAList[i].pyBase[j].iPhrase; n++) {
343 int result = strcmp(PYFAList[i].pyBase[j].phrase[n].strMap, phrase[m].strMap);
344 if (result == 0) {
345 if (strcmp(PYFAList[i].pyBase[j].phrase[n].strPhrase, phrase[m].strPhrase) == 0)
346 break;
347 }
348 }
349 if (n != PYFAList[i].pyBase[j].iPhrase) {
350 flag[m] = 1;
351 left -- ;
352 }
353 }
354 }
355 int orig = PYFAList[i].pyBase[j].iPhrase;
356 if (left >= 0) {
357 PYFAList[i].pyBase[j].iPhrase += left;
358 PYFAList[i].pyBase[j].phrase = realloc(PYFAList[i].pyBase[j].phrase, sizeof(PyPhrase) * PYFAList[i].pyBase[j].iPhrase);
359 //memcpy(phrase, oldph, sizeof(PyPhrase) * old);
360 }
361 for (m = 0; m < count; m ++) {
362 if (!flag[m]) {
363 memcpy(&PYFAList[i].pyBase[j].phrase[orig], &phrase[m], sizeof(PyPhrase));
364 orig ++ ;
365 }
366 else {
367 // free(phrase[m].strMap);
368 // free(phrase[m].strPhrase);
369 }
370 }
371 assert(orig == PYFAList[i].pyBase[j].iPhrase);
372 free(flag);
373 free(phrase);
374 }
375 }
376 }
377 }
378
LoadPYOtherDict(FcitxPinyinState * pystate)379 boolean LoadPYOtherDict(FcitxPinyinState* pystate)
380 {
381 //下面开始读系统词组
382 FILE *fp;
383 int32_t i, j, k, iLen;
384 uint32_t iIndex;
385 PyFreq *pyFreqTemp, *pPyFreq;
386 HZ *HZTemp, *pHZ;
387 PYFA* PYFAList = pystate->PYFAList;
388
389 pystate->bPYOtherDictLoaded = true;
390
391 fp = FcitxXDGGetFileWithPrefix("pinyin", PY_PHRASE_FILE, "r", NULL);
392 if (!fp)
393 FcitxLog(ERROR, _("Cannot find System Database of Pinyin!"));
394 else {
395 LoadPYPhraseDict(pystate, fp, true, false);
396 fclose(fp);
397 FcitxStringHashSet *sset = FcitxXDGGetFiles("pinyin", NULL, ".mb");
398 FcitxStringHashSet *curStr = sset;
399 while (curStr) {
400 if (strcmp(curStr->name, PY_PHRASE_FILE) != 0
401 && strcmp(curStr->name, PY_USERPHRASE_FILE) != 0
402 && strcmp(curStr->name, PY_SYMBOL_FILE) != 0
403 && strcmp(curStr->name, PY_BASE_FILE) != 0
404 && strcmp(curStr->name, PY_FREQ_FILE) != 0) {
405
406 fp = FcitxXDGGetFileWithPrefix("pinyin", curStr->name, "r", NULL);
407 if (fp) {
408 LoadPYPhraseDict(pystate, fp, true, true);
409 fclose(fp);
410 }
411 }
412 curStr = curStr->hh.next;
413 }
414
415 fcitx_utils_free_string_hash_set(sset);
416
417 pystate->iOrigCounter = pystate->iCounter;
418 }
419
420 //下面开始读取用户词库
421 fp = FcitxXDGGetFileUserWithPrefix("pinyin", PY_USERPHRASE_FILE, "r", NULL);
422 if (fp) {
423 LoadPYPhraseDict(pystate, fp, false, false);
424 fclose(fp);
425 }
426 //下面读取索引文件
427 fp = FcitxXDGGetFileUserWithPrefix("pinyin", PY_INDEX_FILE, "r", NULL);
428 if (fp) {
429 uint32_t magic = 0;
430 fcitx_utils_read_uint32(fp, &magic);
431 if (magic == PY_INDEX_MAGIC_NUMBER) {
432 fcitx_utils_read_int32(fp, &iLen);
433 if (iLen > pystate->iCounter)
434 pystate->iCounter = iLen;
435 while (!feof(fp)) {
436 fcitx_utils_read_int32(fp, &i);
437 fcitx_utils_read_int32(fp, &j);
438 fcitx_utils_read_int32(fp, &k);
439 fcitx_utils_read_uint32(fp, &iIndex);
440 fcitx_utils_read_int32(fp, &iLen);
441
442 if (i < pystate->iPYFACount) {
443 if (j < PYFAList[i].iBase) {
444 if (k < PYFAList[i].pyBase[j].iPhrase) {
445 if (k >= 0) {
446 PYFAList[i].pyBase[j].phrase[k].iIndex = iIndex;
447 PYFAList[i].pyBase[j].phrase[k].iHit = iLen;
448 } else {
449 PYFAList[i].pyBase[j].iIndex = iIndex;
450 PYFAList[i].pyBase[j].iHit = iLen;
451 }
452 }
453 }
454 }
455 }
456 } else {
457 FcitxLog(WARNING, _("Pinyin Index Magic Number Doesn't match"));
458 }
459
460 fclose(fp);
461 }
462 //下面读取常用词表
463 fp = FcitxXDGGetFileUserWithPrefix("pinyin", PY_FREQ_FILE, "r", NULL);
464 if (fp) {
465 pPyFreq = pystate->pyFreq;
466
467 fcitx_utils_read_uint32(fp, &pystate->iPYFreqCount);
468
469 for (i = 0; i < pystate->iPYFreqCount; i++) {
470 pyFreqTemp = fcitx_utils_new(PyFreq);
471 // pyFreqTemp->next = NULL;
472
473 fread(pyFreqTemp->strPY, sizeof(char) * 11, 1, fp);
474 fcitx_utils_read_uint32(fp, &pyFreqTemp->iCount);
475
476 pyFreqTemp->HZList = fcitx_utils_new(HZ);
477 // pyFreqTemp->HZList->next = NULL;
478 pHZ = pyFreqTemp->HZList;
479
480 for (k = 0; k < pyFreqTemp->iCount; k++) {
481 int8_t slen;
482 HZTemp = fcitx_utils_new(HZ);
483 fread(&slen, sizeof(int8_t), 1, fp);
484 fread(HZTemp->strHZ, sizeof(char) * slen, 1, fp);
485 HZTemp->strHZ[slen] = '\0';
486 fcitx_utils_read_int32(fp, &HZTemp->iPYFA);
487 fcitx_utils_read_uint32(fp, &HZTemp->iHit);
488 fcitx_utils_read_uint32(fp, &HZTemp->iIndex);
489 pHZ->next = HZTemp;
490 pHZ = HZTemp;
491 }
492
493 pPyFreq->next = pyFreqTemp;
494 pPyFreq = pyFreqTemp;
495 }
496
497 fclose(fp);
498 }
499 return true;
500 }
501
ResetPYStatus(void * arg)502 void ResetPYStatus(void* arg)
503 {
504 FcitxPinyinState *pystate = (FcitxPinyinState*)arg;
505 pystate->iPYInsertPoint = 0;
506 pystate->iPYSelected = 0;
507 pystate->strFindString[0] = '\0';
508 pystate->strPYAuto[0] = '\0';
509
510 pystate->bIsPYAddFreq = false;
511 pystate->bIsPYDelFreq = false;
512 pystate->bIsPYDelUserPhr = false;
513
514 pystate->findMap.iMode = PARSE_SINGLEHZ; //只要不是PARSE_ERROR就可以
515 }
516
GetBaseIndex(FcitxPinyinState * pystate,int32_t iPYFA,char * strBase)517 int GetBaseIndex(FcitxPinyinState* pystate, int32_t iPYFA, char *strBase)
518 {
519 int i;
520
521 if (iPYFA < pystate->iPYFACount) {
522 for (i = 0; i < pystate->PYFAList[iPYFA].iBase; i++) {
523 if (!strcmp(strBase, pystate->PYFAList[iPYFA].pyBase[i].strHZ))
524 return i;
525 }
526 }
527
528 return -1;
529 }
530
DoPYInput(void * arg,FcitxKeySym sym,unsigned int state)531 INPUT_RETURN_VALUE DoPYInput(void* arg, FcitxKeySym sym, unsigned int state)
532 {
533 FcitxPinyinState *pystate = (FcitxPinyinState*) arg;
534 FcitxInputState *input = FcitxInstanceGetInputState(pystate->owner);
535 int i = 0;
536 int val;
537 INPUT_RETURN_VALUE retVal;
538 FcitxCandidateWordList *candList = FcitxInputStateGetCandidateList(input);
539
540 if (sym == 0 && state == 0)
541 sym = FcitxKey_VoidSymbol;
542
543 if (!pystate->bPYBaseDictLoaded)
544 LoadPYBaseDict(pystate);
545 if (!pystate->bPYOtherDictLoaded)
546 LoadPYOtherDict(pystate);
547
548 retVal = IRV_TO_PROCESS;
549
550 /* is not in py special state */
551 if (!pystate->bIsPYAddFreq && !pystate->bIsPYDelFreq && !pystate->bIsPYDelUserPhr) {
552 if ((FcitxHotkeyIsHotKeyLAZ(sym, state)
553 || FcitxHotkeyIsHotKey(sym, state, FCITX_SEPARATOR)
554 || (pystate->bSP && FcitxInputStateGetRawInputBufferSize(input) > 0 && pystate->bSP_UseSemicolon && FcitxHotkeyIsHotKey(sym, state, FCITX_SEMICOLON)))) {
555 FcitxInputStateSetIsInRemind(input, false);
556 FcitxInputStateSetShowCursor(input, true);
557
558 /* we cannot insert seperator in the first, nor there is a existing separator */
559 if (FcitxHotkeyIsHotKey(sym, state, FCITX_SEPARATOR)) {
560 if (!pystate->iPYInsertPoint)
561 return IRV_TO_PROCESS;
562 if (pystate->strFindString[pystate->iPYInsertPoint - 1] == PY_SEPARATOR)
563 return IRV_DO_NOTHING;
564 }
565
566 val = i = strlen(pystate->strFindString);
567
568 if (!pystate->bSP &&
569 pystate->pyconfig.bUseVForQuickPhrase && i == 0 &&
570 FcitxHotkeyIsKey(sym, state, FcitxKey_v, FcitxKeyState_None)) {
571 int key = sym;
572 boolean useDup = false;
573 boolean append = true;
574 if (FcitxQuickPhraseLaunch(pystate->owner, &key,
575 &useDup, &append))
576 return IRV_DISPLAY_MESSAGE;
577 }
578
579 /* do the insert */
580 for (; i > pystate->iPYInsertPoint; i--)
581 pystate->strFindString[i] = pystate->strFindString[i - 1];
582
583 pystate->strFindString[pystate->iPYInsertPoint++] = sym;
584 pystate->strFindString[val + 1] = '\0';
585 ParsePY(&pystate->pyconfig, pystate->strFindString, &pystate->findMap, PY_PARSE_INPUT_USER, pystate->bSP);
586
587 val = 0;
588 for (i = 0; i < pystate->iPYSelected; i++)
589 val += fcitx_utf8_strlen(pystate->pySelected[i].strHZ);
590
591 retVal = IRV_DISPLAY_CANDWORDS;
592 if (pystate->findMap.iHZCount > (MAX_WORDS_USER_INPUT - val)) {
593 UpdateFindString(pystate, val);
594 ParsePY(&pystate->pyconfig, pystate->strFindString, &pystate->findMap, PY_PARSE_INPUT_USER, pystate->bSP);
595 retVal = IRV_DO_NOTHING;
596 }
597
598 } else if (FcitxHotkeyIsHotKey(sym, state, FCITX_BACKSPACE)) {
599 if (pystate->iPYSelected) {
600 char strTemp[MAX_USER_INPUT + 1];
601
602 val = strlen(pystate->strFindString);
603 strcpy(strTemp, pystate->pySelected[pystate->iPYSelected - 1].strPY);
604 strcat(strTemp, pystate->strFindString);
605 strcpy(pystate->strFindString, strTemp);
606 pystate->iPYInsertPoint += strlen(pystate->strFindString) - val;
607 pystate->iPYSelected--;
608 ParsePY(&pystate->pyconfig, pystate->strFindString, &pystate->findMap, PY_PARSE_INPUT_USER, pystate->bSP);
609
610 retVal = IRV_DISPLAY_CANDWORDS;
611 } else if (pystate->iPYInsertPoint) {
612 char *move_src = (pystate->strFindString
613 + pystate->iPYInsertPoint);
614 /* we cannot delete it if cursor is at the first */
615 val = ((pystate->iPYInsertPoint > 1)
616 && (move_src[-2] == PY_SEPARATOR)) ? 2 : 1;
617 memmove(move_src - val, move_src, strlen(move_src) + 1);
618 ParsePY(&pystate->pyconfig, pystate->strFindString,
619 &pystate->findMap, PY_PARSE_INPUT_USER, pystate->bSP);
620 pystate->iPYInsertPoint -= val;
621
622 if (!strlen(pystate->strFindString)) {
623 retVal = IRV_CLEAN;
624 } else {
625 retVal = IRV_DISPLAY_CANDWORDS;
626 }
627 } else {
628 if (!strlen(pystate->strFindString)) {
629 retVal = IRV_TO_PROCESS;
630 } else {
631 retVal = IRV_DO_NOTHING;
632 }
633 }
634 } else if (FcitxInputStateGetRawInputBufferSize(input) && FcitxHotkeyIsHotKey(sym, state, FCITX_DELETE)) {
635 if (pystate->iPYInsertPoint == strlen(pystate->strFindString))
636 retVal = IRV_DO_NOTHING;
637 char *move_dst = (pystate->strFindString
638 + pystate->iPYInsertPoint);
639 val = (move_dst[1] == PY_SEPARATOR) ? 2 : 1;
640 memmove(move_dst, move_dst + val, strlen(move_dst + val) + 1);
641
642 ParsePY(&pystate->pyconfig, pystate->strFindString,
643 &pystate->findMap, PY_PARSE_INPUT_USER, pystate->bSP);
644 if (!strlen(pystate->strFindString)) {
645 retVal = IRV_CLEAN;
646 } else {
647 retVal = IRV_DISPLAY_CANDWORDS;
648 }
649 } else if (FcitxInputStateGetRawInputBufferSize(input) && FcitxHotkeyIsHotKey(sym, state, FCITX_HOME)) {
650 pystate->iPYInsertPoint = 0;
651 retVal = IRV_DISPLAY_CANDWORDS;
652 } else if (FcitxInputStateGetRawInputBufferSize(input) && FcitxHotkeyIsHotKey(sym, state, FCITX_END)) {
653 pystate->iPYInsertPoint = strlen(pystate->strFindString);
654 retVal = IRV_DISPLAY_CANDWORDS;
655 } else if (FcitxInputStateGetRawInputBufferSize(input) && FcitxHotkeyIsHotKey(sym, state, FCITX_RIGHT)) {
656 if (pystate->iPYInsertPoint == strlen(pystate->strFindString)) {
657 retVal = IRV_DO_NOTHING;
658 } else {
659 pystate->iPYInsertPoint++;
660 retVal = IRV_DISPLAY_CANDWORDS;
661 }
662 } else if (FcitxInputStateGetRawInputBufferSize(input) && FcitxHotkeyIsHotKey(sym, state, FCITX_LEFT)) {
663 if (pystate->iPYInsertPoint <= 0) {
664 if (pystate->iPYSelected) {
665 char strTemp[MAX_USER_INPUT + 1];
666
667 val = strlen(pystate->strFindString);
668 strcpy(strTemp, pystate->pySelected[pystate->iPYSelected - 1].strPY);
669 strcat(strTemp, pystate->strFindString);
670 strcpy(pystate->strFindString, strTemp);
671 pystate->iPYInsertPoint = strlen(pystate->strFindString) - val;
672 pystate->iPYSelected--;
673 ParsePY(&pystate->pyconfig, pystate->strFindString, &pystate->findMap, PY_PARSE_INPUT_USER, pystate->bSP);
674
675 retVal = IRV_DISPLAY_CANDWORDS;
676 } else {
677 retVal = IRV_DO_NOTHING;
678 }
679 } else {
680 pystate->iPYInsertPoint--;
681 retVal = IRV_DISPLAY_CANDWORDS;
682 }
683 } else if (FcitxHotkeyIsHotKey(sym, state, FCITX_SPACE)) {
684 if (FcitxCandidateWordPageCount(candList) == 0) {
685 if (FcitxInputStateGetRawInputBufferSize(input) == 0)
686 retVal = IRV_TO_PROCESS;
687 else
688 retVal = IRV_DO_NOTHING;
689 } else {
690 retVal = FcitxCandidateWordChooseByIndex(candList, 0);
691 }
692 } else if (FcitxInputStateGetRawInputBufferSize(input) && FcitxHotkeyIsHotKey(sym, state, FCITX_ENTER)) {
693 char* outputString = FcitxInputStateGetOutputString(input);
694 strcpy(outputString, "");
695 if (pystate->iPYSelected) {
696 for (i = 0; i < pystate->iPYSelected; i++) {
697 strcat(outputString, pystate->pySelected[i].strHZ);
698 }
699 }
700
701 for (i = 0; i < pystate->findMap.iHZCount; i++) {
702 strcat(outputString, pystate->findMap.strPYParsed[i]);
703 }
704 retVal = IRV_COMMIT_STRING;
705 } else if (FcitxHotkeyIsHotKey(sym, state, pystate->pyconfig.hkPYDelUserPhr)) {
706 if (!pystate->bIsPYDelUserPhr) {
707 int i;
708 FcitxCandidateWord* candWord = NULL;
709 for (i = 0;
710 (candWord = FcitxCandidateWordGetByIndex(candList, i));
711 i++) {
712 if (candWord->owner == pystate) {
713 PYCandWord* pycandWord = candWord->priv;
714 if (pycandWord->iWhich == PY_CAND_USERPHRASE)
715 break;
716 }
717 }
718
719 if (!candWord) {
720 retVal = IRV_TO_PROCESS;
721 } else {
722
723 pystate->bIsPYDelUserPhr = true;
724 FcitxInputStateSetIsDoInputOnly(input, true);
725
726 FcitxInstanceCleanInputWindowUp(pystate->owner);
727 FcitxMessagesAddMessageStringsAtLast(
728 FcitxInputStateGetAuxUp(input), MSG_TIPS,
729 _("Press index to delete user phrase (ESC for cancel)"));
730 FcitxInputStateSetShowCursor(input, false);
731
732 return IRV_DISPLAY_MESSAGE;
733 }
734 }
735 } else if (FcitxHotkeyIsHotKey(sym, state, pystate->pyconfig.hkPYAddFreq)) {
736 if (!pystate->bIsPYAddFreq && pystate->findMap.iHZCount == 1 && FcitxInputStateGetRawInputBufferSize(input)) {
737 pystate->bIsPYAddFreq = true;
738 FcitxInputStateSetIsDoInputOnly(input, true);
739
740 FcitxInstanceCleanInputWindowUp(pystate->owner);
741 FcitxMessagesAddMessageStringsAtLast(
742 FcitxInputStateGetAuxUp(input), MSG_TIPS,
743 _("Press number to make word in frequent list"));
744 FcitxInputStateSetShowCursor(input, false);
745
746 return IRV_DISPLAY_MESSAGE;
747 }
748 } else if (FcitxHotkeyIsHotKey(sym, state, pystate->pyconfig.hkPYDelFreq)) {
749 if (!pystate->bIsPYDelFreq) {
750 val = 0;
751 int i;
752 FcitxCandidateWord* candWord = NULL;
753 for (i = 0;
754 (candWord = FcitxCandidateWordGetByIndex(candList, i));
755 i++) {
756 if (candWord->owner == pystate) {
757 PYCandWord* pycandWord = candWord->priv;
758 if (pycandWord->iWhich == PY_CAND_FREQ) {
759 val = i + 1;
760 }
761 }
762 }
763
764 if (val == 0)
765 return IRV_DO_NOTHING;
766
767 FcitxInstanceCleanInputWindowUp(pystate->owner);
768 if (val == 1) {
769 FcitxMessagesAddMessageAtLast(FcitxInputStateGetAuxUp(input), MSG_TIPS, _("Press 1 to delete %s in frequent list (ESC for cancel)"), pystate->strFindString);
770 } else {
771 FcitxMessagesAddMessageAtLast(FcitxInputStateGetAuxUp(input), MSG_TIPS, _("Press 1-%d to delete %s in frequent list (ESC for cancel)"), val, pystate->strFindString);
772 }
773
774 pystate->bIsPYDelFreq = true;
775 FcitxInputStateSetIsDoInputOnly(input, true);
776
777 FcitxInputStateSetShowCursor(input, false);
778
779 return IRV_DISPLAY_MESSAGE;
780 }
781 }
782 }
783
784 int iKey;
785 iKey = FcitxCandidateWordCheckChooseKey(candList, sym, state);
786 if (retVal == IRV_TO_PROCESS) {
787 if (iKey >= 0) {
788 FcitxCandidateWord *candWord;
789 candWord = FcitxCandidateWordGetByIndex(candList, iKey);
790 if (!FcitxInputStateGetIsInRemind(input)) {
791 if (!FcitxInputStateGetRawInputBufferSize(input))
792 return IRV_TO_PROCESS;
793 else if (candWord == NULL)
794 return IRV_DO_NOTHING;
795 else {
796 if (candWord->owner == pystate && (pystate->bIsPYAddFreq || pystate->bIsPYDelFreq || pystate->bIsPYDelUserPhr)) {
797 PYCandWord* pycandWord = candWord->priv;
798 if (pystate->bIsPYAddFreq) {
799 PYAddFreq(pystate, pycandWord);
800 pystate->bIsPYAddFreq = false;
801 } else if (pystate->bIsPYDelFreq) {
802 PYDelFreq(pystate, pycandWord);
803 pystate->bIsPYDelFreq = false;
804 } else {
805 if (pycandWord->iWhich == PY_CAND_USERPHRASE)
806 PYDelUserPhrase(pystate, pycandWord->cand.phrase.iPYFA,
807 pycandWord->cand.phrase.iBase, (PyUsrPhrase*) pycandWord->cand.phrase.phrase);
808 pystate->bIsPYDelUserPhr = false;
809 }
810 FcitxInputStateSetIsDoInputOnly(input, false);
811 FcitxInputStateSetShowCursor(input, true);
812
813 retVal = IRV_DISPLAY_CANDWORDS;
814 }
815 }
816 }
817 } else if (sym == FcitxKey_VoidSymbol) {
818 ParsePY(&pystate->pyconfig, pystate->strFindString, &pystate->findMap, PY_PARSE_INPUT_USER, pystate->bSP);
819 pystate->iPYInsertPoint = 0;
820 retVal = IRV_DISPLAY_CANDWORDS;
821 } else if (FcitxHotkeyIsHotKey(sym, state, FCITX_ESCAPE)) {
822 return IRV_TO_PROCESS;
823 } else if (pystate->bIsPYAddFreq || pystate->bIsPYDelFreq ||
824 pystate->bIsPYDelUserPhr) {
825 return IRV_DO_NOTHING;
826 }
827 }
828
829 if (!FcitxInputStateGetIsInRemind(input)) {
830 UpdateCodeInputPY(pystate);
831 CalculateCursorPosition(pystate);
832 } else {
833 if (retVal == IRV_TO_PROCESS && iKey < 0) {
834 ResetPYStatus(pystate);
835 FcitxInstanceCleanInputWindow(pystate->owner);
836 FcitxUIUpdateInputWindow(pystate->owner);
837 }
838 }
839
840 return retVal;
841 }
842
843 /*
844 * 本函数根据当前插入点计算光标的实际位置
845 */
CalculateCursorPosition(FcitxPinyinState * pystate)846 void CalculateCursorPosition(FcitxPinyinState* pystate)
847 {
848 int i;
849 int iTemp;
850 FcitxInputState* input = FcitxInstanceGetInputState(pystate->owner);
851
852 int iCursorPos = 0;
853 int hzLen = 0;
854
855 for (i = 0; i < pystate->iPYSelected; i++)
856 iCursorPos += strlen(pystate->pySelected[i].strHZ);
857
858 hzLen = iCursorPos;
859
860 if (pystate->iPYInsertPoint > strlen(pystate->strFindString))
861 pystate->iPYInsertPoint = strlen(pystate->strFindString);
862 iTemp = pystate->iPYInsertPoint;
863
864 for (i = 0; i < pystate->findMap.iHZCount; i++) {
865 if (strlen(pystate->findMap.strPYParsed[i]) >= iTemp) {
866 iCursorPos += iTemp;
867 break;
868 }
869 iCursorPos += strlen(pystate->findMap.strPYParsed[i]);
870
871 iCursorPos++;
872 iTemp -= strlen(pystate->findMap.strPYParsed[i]);
873 }
874 FcitxInputStateSetCursorPos(input, iCursorPos);
875
876 if (pystate->pyconfig.bFixCursorAtHead)
877 FcitxInputStateSetClientCursorPos(input, 0);
878 else
879 FcitxInputStateSetClientCursorPos(input, hzLen);
880 }
881
882 /*
883 * 由于拼音的编辑功能修改了strFindString,必须保证FcitxInputStateGetRawInputBuffer(input)与用户的输入一致
884 */
UpdateCodeInputPY(FcitxPinyinState * pystate)885 void UpdateCodeInputPY(FcitxPinyinState* pystate)
886 {
887 int i;
888 FcitxInputState* input = FcitxInstanceGetInputState(pystate->owner);
889 char* strCodeInput = FcitxInputStateGetRawInputBuffer(input);
890
891 strCodeInput[0] = '\0';
892 for (i = 0; i < pystate->iPYSelected; i++)
893 strcat(strCodeInput, pystate->pySelected[i].strPY);
894 strcat(strCodeInput, pystate->strFindString);
895 FcitxInputStateSetRawInputBufferSize(input, strlen(strCodeInput));
896 }
897
UpdateFindString(FcitxPinyinState * pystate,int val)898 void UpdateFindString(FcitxPinyinState* pystate, int val)
899 {
900 int i;
901
902 pystate->strFindString[0] = '\0';
903 for (i = 0; i < pystate->findMap.iHZCount; i++) {
904 if (i >= MAX_WORDS_USER_INPUT - val)
905 break;
906 strcat(pystate->strFindString, pystate->findMap.strPYParsed[i]);
907 }
908 if (pystate->iPYInsertPoint > strlen(pystate->strFindString))
909 pystate->iPYInsertPoint = strlen(pystate->strFindString);
910 }
911
PYGetCandWords(void * arg)912 INPUT_RETURN_VALUE PYGetCandWords(void* arg)
913 {
914 int iVal;
915 FcitxPinyinState *pystate = (FcitxPinyinState*) arg;
916 FcitxInputState *input = FcitxInstanceGetInputState(pystate->owner);
917 FcitxGlobalConfig* config = FcitxInstanceGetGlobalConfig(pystate->owner);
918 FcitxMessages* msgPreedit = FcitxInputStateGetPreedit(input);
919 FcitxMessages* msgClientPreedit = FcitxInputStateGetClientPreedit(input);
920 FcitxCandidateWordList* candList = FcitxInputStateGetCandidateList(input);
921
922 FcitxCandidateWordSetPageSize(candList, config->iMaxCandWord);
923 FcitxCandidateWordSetChoose(candList, DIGIT_STR_CHOOSE);
924
925 /* update preedit string */
926 int i;
927 FcitxMessagesSetMessageCount(msgPreedit, 0);
928 FcitxMessagesSetMessageCount(msgClientPreedit, 0);
929 if (pystate->iPYSelected) {
930 FcitxMessagesAddMessageStringsAtLast(msgPreedit, MSG_OTHER, "");
931 FcitxMessagesAddMessageStringsAtLast(msgClientPreedit, MSG_OTHER, "");
932 for (i = 0; i < pystate->iPYSelected; i++) {
933 FcitxMessagesMessageConcat(msgPreedit, FcitxMessagesGetMessageCount(msgPreedit) - 1, pystate->pySelected[i].strHZ);
934 FcitxMessagesMessageConcat(msgClientPreedit, FcitxMessagesGetMessageCount(msgClientPreedit) - 1, pystate->pySelected[i].strHZ);
935 }
936 }
937
938 for (i = 0; i < pystate->findMap.iHZCount; i++) {
939 FcitxMessagesAddMessageStringsAtLast(msgPreedit, MSG_CODE,
940 pystate->findMap.strPYParsed[i]);
941 if (i < pystate->findMap.iHZCount - 1)
942 FcitxMessagesMessageConcat(msgPreedit, FcitxMessagesGetMessageCount(msgPreedit) - 1, " ");
943 }
944
945 if (pystate->findMap.iMode == PARSE_ERROR) {
946 for (i = 0; i < pystate->findMap.iHZCount; i++) {
947 FcitxMessagesAddMessageStringsAtLast(
948 msgClientPreedit, MSG_CODE, pystate->findMap.strPYParsed[i]);
949 }
950 char* errorAuto = FcitxUIMessagesToCString(msgClientPreedit);
951 FcitxInstanceCleanInputWindowDown(pystate->owner);
952
953 FcitxCandidateWord candWord;
954 candWord.owner = pystate;
955 candWord.callback = PYGetCandWord;
956 candWord.priv = NULL;
957 candWord.strWord = strdup(errorAuto);
958 candWord.strExtra = NULL;
959 candWord.wordType = MSG_OTHER;
960 FcitxCandidateWordAppend(candList, &candWord);
961 return IRV_DISPLAY_CANDWORDS;
962 }
963
964 if (FcitxInputStateGetIsInRemind(input))
965 return PYGetRemindCandWords(pystate);
966
967 //判断是不是要输入常用字或符号
968 PyFreq* pCurFreq = pystate->pyFreq->next;
969 for (iVal = 0; iVal < pystate->iPYFreqCount; iVal++) {
970 if (!strcmp(pystate->strFindString, pCurFreq->strPY))
971 break;
972 pCurFreq = pCurFreq->next;
973 }
974
975 if (pystate->pyconfig.bPYCreateAuto)
976 PYCreateAuto(pystate);
977
978 if (pystate->strPYAuto[0]) {
979 FcitxCandidateWord candWord;
980 PYCandWord* pycandword = fcitx_utils_new(PYCandWord);
981 pycandword->iWhich = PY_CAND_AUTO;
982 candWord.owner = pystate;
983 candWord.callback = PYGetCandWord;
984 candWord.priv = pycandword;
985 candWord.strWord = strdup(pystate->strPYAuto);
986 candWord.strExtra = NULL;
987 candWord.wordType = MSG_OTHER;
988 FcitxCandidateWordAppend(candList, &candWord);
989 }
990
991 PYGetPhraseCandWords(pystate);
992 if (pCurFreq)
993 PYGetFreqCandWords(pystate, pCurFreq);
994 PYGetBaseCandWords(pystate, pCurFreq);
995
996 if (FcitxCandidateWordPageCount(candList) != 0) {
997 FcitxCandidateWord *candWord = FcitxCandidateWordGetCurrentWindow(candList);
998 FcitxMessagesAddMessageStringsAtLast(msgClientPreedit, MSG_INPUT,
999 candWord->strWord);
1000 }
1001
1002 return IRV_DISPLAY_CANDWORDS;
1003 }
1004
1005 /*
1006 * 根据用户的录入自动生成一个汉字组合
1007 * 此处采用的策略是按照使用频率最高的字/词
1008 */
PYCreateAuto(FcitxPinyinState * pystate)1009 void PYCreateAuto(FcitxPinyinState* pystate)
1010 {
1011 PYCandIndex candPos;
1012 int val;
1013 int iMatchedLength;
1014 char str[3];
1015 PyPhrase *phrase;
1016 PyPhrase *phraseSelected = NULL;
1017 PyBase *baseSelected = NULL;
1018 PYFA *pPYFA = NULL;
1019 char strMap[MAX_WORDS_USER_INPUT * 2 + 1];
1020 int iCount;
1021 PYFA* PYFAList = pystate->PYFAList;
1022 FcitxPinyinConfig* pyconfig = &pystate->pyconfig;
1023
1024 pystate->strPYAuto[0] = '\0';
1025 pystate->strPYAutoMap[0] = '\0';
1026 str[2] = '\0';
1027
1028 if (pystate->findMap.iHZCount == 1)
1029 return;
1030
1031 while (fcitx_utf8_strlen(pystate->strPYAuto) < pystate->findMap.iHZCount) {
1032 phraseSelected = NULL;
1033 baseSelected = NULL;
1034
1035 iCount = fcitx_utf8_strlen(pystate->strPYAuto);
1036 str[0] = pystate->findMap.strMap[iCount][0];
1037 str[1] = pystate->findMap.strMap[iCount][1];
1038
1039 strMap[0] = '\0';
1040
1041 for (val = iCount + 1; val < pystate->findMap.iHZCount; val++)
1042 strcat(strMap, pystate->findMap.strMap[val]);
1043
1044 candPos.iPYFA = 0;
1045 candPos.iBase = 0;
1046 candPos.iPhrase = 0;
1047 if ((pystate->findMap.iHZCount - iCount) > 1) {
1048 for (candPos.iPYFA = 0; candPos.iPYFA < pystate->iPYFACount; candPos.iPYFA++) {
1049 if (!Cmp2Map(pyconfig, PYFAList[candPos.iPYFA].strMap, str, pystate->bSP)) {
1050 for (candPos.iBase = 0; candPos.iBase < PYFAList[candPos.iPYFA].iBase; candPos.iBase++) {
1051 phrase = USER_PHRASE_NEXT(PYFAList[candPos.iPYFA].pyBase[candPos.iBase].userPhrase);
1052 for (candPos.iPhrase = 0;
1053 candPos.iPhrase < PYFAList[candPos.iPYFA].pyBase[candPos.iBase].iUserPhrase; candPos.iPhrase++) {
1054 val = CmpMap(pyconfig, phrase->strMap, strMap, &iMatchedLength, pystate->bSP);
1055 if (!val && iMatchedLength == (pystate->findMap.iHZCount - 1) * 2)
1056 return;
1057 if (!val || (val && (strlen(phrase->strMap) == iMatchedLength))) {
1058 if (!phraseSelected) {
1059 baseSelected = &(PYFAList[candPos.iPYFA].pyBase[candPos.iBase]);
1060 pPYFA = &PYFAList[candPos.iPYFA];
1061 phraseSelected = phrase;
1062 } else if (strlen(phrase->strMap) <= (pystate->findMap.iHZCount - 1) * 2) {
1063 if (strlen(phrase->strMap) == strlen(phraseSelected->strMap)) {
1064 //先看词频,如果词频一样,再最近优先
1065 if ((phrase->iHit > phraseSelected->iHit)
1066 || ((phrase->iHit == phraseSelected->iHit)
1067 && (phrase->iIndex > phraseSelected->iIndex))) {
1068 baseSelected = &(PYFAList[candPos.iPYFA].pyBase[candPos.iBase]);
1069 pPYFA = &PYFAList[candPos.iPYFA];
1070 phraseSelected = phrase;
1071 }
1072 } else if (strlen(phrase->strMap) > strlen(phraseSelected->strMap)) {
1073 baseSelected = &(PYFAList[candPos.iPYFA].pyBase[candPos.iBase]);
1074 pPYFA = &PYFAList[candPos.iPYFA];
1075 phraseSelected = phrase;
1076 }
1077 }
1078 }
1079 phrase = USER_PHRASE_NEXT(phrase);
1080 }
1081 }
1082 }
1083 }
1084
1085 for (candPos.iPYFA = 0; candPos.iPYFA < pystate->iPYFACount; candPos.iPYFA++) {
1086 if (!Cmp2Map(pyconfig, PYFAList[candPos.iPYFA].strMap, str, pystate->bSP)) {
1087 for (candPos.iBase = 0; candPos.iBase < PYFAList[candPos.iPYFA].iBase; candPos.iBase++) {
1088 for (candPos.iPhrase = 0;
1089 candPos.iPhrase < PYFAList[candPos.iPYFA].pyBase[candPos.iBase].iPhrase; candPos.iPhrase++) {
1090 val =
1091 CmpMap(pyconfig, PYFAList[candPos.iPYFA].pyBase[candPos.iBase].phrase[candPos.iPhrase].strMap,
1092 strMap, &iMatchedLength, pystate->bSP);
1093 if (!val && iMatchedLength == (pystate->findMap.iHZCount - 1) * 2)
1094 return;
1095 if (!val || (val && (strlen(PYFAList[candPos.iPYFA].pyBase[candPos.iBase].phrase[candPos.iPhrase].strMap)
1096 == iMatchedLength))) {
1097 if (!phraseSelected) {
1098 baseSelected = &(PYFAList[candPos.iPYFA].pyBase[candPos.iBase]);
1099 pPYFA = &PYFAList[candPos.iPYFA];
1100 phraseSelected = &(PYFAList[candPos.iPYFA].pyBase[candPos.iBase].phrase[candPos.iPhrase]);
1101 } else if (strlen(PYFAList[candPos.iPYFA].pyBase[candPos.iBase].phrase[candPos.iPhrase].strMap)
1102 <= (pystate->findMap.iHZCount - 1) * 2) {
1103 if (strlen(PYFAList[candPos.iPYFA].pyBase[candPos.iBase].phrase[candPos.iPhrase].strMap)
1104 == strlen(phraseSelected->strMap)) {
1105 //先看词频,如果词频一样,再最近优先
1106 if ((PYFAList[candPos.iPYFA].pyBase[candPos.iBase].phrase[candPos.iPhrase].iHit >
1107 phraseSelected->iHit)
1108 ||
1109 ((PYFAList[candPos.iPYFA].pyBase[candPos.iBase].phrase[candPos.iPhrase].iHit ==
1110 phraseSelected->iHit)
1111 &&
1112 (PYFAList[candPos.iPYFA].pyBase[candPos.iBase].phrase[candPos.iPhrase].iIndex >
1113 phraseSelected->iIndex))) {
1114 baseSelected = &(PYFAList[candPos.iPYFA].pyBase[candPos.iBase]);
1115 pPYFA = &PYFAList[candPos.iPYFA];
1116 phraseSelected = &(PYFAList[candPos.iPYFA].pyBase[candPos.iBase].phrase[candPos.iPhrase]);
1117 }
1118 } else if (strlen(PYFAList[candPos.iPYFA].pyBase[candPos.iBase].phrase[candPos.iPhrase].strMap)
1119 > strlen(phraseSelected->strMap)) {
1120 baseSelected = &(PYFAList[candPos.iPYFA].pyBase[candPos.iBase]);
1121 pPYFA = &PYFAList[candPos.iPYFA];
1122 phraseSelected = &(PYFAList[candPos.iPYFA].pyBase[candPos.iBase].phrase[candPos.iPhrase]);
1123 }
1124 }
1125 }
1126 }
1127 }
1128 }
1129 }
1130 if (baseSelected) {
1131 strcat(pystate->strPYAuto, baseSelected->strHZ);
1132 strcat(pystate->strPYAutoMap, pPYFA->strMap);
1133 strcat(pystate->strPYAuto, phraseSelected->strPhrase);
1134 strcat(pystate->strPYAutoMap, phraseSelected->strMap);
1135 }
1136 }
1137
1138 if (!baseSelected) {
1139 val = -1;
1140 baseSelected = NULL;
1141 for (candPos.iPYFA = 0; candPos.iPYFA < pystate->iPYFACount; candPos.iPYFA++) {
1142 if (!Cmp2Map(pyconfig, PYFAList[candPos.iPYFA].strMap, str, pystate->bSP)) {
1143 for (candPos.iBase = 0; candPos.iBase < PYFAList[candPos.iPYFA].iBase; candPos.iBase++) {
1144 if ((int)
1145 (PYFAList[candPos.iPYFA].pyBase[candPos.iBase].iHit) > val) {
1146 val = PYFAList[candPos.iPYFA].pyBase[candPos.iBase].iHit;
1147 baseSelected = &(PYFAList[candPos.iPYFA].pyBase[candPos.iBase]);
1148 pPYFA = &PYFAList[candPos.iPYFA];
1149 }
1150 }
1151 }
1152 }
1153
1154 if (baseSelected) {
1155 strcat(pystate->strPYAuto, baseSelected->strHZ);
1156 strcat(pystate->strPYAutoMap, pPYFA->strMap);
1157 } else { //出错了
1158 pystate->strPYAuto[0] = '\0';
1159 return;
1160 }
1161 }
1162 }
1163 }
1164
PYGetCandWord(void * arg,FcitxCandidateWord * candWord)1165 INPUT_RETURN_VALUE PYGetCandWord(void* arg, FcitxCandidateWord* candWord)
1166 {
1167 FcitxPinyinState *pystate = (FcitxPinyinState*)arg;
1168 FcitxInputState* input = FcitxInstanceGetInputState(pystate->owner);
1169
1170 if (candWord->priv == NULL) {
1171 strcpy(FcitxInputStateGetOutputString(input), candWord->strWord);
1172 return IRV_COMMIT_STRING;
1173 }
1174
1175 char *pBase = NULL, *pPhrase = NULL;
1176 char *pBaseMap = NULL, *pPhraseMap = NULL;
1177 unsigned int *pIndex = NULL;
1178 boolean bAddNewPhrase = true;
1179 int i;
1180 char strHZString[MAX_WORDS_USER_INPUT * UTF8_MAX_LENGTH + 1];
1181 int iLen;
1182 PYFA* PYFAList = pystate->PYFAList;
1183 FcitxInstance* instance = pystate->owner;
1184 PYCandWord* pycandWord = candWord->priv;
1185 FcitxProfile* profile = FcitxInstanceGetProfile(pystate->owner);
1186
1187 switch (pycandWord->iWhich) {
1188 case PY_CAND_AUTO:
1189 pBase = pystate->strPYAuto;
1190 pBaseMap = pystate->strPYAutoMap;
1191 bAddNewPhrase = (pystate->iPYSelected > 0) || pystate->pyconfig.bPYSaveAutoAsPhrase;
1192 break;
1193 case PY_CAND_BASE: //是系统单字
1194 pBase = PYFAList[pycandWord->cand.base.iPYFA].pyBase[pycandWord->cand.base.iBase].strHZ;
1195 pBaseMap = PYFAList[pycandWord->cand.base.iPYFA].strMap;
1196 pIndex = &(PYFAList[pycandWord->cand.base.iPYFA].pyBase[pycandWord->cand.base.iBase].iIndex);
1197 PYFAList[pycandWord->cand.base.iPYFA].pyBase[pycandWord->cand.base.iBase].iHit++;
1198 pystate->iOrderCount++;
1199 break;
1200 case PY_CAND_USERPHRASE: //是用户词组
1201 pystate->iNewPYPhraseCount++; // fall through
1202 case PY_CAND_SYSPHRASE: //是系统词组
1203 pBase = PYFAList[pycandWord->cand.phrase.iPYFA].pyBase[pycandWord->cand.phrase.iBase].strHZ;
1204 pBaseMap = PYFAList[pycandWord->cand.phrase.iPYFA].strMap;
1205 pPhrase = pycandWord->cand.phrase.phrase->strPhrase;
1206 pPhraseMap = pycandWord->cand.phrase.phrase->strMap;
1207 pIndex = &(pycandWord->cand.phrase.phrase->iIndex);
1208 pycandWord->cand.phrase.phrase->iHit++;
1209 pystate->iOrderCount++;
1210 break;
1211 case PY_CAND_FREQ: //是常用字
1212 pBase = pycandWord->cand.freq.hz->strHZ;
1213 pBaseMap = PYFAList[pycandWord->cand.freq.hz->iPYFA].strMap;
1214 pycandWord->cand.freq.hz->iHit++;
1215 pIndex = &(pycandWord->cand.freq.hz->iIndex);
1216 pystate->iNewFreqCount++;
1217 break;
1218 case PY_CAND_REMIND: {
1219 strcpy(pystate->strPYRemindSource, pycandWord->cand.remind.phrase->strPhrase + pycandWord->cand.remind.iLength);
1220 strcpy(pystate->strPYRemindMap, pycandWord->cand.remind.phrase->strMap + pycandWord->cand.remind.iLength);
1221 pBase = pystate->strPYRemindSource;
1222 strcpy(FcitxInputStateGetOutputString(input), pBase);
1223 FcitxCandidateWordReset(FcitxInputStateGetCandidateList(input));
1224 INPUT_RETURN_VALUE retVal = PYGetRemindCandWords(pystate);
1225 if (retVal == IRV_DISPLAY_CANDWORDS)
1226 return IRV_COMMIT_STRING_REMIND;
1227 else
1228 return IRV_COMMIT_STRING;
1229 }
1230 }
1231
1232 if (pIndex && (*pIndex != pystate->iCounter))
1233 *pIndex = ++pystate->iCounter;
1234 if (pystate->iOrderCount >= AUTOSAVE_ORDER_COUNT) {
1235 SavePYIndex(pystate);
1236 }
1237 if (pystate->iNewFreqCount >= AUTOSAVE_FREQ_COUNT) {
1238 SavePYFreq(pystate);
1239 }
1240
1241 strcpy(strHZString, pBase);
1242 if (pPhrase)
1243 strcat(strHZString, pPhrase);
1244 iLen = fcitx_utf8_strlen(strHZString);
1245 if (iLen == pystate->findMap.iHZCount) {
1246 pystate->strPYAuto[0] = '\0';
1247 for (iLen = 0; iLen < pystate->iPYSelected; iLen++)
1248 strcat(pystate->strPYAuto, pystate->pySelected[iLen].strHZ);
1249 strcat(pystate->strPYAuto, strHZString);
1250 ParsePY(&pystate->pyconfig, FcitxInputStateGetRawInputBuffer(input), &pystate->findMap, PY_PARSE_INPUT_USER, pystate->bSP);
1251 strHZString[0] = '\0';
1252 for (i = 0; i < pystate->iPYSelected; i++)
1253 strcat(strHZString, pystate->pySelected[i].strMap);
1254 if (pBaseMap)
1255 strcat(strHZString, pBaseMap);
1256 if (pPhraseMap)
1257 strcat(strHZString, pPhraseMap);
1258 if (bAddNewPhrase && (fcitx_utf8_strlen(pystate->strPYAuto) <= (MAX_PY_PHRASE_LENGTH)))
1259 PYAddUserPhrase(pystate, pystate->strPYAuto, strHZString, false);
1260 FcitxInstanceCleanInputWindow(instance);
1261 strcpy(FcitxInputStateGetOutputString(input), pystate->strPYAuto);
1262 if (profile->bUseRemind) {
1263 FcitxInputStateGetRawInputBuffer(input)[0] = '\0';
1264 FcitxInputStateSetRawInputBufferSize(input, 0);
1265 strcpy(pystate->strPYRemindSource, pystate->strPYAuto);
1266 strcpy(pystate->strPYRemindMap, strHZString);
1267 INPUT_RETURN_VALUE retVal = PYGetRemindCandWords(pystate);
1268
1269 if (retVal != IRV_TO_PROCESS) {
1270 pystate->iPYInsertPoint = 0;
1271 pystate->strFindString[0] = '\0';
1272
1273 return IRV_COMMIT_STRING_REMIND;
1274 }
1275 }
1276
1277 return IRV_COMMIT_STRING;
1278 }
1279 //此时进入自造词状态
1280 pystate->pySelected[pystate->iPYSelected].strPY[0] = '\0';
1281 pystate->pySelected[pystate->iPYSelected].strMap[0] = '\0';
1282 for (i = 0; i < iLen; i++)
1283 strcat(pystate->pySelected[pystate->iPYSelected].strPY, pystate->findMap.strPYParsed[i]);
1284 if (pBaseMap)
1285 strcat(pystate->pySelected[pystate->iPYSelected].strMap, pBaseMap);
1286 if (pPhraseMap)
1287 strcat(pystate->pySelected[pystate->iPYSelected].strMap, pPhraseMap);
1288 strcpy(pystate->pySelected[pystate->iPYSelected].strHZ, strHZString);
1289 pystate->iPYSelected++;
1290 pystate->strFindString[0] = '\0';
1291 for (; i < pystate->findMap.iHZCount; i++)
1292 strcat(pystate->strFindString, pystate->findMap.strPYParsed[i]);
1293 DoPYInput(pystate, 0, 0);
1294 pystate->iPYInsertPoint = strlen(pystate->strFindString);
1295
1296 CalculateCursorPosition(pystate);
1297 return IRV_DISPLAY_CANDWORDS;
1298 }
1299
PYGetPhraseCandWords(FcitxPinyinState * pystate)1300 void PYGetPhraseCandWords(FcitxPinyinState* pystate)
1301 {
1302 PYCandIndex candPos;
1303 char str[3];
1304 int val, iMatchedLength;
1305 char strMap[MAX_WORDS_USER_INPUT * 2 + 1];
1306 PyPhrase *phrase;
1307 PYFA* PYFAList = pystate->PYFAList;
1308 FcitxPinyinConfig* pyconfig = &pystate->pyconfig;
1309 FcitxInputState* input = FcitxInstanceGetInputState(pystate->owner);
1310
1311 if (pystate->findMap.iHZCount == 1)
1312 return;
1313
1314 UT_array candtemp;
1315 utarray_init(&candtemp, fcitx_ptr_icd);
1316
1317 str[0] = pystate->findMap.strMap[0][0];
1318 str[1] = pystate->findMap.strMap[0][1];
1319 str[2] = '\0';
1320 strMap[0] = '\0';
1321 for (val = 1; val < pystate->findMap.iHZCount; val++)
1322 strcat(strMap, pystate->findMap.strMap[val]);
1323 for (candPos.iPYFA = 0; candPos.iPYFA < pystate->iPYFACount; candPos.iPYFA++) {
1324 if (!Cmp2Map(pyconfig, PYFAList[candPos.iPYFA].strMap, str, pystate->bSP)) {
1325 for (candPos.iBase = 0; candPos.iBase < PYFAList[candPos.iPYFA].iBase; candPos.iBase++) {
1326 phrase = USER_PHRASE_NEXT(PYFAList[candPos.iPYFA].pyBase[candPos.iBase].userPhrase);
1327 for (candPos.iPhrase = 0;
1328 candPos.iPhrase < PYFAList[candPos.iPYFA].pyBase[candPos.iBase].iUserPhrase; candPos.iPhrase++) {
1329 val = CmpMap(pyconfig, phrase->strMap, strMap, &iMatchedLength, pystate->bSP);
1330 if (!val || (val && (strlen(phrase->strMap) == iMatchedLength))) {
1331 PYCandWord *pycandWord = fcitx_utils_new(PYCandWord);
1332 PYAddPhraseCandWord(pystate, candPos, phrase, false, pycandWord);
1333 utarray_push_back(&candtemp, &pycandWord);
1334 }
1335
1336 phrase = USER_PHRASE_NEXT(phrase);
1337 }
1338 }
1339 }
1340 }
1341
1342 for (candPos.iPYFA = 0; candPos.iPYFA < pystate->iPYFACount; candPos.iPYFA++) {
1343 if (!Cmp2Map(pyconfig, PYFAList[candPos.iPYFA].strMap, str, pystate->bSP)) {
1344 for (candPos.iBase = 0; candPos.iBase < PYFAList[candPos.iPYFA].iBase; candPos.iBase++) {
1345 for (candPos.iPhrase = 0; candPos.iPhrase < PYFAList[candPos.iPYFA].pyBase[candPos.iBase].iPhrase; candPos.iPhrase++) {
1346 val = CmpMap(
1347 pyconfig,
1348 PYFAList[candPos.iPYFA].pyBase[candPos.iBase].phrase[candPos.iPhrase].strMap,
1349 strMap,
1350 &iMatchedLength,
1351 pystate->bSP);
1352 if (!val ||
1353 (val && (strlen(PYFAList[candPos.iPYFA].pyBase[candPos.iBase].phrase[candPos.iPhrase].strMap) == iMatchedLength))) {
1354 PYCandWord* pycandWord = fcitx_utils_new(PYCandWord);
1355 PYAddPhraseCandWord(pystate, candPos, &(PYFAList[candPos.iPYFA].pyBase[candPos.iBase].phrase[candPos.iPhrase]), true, pycandWord);
1356 utarray_push_back(&candtemp, &pycandWord);
1357 }
1358 }
1359 }
1360 }
1361 }
1362
1363 PYCandWordSortContext context;
1364 context.order = pystate->pyconfig.phraseOrder;
1365 context.type = PY_CAND_SYSPHRASE;
1366 context.pystate = pystate;
1367 if (context.order != AD_NO)
1368 utarray_msort_r(&candtemp, PYCandWordCmp, &context);
1369
1370 PYCandWord** pcand = NULL;
1371 for (pcand = (PYCandWord**) utarray_front(&candtemp);
1372 pcand != NULL;
1373 pcand = (PYCandWord**) utarray_next(&candtemp, pcand)) {
1374 FcitxCandidateWord candWord;
1375 candWord.callback = PYGetCandWord;
1376 candWord.owner = pystate;
1377 candWord.priv = *pcand;
1378 candWord.strExtra = NULL;
1379 candWord.strWord = NULL;
1380 if ((*pcand)->iWhich == PY_CAND_USERPHRASE)
1381 candWord.wordType = MSG_USERPHR;
1382 else
1383 candWord.wordType = MSG_OTHER;
1384 const char* pBase = PYFAList[(*pcand)->cand.phrase.iPYFA].pyBase[(*pcand)->cand.phrase.iBase].strHZ;
1385 const char* pPhrase = (*pcand)->cand.phrase.phrase->strPhrase;
1386 fcitx_utils_alloc_cat_str(candWord.strWord, pBase, pPhrase);
1387 FcitxCandidateWordAppend(FcitxInputStateGetCandidateList(input),
1388 &candWord);
1389 }
1390
1391 utarray_done(&candtemp);
1392 }
1393
1394 /*
1395 * 将一个词加入到候选列表的合适位置中
1396 * b = true 表示是系统词组,false表示是用户词组
1397 */
PYAddPhraseCandWord(FcitxPinyinState * pystate,PYCandIndex pos,PyPhrase * phrase,boolean b,PYCandWord * pycandword)1398 boolean PYAddPhraseCandWord(FcitxPinyinState* pystate, PYCandIndex pos, PyPhrase * phrase, boolean b, PYCandWord* pycandword)
1399 {
1400 PYFA* PYFAList = pystate->PYFAList;
1401 char str[MAX_WORDS_USER_INPUT * UTF8_MAX_LENGTH + 1];
1402
1403 strcpy(str, PYFAList[pos.iPYFA].pyBase[pos.iBase].strHZ);
1404 strcat(str, phrase->strPhrase);
1405 if (pystate->strPYAuto[0]) {
1406 if (strcmp(pystate->strPYAuto, str) == 0) {
1407 return false;
1408 }
1409 }
1410
1411 pycandword->iWhich = (b) ? PY_CAND_SYSPHRASE : PY_CAND_USERPHRASE;
1412 pycandword->cand.phrase.phrase = phrase;
1413 pycandword->cand.phrase.iPYFA = pos.iPYFA;
1414 pycandword->cand.phrase.iBase = pos.iBase;
1415 return true;
1416 }
1417
1418 //*****************************************************
1419
PYGetBaseCandWords(FcitxPinyinState * pystate,PyFreq * pCurFreq)1420 void PYGetBaseCandWords(FcitxPinyinState* pystate, PyFreq* pCurFreq)
1421 {
1422 PYCandIndex candPos = {
1423 0, 0, 0
1424 };
1425 char str[3];
1426 PYFA* PYFAList = pystate->PYFAList;
1427 FcitxPinyinConfig* pyconfig = &pystate->pyconfig;
1428 FcitxInputState* input = FcitxInstanceGetInputState(pystate->owner);
1429 UT_array candtemp;
1430 utarray_init(&candtemp, fcitx_ptr_icd);
1431
1432 str[0] = pystate->findMap.strMap[0][0];
1433 str[1] = pystate->findMap.strMap[0][1];
1434 str[2] = '\0';
1435 for (candPos.iPYFA = 0; candPos.iPYFA < pystate->iPYFACount; candPos.iPYFA++) {
1436 if (!Cmp2Map(pyconfig, PYFAList[candPos.iPYFA].strMap, str, pystate->bSP)) {
1437 for (candPos.iBase = 0; candPos.iBase < PYFAList[candPos.iPYFA].iBase; candPos.iBase++) {
1438 if (!PYIsInFreq(pCurFreq, PYFAList[candPos.iPYFA].pyBase[candPos.iBase].strHZ)) {
1439 PYCandWord *pycandWord = fcitx_utils_new(PYCandWord);
1440 PYAddBaseCandWord(candPos, pycandWord);
1441 utarray_push_back(&candtemp, &pycandWord);
1442 }
1443 }
1444 }
1445 }
1446
1447 PYCandWordSortContext context;
1448 context.order = pystate->pyconfig.baseOrder;
1449 context.type = PY_CAND_BASE;
1450 context.pystate = pystate;
1451 if (context.order != AD_NO)
1452 utarray_msort_r(&candtemp, PYCandWordCmp, &context);
1453
1454 PYCandWord** pcand = NULL;
1455 for (pcand = (PYCandWord**) utarray_front(&candtemp);
1456 pcand != NULL;
1457 pcand = (PYCandWord**) utarray_next(&candtemp, pcand)) {
1458 FcitxCandidateWord candWord;
1459 candWord.callback = PYGetCandWord;
1460 candWord.owner = pystate;
1461 candWord.priv = *pcand;
1462 candWord.strExtra = NULL;
1463 candWord.strWord = strdup(PYFAList[(*pcand)->cand.base.iPYFA].pyBase[(*pcand)->cand.base.iBase].strHZ);
1464 candWord.wordType = MSG_OTHER;
1465
1466 FcitxCandidateWordAppend(FcitxInputStateGetCandidateList(input), &candWord);
1467 }
1468
1469 utarray_done(&candtemp);
1470 }
1471
1472 /*
1473 * 将一个字加入到候选列表的合适位置中
1474 */
PYAddBaseCandWord(PYCandIndex pos,PYCandWord * pycandWord)1475 void PYAddBaseCandWord(PYCandIndex pos, PYCandWord* pycandWord)
1476 {
1477 pycandWord->iWhich = PY_CAND_BASE;
1478 pycandWord->cand.base.iPYFA = pos.iPYFA;
1479 pycandWord->cand.base.iBase = pos.iBase;
1480 }
1481
PYGetFreqCandWords(FcitxPinyinState * pystate,PyFreq * pCurFreq)1482 void PYGetFreqCandWords(FcitxPinyinState* pystate, PyFreq* pCurFreq)
1483 {
1484 int i;
1485 HZ *hz;
1486 UT_array candtemp;
1487 FcitxInputState* input = FcitxInstanceGetInputState(pystate->owner);
1488 utarray_init(&candtemp, fcitx_ptr_icd);
1489
1490 if (pCurFreq) {
1491 hz = pCurFreq->HZList->next;
1492 for (i = 0; i < pCurFreq->iCount; i++) {
1493 PYCandWord *pycandWord = fcitx_utils_new(PYCandWord);
1494 PYAddFreqCandWord(pCurFreq, hz, pCurFreq->strPY, pycandWord);
1495 utarray_push_back(&candtemp, &pycandWord);
1496 hz = hz->next;
1497 }
1498 }
1499
1500 PYCandWordSortContext context;
1501 context.order = pystate->pyconfig.freqOrder;
1502 context.type = PY_CAND_FREQ;
1503 context.pystate = pystate;
1504 if (context.order != AD_NO)
1505 utarray_msort_r(&candtemp, PYCandWordCmp, &context);
1506
1507 PYCandWord** pcand = NULL;
1508 for (pcand = (PYCandWord**) utarray_front(&candtemp);
1509 pcand != NULL;
1510 pcand = (PYCandWord**) utarray_next(&candtemp, pcand)) {
1511 FcitxCandidateWord candWord;
1512 candWord.callback = PYGetCandWord;
1513 candWord.owner = pystate;
1514 candWord.priv = *pcand;
1515 candWord.strExtra = NULL;
1516 candWord.strWord = strdup((*pcand)->cand.freq.hz->strHZ);
1517 candWord.wordType = MSG_USERPHR;
1518
1519 FcitxCandidateWordAppend(FcitxInputStateGetCandidateList(input), &candWord);
1520 }
1521
1522 utarray_done(&candtemp);
1523 }
1524
1525 /*
1526 * 将一个常用字加入到候选列表的合适位置中
1527 */
PYAddFreqCandWord(PyFreq * pyFreq,HZ * hz,char * strPY,PYCandWord * pycandWord)1528 void PYAddFreqCandWord(PyFreq* pyFreq, HZ * hz, char *strPY, PYCandWord* pycandWord)
1529 {
1530 pycandWord->iWhich = PY_CAND_FREQ;
1531 pycandWord->cand.freq.hz = hz;
1532 pycandWord->cand.freq.strPY = strPY;
1533 pycandWord->cand.freq.pyFreq = pyFreq;
1534 }
1535
1536 /*
1537 * 将一个词组保存到用户词组库中
1538 * 返回true表示是新词组
1539 */
PYAddUserPhrase(FcitxPinyinState * pystate,const char * phrase,const char * map,boolean incHit)1540 boolean PYAddUserPhrase(FcitxPinyinState* pystate, const char *phrase, const char *map, boolean incHit)
1541 {
1542 PyUsrPhrase *userPhrase, *newPhrase, *temp;
1543 char str[UTF8_MAX_LENGTH + 1];
1544 int i, j, k, iTemp;
1545 int clen;
1546 PYFA* PYFAList = pystate->PYFAList;
1547 FcitxPinyinConfig* pyconfig = &pystate->pyconfig;
1548
1549 //如果短于两个汉字,则不能组成词组
1550 if (fcitx_utf8_strlen(phrase) < 2)
1551 return false;
1552 str[0] = map[0];
1553 str[1] = map[1];
1554 str[2] = '\0';
1555 i = GetBaseMapIndex(pystate, str);
1556
1557 clen = fcitx_utf8_char_len(phrase);
1558 strncpy(str, phrase, clen);
1559 str[clen] = '\0';
1560 j = GetBaseIndex(pystate, i, str);;
1561 //判断该词组是否已经在库中
1562 //首先,看它是不是在用户词组库中
1563 userPhrase = PYFAList[i].pyBase[j].userPhrase->next;
1564 for (k = 0; k < PYFAList[i].pyBase[j].iUserPhrase; k++) {
1565 if (!strcmp(map + 2, userPhrase->phrase.strMap)
1566 && !strcmp(phrase + clen, userPhrase->phrase.strPhrase)) {
1567 if (incHit) {
1568 userPhrase->phrase.iHit ++;
1569 userPhrase->phrase.iIndex = ++pystate->iCounter;
1570 }
1571 return false;
1572 }
1573 userPhrase = userPhrase->next;
1574 }
1575
1576 //然后,看它是不是在系统词组库中
1577 for (k = 0; k < PYFAList[i].pyBase[j].iPhrase; k++)
1578 if (!strcmp(map + 2, PYFAList[i].pyBase[j].phrase[k].strMap)
1579 && !strcmp(phrase + clen, PYFAList[i].pyBase[j].phrase[k].strPhrase)) {
1580 if (incHit) {
1581 PYFAList[i].pyBase[j].phrase[k].iHit ++;
1582 PYFAList[i].pyBase[j].phrase[k].iIndex = ++pystate->iCounter;
1583 }
1584 return false;
1585 }
1586 //下面将词组添加到列表中
1587 newPhrase = fcitx_utils_new(PyUsrPhrase);
1588 newPhrase->phrase.strMap = (char*)fcitx_utils_malloc0(sizeof(char) * strlen(map + 2) + 1);
1589 newPhrase->phrase.strPhrase = (char*)fcitx_utils_malloc0(sizeof(char) * strlen(phrase + clen) + 1);
1590 strcpy(newPhrase->phrase.strMap, map + 2);
1591 strcpy(newPhrase->phrase.strPhrase, phrase + clen);
1592 newPhrase->phrase.iIndex = ++pystate->iCounter;
1593 newPhrase->phrase.iHit = 1;
1594 temp = PYFAList[i].pyBase[j].userPhrase;
1595 userPhrase = PYFAList[i].pyBase[j].userPhrase->next;
1596 for (k = 0; k < PYFAList[i].pyBase[j].iUserPhrase; k++) {
1597 if (CmpMap(pyconfig, map + 2, userPhrase->phrase.strMap, &iTemp, pystate->bSP) > 0)
1598 break;
1599 temp = userPhrase;
1600 userPhrase = userPhrase->next;
1601 }
1602
1603 newPhrase->next = temp->next;
1604 temp->next = newPhrase;
1605 PYFAList[i].pyBase[j].iUserPhrase++;
1606 pystate->iNewPYPhraseCount++;
1607 if (pystate->iNewPYPhraseCount >= AUTOSAVE_PHRASE_COUNT) {
1608 SavePYUserPhrase(pystate);
1609 }
1610
1611 return true;
1612 }
1613
PYDelUserPhrase(FcitxPinyinState * pystate,int32_t iPYFA,int iBase,PyUsrPhrase * phrase)1614 void PYDelUserPhrase(FcitxPinyinState* pystate, int32_t iPYFA, int iBase, PyUsrPhrase * phrase)
1615 {
1616 PyUsrPhrase *temp;
1617 PYFA* PYFAList = pystate->PYFAList;
1618
1619 //首先定位该词组
1620 temp = PYFAList[iPYFA].pyBase[iBase].userPhrase;
1621 while (temp) {
1622 if (temp->next == phrase)
1623 break;
1624 temp = temp->next;
1625 }
1626 if (!temp)
1627 return;
1628 temp->next = phrase->next;
1629 free(phrase->phrase.strPhrase);
1630 free(phrase->phrase.strMap);
1631 free(phrase);
1632 PYFAList[iPYFA].pyBase[iBase].iUserPhrase--;
1633 pystate->iNewPYPhraseCount++;
1634 if (pystate->iNewPYPhraseCount >= AUTOSAVE_PHRASE_COUNT) {
1635 SavePYUserPhrase(pystate);
1636 }
1637 }
1638
GetBaseMapIndex(FcitxPinyinState * pystate,char * strMap)1639 int GetBaseMapIndex(FcitxPinyinState* pystate, char *strMap)
1640 {
1641 int i;
1642
1643 for (i = 0; i < pystate->iPYFACount; i++) {
1644 if (!strcmp(strMap, pystate->PYFAList[i].strMap))
1645 return i;
1646 }
1647 return -1;
1648 }
1649
1650 /*
1651 * 保存用户词库
1652 */
SavePYUserPhrase(FcitxPinyinState * pystate)1653 void SavePYUserPhrase(FcitxPinyinState* pystate)
1654 {
1655 int j, k;
1656 int32_t i, iTemp;
1657 char *tempfile, *pstr;
1658 FILE *fp;
1659 PyPhrase *phrase;
1660 PYFA* PYFAList = pystate->PYFAList;
1661 int fd;
1662
1663 FcitxXDGGetFileUserWithPrefix("pinyin", "", "w", NULL);
1664 FcitxXDGGetFileUserWithPrefix("pinyin", PINYIN_TEMP_FILE, NULL, &tempfile);
1665 fd = mkstemp(tempfile);
1666 fp = NULL;
1667
1668 if (fd > 0)
1669 fp = fdopen(fd, "w");
1670
1671 if (!fp) {
1672 FcitxLog(ERROR, _("Cannot Save User Pinyin Database: %s"), tempfile);
1673 free(tempfile);
1674 return;
1675 }
1676
1677 for (i = 0; i < pystate->iPYFACount; i++) {
1678 for (j = 0; j < PYFAList[i].iBase; j++) {
1679 iTemp = PYFAList[i].pyBase[j].iUserPhrase;
1680 if (iTemp) {
1681 char clen;
1682 fcitx_utils_write_int32(fp, i);
1683 clen = strlen(PYFAList[i].pyBase[j].strHZ);
1684 fwrite(&clen, sizeof(char), 1, fp);
1685 fwrite(PYFAList[i].pyBase[j].strHZ, sizeof(char) * clen, 1, fp);
1686 fcitx_utils_write_int32(fp, iTemp);
1687 phrase = USER_PHRASE_NEXT(PYFAList[i].pyBase[j].userPhrase);
1688 for (k = 0; k < PYFAList[i].pyBase[j].iUserPhrase; k++) {
1689 iTemp = strlen(phrase->strMap);
1690 fcitx_utils_write_int32(fp, iTemp);
1691 fwrite(phrase->strMap, sizeof(char) * iTemp, 1, fp);
1692
1693 iTemp = strlen(phrase->strPhrase);
1694 fcitx_utils_write_int32(fp, iTemp);
1695 fwrite(phrase->strPhrase, sizeof(char) * iTemp, 1, fp);
1696
1697 fcitx_utils_write_uint32(fp, phrase->iIndex);
1698 fcitx_utils_write_uint32(fp, phrase->iHit);
1699 phrase = USER_PHRASE_NEXT(phrase);
1700 }
1701 }
1702 }
1703 }
1704
1705 fclose(fp);
1706 FcitxXDGGetFileUserWithPrefix("pinyin", PY_USERPHRASE_FILE, NULL, &pstr);
1707 if (access(pstr, 0))
1708 unlink(pstr);
1709 rename(tempfile, pstr);
1710 free(pstr);
1711 free(tempfile);
1712 pystate->iNewPYPhraseCount = 0;
1713 }
1714
SavePYFreq(FcitxPinyinState * pystate)1715 void SavePYFreq(FcitxPinyinState *pystate)
1716 {
1717 int32_t i;
1718 int k;
1719 char *pstr;
1720 char *tempfile;
1721 FILE *fp;
1722 PyFreq *pPyFreq;
1723 HZ *hz;
1724 int fd;
1725
1726 FcitxXDGGetFileUserWithPrefix("pinyin", "", "w", NULL);
1727 FcitxXDGGetFileUserWithPrefix("pinyin", PINYIN_TEMP_FILE, NULL, &tempfile);
1728 fd = mkstemp(tempfile);
1729 fp = NULL;
1730
1731 if (fd > 0)
1732 fp = fdopen(fd, "w");
1733
1734 if (!fp) {
1735 FcitxLog(ERROR, _("Cannot Save Frequent word: %s"), tempfile);
1736 free(tempfile);
1737 return;
1738 }
1739
1740 i = 0;
1741 pPyFreq = pystate->pyFreq->next;
1742 while (pPyFreq) {
1743 i++;
1744 pPyFreq = pPyFreq->next;
1745 }
1746 fcitx_utils_write_int32(fp, i);
1747 pPyFreq = pystate->pyFreq->next;
1748 while (pPyFreq) {
1749 fwrite(pPyFreq->strPY, sizeof(char) * 11, 1, fp);
1750 fcitx_utils_write_int32(fp, pPyFreq->iCount);
1751 hz = pPyFreq->HZList->next;
1752 for (k = 0; k < pPyFreq->iCount; k++) {
1753 char slen = strlen(hz->strHZ);
1754 fwrite(&slen, sizeof(char), 1, fp);
1755 fwrite(hz->strHZ, sizeof(char) * slen, 1, fp);
1756 fcitx_utils_write_int32(fp, hz->iPYFA);
1757 fcitx_utils_write_uint32(fp, hz->iHit);
1758 fcitx_utils_write_int32(fp, hz->iIndex);
1759
1760 hz = hz->next;
1761 }
1762 pPyFreq = pPyFreq->next;
1763 }
1764
1765 fclose(fp);
1766
1767 FcitxXDGGetFileUserWithPrefix("pinyin", PY_FREQ_FILE, NULL, &pstr);
1768 if (access(pstr, 0))
1769 unlink(pstr);
1770 rename(tempfile, pstr);
1771
1772 free(pstr);
1773 free(tempfile);
1774 pystate->iNewFreqCount = 0;
1775 }
1776
1777 /*
1778 * 保存索引文件
1779 */
SavePYIndex(FcitxPinyinState * pystate)1780 void SavePYIndex(FcitxPinyinState *pystate)
1781 {
1782 int32_t i, j, k;
1783 char *pstr;
1784 char *tempfile;
1785 FILE *fp;
1786 PYFA* PYFAList = pystate->PYFAList;
1787 int fd;
1788
1789 FcitxXDGGetFileUserWithPrefix("pinyin", "", "w", NULL);
1790 FcitxXDGGetFileUserWithPrefix("pinyin", PINYIN_TEMP_FILE, NULL, &tempfile);
1791 fd = mkstemp(tempfile);
1792 fp = NULL;
1793
1794 if (fd > 0)
1795 fp = fdopen(fd, "w");
1796
1797 if (!fp) {
1798 FcitxLog(ERROR, _("Cannot Save Pinyin Index: %s"), tempfile);
1799 free(tempfile);
1800 return;
1801 }
1802
1803 fcitx_utils_write_uint32(fp, PY_INDEX_MAGIC_NUMBER);
1804
1805 //Save Counter
1806 fcitx_utils_write_uint32(fp, pystate->iCounter);
1807 //先保存索引不为0的单字
1808 k = -1;
1809 for (i = 0; i < pystate->iPYFACount; i++) {
1810 for (j = 0; j < PYFAList[i].iBase; j++) {
1811 if (PYFAList[i].pyBase[j].iIndex > pystate->iOrigCounter) {
1812 fcitx_utils_write_int32(fp, i);
1813 fcitx_utils_write_int32(fp, j);
1814 fcitx_utils_write_int32(fp, k);
1815 fcitx_utils_write_uint32(fp, PYFAList[i].pyBase[j].iIndex);
1816 fcitx_utils_write_uint32(fp, PYFAList[i].pyBase[j].iHit);
1817 }
1818 }
1819 }
1820
1821 //再保存索引不为0的系统词组
1822 for (i = 0; i < pystate->iPYFACount; i++) {
1823 for (j = 0; j < PYFAList[i].iBase; j++) {
1824 for (k = 0; k < PYFAList[i].pyBase[j].iPhrase; k++) {
1825 if (PYFAList[i].pyBase[j].phrase[k].iIndex
1826 > pystate->iOrigCounter) {
1827 fcitx_utils_write_int32(fp, i);
1828 fcitx_utils_write_int32(fp, j);
1829 fcitx_utils_write_int32(fp, k);
1830 fcitx_utils_write_uint32(
1831 fp, PYFAList[i].pyBase[j].phrase[k].iIndex);
1832 fcitx_utils_write_uint32(
1833 fp, PYFAList[i].pyBase[j].phrase[k].iHit);
1834 }
1835 }
1836 }
1837 }
1838
1839 fclose(fp);
1840
1841 FcitxXDGGetFileUserWithPrefix("pinyin", PY_INDEX_FILE, NULL, &pstr);
1842 if (access(pstr, 0))
1843 unlink(pstr);
1844 rename(tempfile, pstr);
1845
1846 free(pstr);
1847 free(tempfile);
1848 pystate->iOrderCount = 0;
1849 }
1850
1851 /*
1852 * 设置拼音的常用字表
1853 * 只有以下情形才能设置
1854 * 当用户输入单字时
1855 * 至于常用词的问题暂时不考虑
1856 */
PYAddFreq(FcitxPinyinState * pystate,PYCandWord * pycandWord)1857 void PYAddFreq(FcitxPinyinState* pystate, PYCandWord* pycandWord)
1858 {
1859 int i;
1860 HZ *HZTemp;
1861 PyFreq *freq;
1862 HZ *hz;
1863 PYFA* PYFAList = pystate->PYFAList;
1864 PyFreq* pCurFreq = pystate->pyFreq->next;
1865 for (i = 0; i < pystate->iPYFreqCount; i++) {
1866 if (!strcmp(pystate->strFindString, pCurFreq->strPY))
1867 break;
1868 pCurFreq = pCurFreq->next;
1869 }
1870
1871 //能到这儿来,就说明候选列表中都是单字
1872 //首先,看这个字是不是已经在常用字表中
1873 i = 1;
1874 if (pCurFreq) {
1875 i = -1;
1876 if (pycandWord->iWhich != PY_CAND_FREQ) {
1877 //说明该字是系统单字
1878 HZTemp = pCurFreq->HZList->next;
1879 for (i = 0; i < pCurFreq->iCount; i++) {
1880 if (!strcmp(PYFAList[pycandWord->cand.base.iPYFA].pyBase[pycandWord->cand.base.iBase].strHZ, HZTemp->strHZ)) {
1881 i = -1;
1882 break;
1883 }
1884 HZTemp = HZTemp->next;
1885 }
1886 }
1887 }
1888 //借用i来指示是否需要添加新的常用字
1889 if (i < 0)
1890 return;
1891 //需要添加该字,此时该字必然是系统单字
1892 if (!pCurFreq) {
1893 freq = fcitx_utils_new(PyFreq);
1894 freq->HZList = fcitx_utils_new(HZ);
1895 freq->HZList->next = NULL;
1896 strcpy(freq->strPY, pystate->strFindString);
1897 freq->next = NULL;
1898 freq->iCount = 0;
1899 pCurFreq = pystate->pyFreq;
1900 for (i = 0; i < pystate->iPYFreqCount; i++)
1901 pCurFreq = pCurFreq->next;
1902 pCurFreq->next = freq;
1903 pystate->iPYFreqCount++;
1904 pCurFreq = freq;
1905 }
1906
1907 HZTemp = fcitx_utils_new(HZ);
1908 strcpy(HZTemp->strHZ, PYFAList[pycandWord->cand.base.iPYFA].pyBase[pycandWord->cand.base.iBase].strHZ);
1909 HZTemp->iPYFA = pycandWord->cand.base.iPYFA;
1910 HZTemp->iHit = 0;
1911 HZTemp->iIndex = 0;
1912 HZTemp->next = NULL;
1913 //将HZTemp加到链表尾部
1914 hz = pCurFreq->HZList;
1915 for (i = 0; i < pCurFreq->iCount; i++)
1916 hz = hz->next;
1917 hz->next = HZTemp;
1918 pCurFreq->iCount++;
1919 pystate->iNewFreqCount++;
1920 if (pystate->iNewFreqCount >= AUTOSAVE_FREQ_COUNT) {
1921 SavePYFreq(pystate);
1922 }
1923 }
1924
1925 /*
1926 * 删除拼音常用字表中的某个字
1927 */
PYDelFreq(FcitxPinyinState * pystate,PYCandWord * pycandWord)1928 void PYDelFreq(FcitxPinyinState *pystate, PYCandWord* pycandWord)
1929 {
1930 HZ *hz;
1931
1932 //能到这儿来,就说明候选列表中都是单字
1933 //首先,看这个字是不是已经在常用字表中
1934 if (pycandWord->iWhich != PY_CAND_FREQ)
1935 return;
1936 //先找到需要删除单字的位置
1937 hz = pycandWord->cand.freq.pyFreq->HZList;
1938 while (hz->next != pycandWord->cand.freq.hz)
1939 hz = hz->next;
1940 hz->next = pycandWord->cand.freq.hz->next;
1941 free(pycandWord->cand.freq.hz);
1942 pycandWord->cand.freq.pyFreq->iCount--;
1943 pystate->iNewFreqCount++;
1944 if (pystate->iNewFreqCount >= AUTOSAVE_FREQ_COUNT) {
1945 SavePYFreq(pystate);
1946 }
1947 }
1948
1949 /*
1950 * 判断一个字是否已经是常用字
1951 */
PYIsInFreq(PyFreq * pCurFreq,char * strHZ)1952 boolean PYIsInFreq(PyFreq* pCurFreq, char *strHZ)
1953 {
1954 HZ *hz;
1955 int i;
1956
1957 if (!pCurFreq)
1958 return false;
1959 hz = pCurFreq->HZList->next;
1960 for (i = 0; i < pCurFreq->iCount; i++) {
1961 if (!strcmp(strHZ, hz->strHZ))
1962 return true;
1963 hz = hz->next;
1964 }
1965
1966 return false;
1967 }
1968
1969 /*
1970 * 取得拼音的联想字串
1971 * 按照频率来定排列顺序
1972 */
PYGetRemindCandWords(void * arg)1973 INPUT_RETURN_VALUE PYGetRemindCandWords(void *arg)
1974 {
1975 int i, j;
1976 PyPhrase *phrase;
1977 FcitxPinyinState* pystate = (FcitxPinyinState*) arg;
1978 FcitxGlobalConfig* config = FcitxInstanceGetGlobalConfig(pystate->owner);
1979 boolean bDisablePagingInRemind = config->bDisablePagingInRemind;
1980 FcitxInputState *input = FcitxInstanceGetInputState(pystate->owner);
1981 PYFA* PYFAList = pystate->PYFAList;
1982
1983 if (!pystate->strPYRemindSource[0])
1984 return IRV_TO_PROCESS;
1985
1986 PyBase* pyBaseForRemind = NULL;
1987 for (i = 0; i < pystate->iPYFACount; i++) {
1988 if (!strncmp(pystate->strPYRemindMap, PYFAList[i].strMap, 2)) {
1989 for (j = 0; j < PYFAList[i].iBase; j++) {
1990 if (!fcitx_utf8_strncmp(pystate->strPYRemindSource, PYFAList[i].pyBase[j].strHZ, 1)) {
1991 pyBaseForRemind = &(PYFAList[i].pyBase[j]);
1992 goto _HIT;
1993 }
1994 }
1995 }
1996 }
1997
1998 _HIT:
1999 if (!pyBaseForRemind)
2000 return IRV_TO_PROCESS;
2001
2002 UT_array candtemp;
2003 utarray_init(&candtemp, fcitx_ptr_icd);
2004
2005 for (i = 0; i < pyBaseForRemind->iPhrase; i++) {
2006
2007 if (bDisablePagingInRemind && utarray_len(&candtemp) >= FcitxCandidateWordGetPageSize(FcitxInputStateGetCandidateList(input)))
2008 break;
2009
2010 if (fcitx_utf8_strlen(pystate->strPYRemindSource) == 1) {
2011 if (fcitx_utf8_strlen(pyBaseForRemind->phrase[i].strPhrase) == 1) {
2012 PYCandWord *pycandWord = fcitx_utils_new(PYCandWord);
2013 PYAddRemindCandWord(pystate, &pyBaseForRemind->phrase[i], pycandWord);
2014 utarray_push_back(&candtemp, &pycandWord);
2015 }
2016 } else if (strlen(pyBaseForRemind->phrase[i].strPhrase) == strlen(pystate->strPYRemindSource)) {
2017 if (!strncmp
2018 (pystate->strPYRemindSource + fcitx_utf8_char_len(pystate->strPYRemindSource),
2019 pyBaseForRemind->phrase[i].strPhrase, strlen(pystate->strPYRemindSource + fcitx_utf8_char_len(pystate->strPYRemindSource)))
2020 ) {
2021 PYCandWord *pycandWord = fcitx_utils_new(PYCandWord);
2022 PYAddRemindCandWord(pystate, &pyBaseForRemind->phrase[i], pycandWord);
2023 utarray_push_back(&candtemp, &pycandWord);
2024 }
2025 }
2026 }
2027
2028 phrase = &pyBaseForRemind->userPhrase->next->phrase;
2029 for (i = 0; i < pyBaseForRemind->iUserPhrase; i++) {
2030 if (bDisablePagingInRemind && utarray_len(&candtemp) >= FcitxCandidateWordGetPageSize(FcitxInputStateGetCandidateList(input)))
2031 break;
2032
2033 if (fcitx_utf8_strlen(pystate->strPYRemindSource) == 1) {
2034 if (fcitx_utf8_strlen(phrase->strPhrase) == 1) {
2035 PYCandWord *pycandWord = fcitx_utils_new(PYCandWord);
2036 PYAddRemindCandWord(pystate, phrase, pycandWord);
2037 utarray_push_back(&candtemp, &pycandWord);
2038 }
2039 } else if (strlen(phrase->strPhrase) == strlen(pystate->strPYRemindSource)) {
2040 if (!strncmp
2041 (pystate->strPYRemindSource + fcitx_utf8_char_len(pystate->strPYRemindSource),
2042 phrase->strPhrase, strlen(pystate->strPYRemindSource + fcitx_utf8_char_len(pystate->strPYRemindSource)))) {
2043 PYCandWord *pycandWord = fcitx_utils_new(PYCandWord);
2044 PYAddRemindCandWord(pystate, phrase, pycandWord);
2045 utarray_push_back(&candtemp, &pycandWord);
2046 }
2047 }
2048
2049 phrase = USER_PHRASE_NEXT(phrase);
2050 }
2051
2052 if (utarray_len(&candtemp) == 0) {
2053 utarray_done(&candtemp);
2054 return IRV_TO_PROCESS;
2055 }
2056
2057 FcitxMessages *msg_up = FcitxInputStateGetAuxUp(input);
2058 FcitxMessagesSetMessageCount(msg_up, 0);
2059 FcitxMessagesAddMessageStringsAtLast(msg_up, MSG_TIPS, _("Remind: "));
2060 FcitxMessagesAddMessageStringsAtLast(msg_up, MSG_INPUT,
2061 pystate->strPYRemindSource);
2062
2063 utarray_foreach(pcand, &candtemp, PYCandWord*) {
2064 FcitxCandidateWord candWord;
2065 candWord.callback = PYGetCandWord;
2066 candWord.owner = pystate;
2067 candWord.priv = *pcand;
2068 candWord.strExtra = NULL;
2069 candWord.strWord = strdup((*pcand)->cand.remind.phrase->strPhrase + (*pcand)->cand.remind.iLength);
2070 candWord.wordType = MSG_OTHER;
2071
2072 FcitxCandidateWordAppend(FcitxInputStateGetCandidateList(input), &candWord);
2073 }
2074
2075 utarray_done(&candtemp);
2076
2077 FcitxInputStateSetIsInRemind(input, (FcitxCandidateWordPageCount(FcitxInputStateGetCandidateList(input)) != 0));
2078 return IRV_DISPLAY_CANDWORDS;
2079 }
2080
PYAddRemindCandWord(FcitxPinyinState * pystate,PyPhrase * phrase,PYCandWord * pycandWord)2081 void PYAddRemindCandWord(FcitxPinyinState* pystate, PyPhrase * phrase, PYCandWord* pycandWord)
2082 {
2083 PYRemindCandWord* pyRemindCandWords = &pycandWord->cand.remind;
2084
2085 pycandWord->iWhich = PY_CAND_REMIND;
2086 pyRemindCandWords->phrase = phrase;
2087 pyRemindCandWords->iLength = strlen(pystate->strPYRemindSource) - fcitx_utf8_char_len(pystate->strPYRemindSource);
2088 }
2089
PYGetPYByHZ(FcitxPinyinState * pystate,const char * strHZ,char * strPY)2090 void PYGetPYByHZ(FcitxPinyinState*pystate, const char *strHZ, char *strPY)
2091 {
2092 int i, j;
2093 char str_PY[MAX_PY_LENGTH + 1];
2094 PYFA* PYFAList = pystate->PYFAList;
2095
2096 strPY[0] = '\0';
2097 for (i = pystate->iPYFACount - 1; i >= 0; i--) {
2098 if (MapToPY(PYFAList[i].strMap, str_PY)) {
2099 for (j = 0; j < PYFAList[i].iBase; j++) {
2100 if (!strcmp(PYFAList[i].pyBase[j].strHZ, strHZ)) {
2101 if (strPY[0])
2102 strcat(strPY, " ");
2103 strcat(strPY, str_PY);
2104 }
2105 }
2106 }
2107 }
2108 }
2109
SavePY(void * arg)2110 void SavePY(void *arg)
2111 {
2112 FcitxPinyinState *pystate = (FcitxPinyinState*)arg;
2113 if (pystate->iNewPYPhraseCount)
2114 SavePYUserPhrase(pystate);
2115 if (pystate->iOrderCount)
2116 SavePYIndex(pystate);
2117 if (pystate->iNewFreqCount)
2118 SavePYFreq(pystate);
2119 }
2120
ReloadConfigPY(void * arg)2121 void ReloadConfigPY(void* arg)
2122 {
2123 FcitxPinyinState *pystate = (FcitxPinyinState*)arg;
2124
2125 LoadPYConfig(&pystate->pyconfig);
2126 }
2127
PinyinMigration()2128 void PinyinMigration()
2129 {
2130 char* olduserphrase, *oldpyindex, *newuserphrase, *newpyindex;
2131 FcitxXDGGetFileUserWithPrefix("", PY_USERPHRASE_FILE, NULL, &olduserphrase);
2132 FcitxXDGGetFileUserWithPrefix("", PY_INDEX_FILE, NULL, &oldpyindex);
2133 FcitxXDGGetFileUserWithPrefix("pinyin", PY_USERPHRASE_FILE, NULL, &newuserphrase);
2134 FcitxXDGGetFileUserWithPrefix("pinyin", PY_INDEX_FILE, NULL, &newpyindex);
2135
2136 struct stat olduserphrasestat, oldpyindexstat, newuserphrasestat, newpyindexstat;
2137
2138 /* check old file are all not exist */
2139 if (stat(newpyindex, &newpyindexstat) == -1 && stat(newuserphrase, &newuserphrasestat) == -1) {
2140 if (stat(oldpyindex, &oldpyindexstat) == 0 || stat(olduserphrase, &olduserphrasestat) == 0) {
2141 FcitxLog(INFO, _("Migrate the old file path to the new one"));
2142 /* there might be a very very rare case, that ~/.config/fcitx/pinyin
2143 * and ~/.config/fcitx in different filesystem, who the fucking guy
2144 * do this meaningless go die */
2145 link(oldpyindex, newpyindex);
2146 link(olduserphrase, newuserphrase);
2147 }
2148 }
2149
2150
2151 free(oldpyindex);
2152 free(olduserphrase);
2153 free(newpyindex);
2154 free(newuserphrase);
2155 }
2156
2157 /* decend sort */
PYCandWordCmp(const void * b,const void * a,void * arg)2158 int PYCandWordCmp(const void* b, const void *a, void* arg)
2159 {
2160 const PYCandWord* canda = *(PYCandWord**)a;
2161 const PYCandWord* candb = *(PYCandWord**)b;
2162 PYCandWordSortContext *context = arg;
2163
2164 switch (context->type) {
2165 case PY_CAND_BASE: {
2166 switch (context->order) {
2167 case AD_NO:
2168 return 0;
2169 case AD_FAST: {
2170 int delta = context->pystate->PYFAList[canda->cand.base.iPYFA].pyBase[canda->cand.base.iBase].iIndex
2171 - context->pystate->PYFAList[candb->cand.base.iPYFA].pyBase[candb->cand.base.iBase].iIndex;
2172 if (delta != 0)
2173 return delta;
2174
2175 delta = context->pystate->PYFAList[canda->cand.base.iPYFA].pyBase[canda->cand.base.iBase].iHit
2176 - context->pystate->PYFAList[candb->cand.base.iPYFA].pyBase[candb->cand.base.iBase].iHit;
2177 return delta;
2178 }
2179 break;
2180 case AD_FREQ: {
2181 int delta = context->pystate->PYFAList[canda->cand.base.iPYFA].pyBase[canda->cand.base.iBase].iHit
2182 - context->pystate->PYFAList[candb->cand.base.iPYFA].pyBase[candb->cand.base.iBase].iHit;
2183 if (delta != 0)
2184 return delta;
2185
2186 delta = context->pystate->PYFAList[canda->cand.base.iPYFA].pyBase[canda->cand.base.iBase].iIndex
2187 - context->pystate->PYFAList[candb->cand.base.iPYFA].pyBase[candb->cand.base.iBase].iIndex;
2188 return delta;
2189 }
2190 break;
2191 }
2192 }
2193 break;
2194 case PY_CAND_SYSPHRASE:
2195 case PY_CAND_USERPHRASE: {
2196 switch (context->order) {
2197 case AD_NO:
2198 return strlen(canda->cand.phrase.phrase->strPhrase) - strlen(candb->cand.phrase.phrase->strPhrase);
2199 break;
2200 case AD_FAST: {
2201 int size = strlen(canda->cand.phrase.phrase->strPhrase) - strlen(candb->cand.phrase.phrase->strPhrase);
2202 if (size != 0)
2203 return size;
2204
2205 if (canda->cand.phrase.phrase->iIndex - candb->cand.phrase.phrase->iIndex != 0)
2206 return canda->cand.phrase.phrase->iIndex - candb->cand.phrase.phrase->iIndex;
2207
2208 return canda->cand.phrase.phrase->iHit - candb->cand.phrase.phrase->iHit;
2209 }
2210 break;
2211 case AD_FREQ: {
2212 int size = strlen(canda->cand.phrase.phrase->strPhrase) - strlen(candb->cand.phrase.phrase->strPhrase);
2213 if (size != 0)
2214 return size;
2215
2216 if (canda->cand.phrase.phrase->iHit - candb->cand.phrase.phrase->iHit != 0)
2217 return canda->cand.phrase.phrase->iHit - candb->cand.phrase.phrase->iHit;
2218
2219 return canda->cand.phrase.phrase->iIndex - candb->cand.phrase.phrase->iIndex;
2220 }
2221 break;
2222 }
2223 }
2224 break;
2225 case PY_CAND_FREQ: {
2226 switch (context->order) {
2227 case AD_NO:
2228 return 0;
2229 case AD_FAST:
2230 return canda->cand.freq.hz->iIndex - candb->cand.freq.hz->iIndex;
2231 case AD_FREQ:
2232 return canda->cand.freq.hz->iHit - candb->cand.freq.hz->iHit;
2233 }
2234 }
2235 break;
2236 case PY_CAND_REMIND:
2237 return canda->cand.remind.phrase->iHit - canda->cand.remind.phrase->iHit;
2238 default:
2239 return 0;
2240 }
2241
2242 return 0;
2243 }
2244
2245 static char*
PYSP2QP(FcitxPinyinState * pystate,const char * strSP)2246 PYSP2QP(FcitxPinyinState *pystate, const char* strSP)
2247 {
2248 char strQP[MAX_PY_LENGTH + 1] = "";
2249 SP2QP(&pystate->pyconfig, strSP, strQP);
2250 return strdup(strQP);
2251 }
2252
2253 static boolean
PYGetPYMapByHZ(FcitxPinyinState * pystate,char * strHZ,char * mapHint,char * strMap)2254 PYGetPYMapByHZ(FcitxPinyinState* pystate, char* strHZ,
2255 char* mapHint, char* strMap)
2256 {
2257 int i, j;
2258 PYFA* PYFAList = pystate->PYFAList;
2259
2260 strMap[0] = '\0';
2261 for (i = pystate->iPYFACount - 1; i >= 0; i--) {
2262 if (!Cmp2Map(&pystate->pyconfig, PYFAList[i].strMap, mapHint, false)) {
2263 for (j = 0; j < PYFAList[i].iBase; j++) {
2264 if (!strcmp(PYFAList[i].pyBase[j].strHZ, strHZ)) {
2265 strcpy(strMap, PYFAList[i].strMap);
2266 return true;
2267 }
2268 }
2269 }
2270 }
2271 return false;
2272 }
2273
2274 static void
PYAddUserPhraseFromCString(FcitxPinyinState * pystate,const char * strHZ)2275 PYAddUserPhraseFromCString(FcitxPinyinState *pystate, const char *strHZ)
2276 {
2277 const char *pivot;
2278 char *sp;
2279 char singleHZ[UTF8_MAX_LENGTH + 1];
2280 char strMap[3];
2281 if (!fcitx_utf8_check_string(strHZ))
2282 return;
2283
2284 pivot = strHZ;
2285 size_t hzCount = fcitx_utf8_strlen(strHZ);
2286 size_t hzCountLocal = 0;
2287
2288 if (pystate->iPYSelected) {
2289 int i;
2290 for (i = 0 ; i < pystate->iPYSelected; i ++) {
2291 hzCountLocal += strlen(pystate->pySelected[i].strMap) / 2;
2292 }
2293 }
2294 hzCountLocal += pystate->findMap.iHZCount;
2295
2296 /* in order not to get a wrong one, use strict check */
2297 if (hzCountLocal != hzCount || hzCount > MAX_PY_PHRASE_LENGTH)
2298 return;
2299 char *totalMap = fcitx_utils_malloc0(1 + 2 * hzCount);
2300
2301 if (pystate->iPYSelected) {
2302 int i;
2303 for (i = 0 ; i < pystate->iPYSelected; i ++)
2304 strcat(totalMap, pystate->pySelected[i].strMap);
2305 strHZ = fcitx_utf8_get_nth_char(strHZ, strlen(totalMap) / 2);
2306 }
2307
2308 int i = 0;
2309 while (*strHZ) {
2310 uint32_t chr;
2311
2312 sp = fcitx_utf8_get_char(strHZ, &chr);
2313 size_t len = sp - strHZ;
2314 strncpy(singleHZ, strHZ, len);
2315 singleHZ[len] = '\0';
2316
2317 if (!PYGetPYMapByHZ(pystate, singleHZ, pystate->findMap.strMap[i],
2318 strMap)) {
2319 free(totalMap);
2320 return;
2321 }
2322
2323 strncat(totalMap, strMap, 2);
2324 strHZ = sp;
2325 i ++;
2326 }
2327
2328 PYAddUserPhrase(pystate, pivot, totalMap, true);
2329 free(totalMap);
2330 }
2331
2332 #include "fcitx-pinyin-addfunctions.h"
2333