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 
21 #include <stdio.h>
22 #include <limits.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <libintl.h>
26 
27 #include "punc.h"
28 #include "fcitx/module.h"
29 #include "fcitx/fcitx.h"
30 #include "fcitx/hook.h"
31 #include "fcitx/ime.h"
32 #include "fcitx/keys.h"
33 #include "fcitx/frontend.h"
34 #include "fcitx/instance.h"
35 #include "fcitx/candidate.h"
36 #include "fcitx/context.h"
37 #include "fcitx-config/xdg.h"
38 #include "fcitx-utils/log.h"
39 #include "fcitx-utils/utils.h"
40 #include "fcitx-utils/bitset.h"
41 #include "module/freedesktop-notify/fcitx-freedesktop-notify.h"
42 
43 /**
44  * @file punc.c
45  * Trans full width punc for Fcitx
46  */
47 
48 #define PUNC_DICT_FILENAME  "punc.mb"
49 #define MAX_PUNC_NO     2
50 #define MAX_PUNC_LENGTH     2
51 
52 struct _FcitxPuncState;
53 typedef struct _WidePunc {
54     char ASCII;
55     char strWidePunc[MAX_PUNC_NO][MAX_PUNC_LENGTH * UTF8_MAX_LENGTH + 1];
56     unsigned iCount: 2;
57 } WidePunc;
58 
59 typedef struct _PuncWhich {
60     FcitxBitSet* bitset;
61     WidePunc* lastPunc;
62 } PuncWhich;
63 
64 typedef struct _FcitxPunc {
65     char* langCode;
66     WidePunc* curPunc;
67 
68     UT_hash_handle hh;
69 } FcitxPunc;
70 
71 static boolean LoadPuncDict(struct _FcitxPuncState* puncState);
72 static FcitxPunc* LoadPuncFile(const char* filename);
73 static char *GetPunc(struct _FcitxPuncState* puncState, int iKey);
74 static void FreePunc(struct _FcitxPuncState* puncState);
75 static void* PuncCreate(FcitxInstance* instance);
76 static boolean PuncPreFilter(void* arg, FcitxKeySym sym, unsigned int state, INPUT_RETURN_VALUE* retVal);
77 static boolean ProcessPunc(void* arg, FcitxKeySym sym, unsigned int state, INPUT_RETURN_VALUE* retVal);
78 static void TogglePuncState(void *arg);
79 static boolean GetPuncState(void *arg);
80 static void ReloadPunc(void *arg);
81 static INPUT_RETURN_VALUE TogglePuncStateWithHotkey(void *arg);
82 static void ResetPunc(void *arg);
83 static void ResetPuncWhichStatus(void* arg);
84 static boolean IsHotKeyPunc(FcitxKeySym sym, unsigned int state);
85 static void PuncLanguageChanged(void* arg, const void* value);
86 
87 static void* PuncWhichAlloc(void* arg);
88 static void* PuncWhichCopy(void* arg, void* data, void* src);
89 static void PuncWhichFree(void* arg, void* data);
90 
91 DECLARE_ADDFUNCTIONS(Punc)
92 
93 typedef struct _FcitxPuncState {
94     char cLastIsAutoConvert;
95     boolean bLastIsNumber;
96     FcitxInstance* owner;
97     FcitxPunc* puncSet;
98     WidePunc* curPunc;
99     int slot;
100 } FcitxPuncState;
101 
102 FCITX_DEFINE_PLUGIN(fcitx_punc, module, FcitxModule) = {
103     PuncCreate,
104     NULL,
105     NULL,
106     NULL,
107     ReloadPunc
108 };
109 
PuncCreate(FcitxInstance * instance)110 void* PuncCreate(FcitxInstance* instance)
111 {
112     FcitxPuncState* puncState = fcitx_utils_malloc0(sizeof(FcitxPuncState));
113     puncState->owner = instance;
114     LoadPuncDict(puncState);
115     FcitxKeyFilterHook hk;
116     hk.arg = puncState;
117     hk.func = ProcessPunc;
118 
119     FcitxInstanceRegisterPostInputFilter(instance, hk);
120 
121     hk.func = PuncPreFilter;
122     FcitxInstanceRegisterPreInputFilter(instance, hk);
123 
124     puncState->cLastIsAutoConvert = '\0';
125     puncState->bLastIsNumber = false;
126 
127     FcitxHotkeyHook hotkey;
128     hotkey.hotkey = FcitxInstanceGetGlobalConfig(instance)->hkPunc;
129     hotkey.hotkeyhandle = TogglePuncStateWithHotkey;
130     hotkey.arg = puncState;
131     FcitxInstanceRegisterHotkeyFilter(instance, hotkey);
132 
133     FcitxIMEventHook hook;
134     hook.arg = puncState;
135     hook.func = ResetPunc;
136 
137     FcitxInstanceRegisterResetInputHook(instance, hook);
138 
139     hook.func = ResetPuncWhichStatus;
140 
141     FcitxInstanceRegisterInputUnFocusHook(instance, hook);
142 
143     FcitxInstanceWatchContext(instance, CONTEXT_IM_LANGUAGE,
144                               PuncLanguageChanged, puncState);
145 
146     FcitxProfile* profile = FcitxInstanceGetProfile(instance);
147     FcitxUIRegisterStatus(instance, puncState, "punc",
148                           profile->bUseWidePunc ? _("Full width punct") :
149                           _("Latin punct"),
150                           _("Toggle Full Width Punctuation"), TogglePuncState,
151                           GetPuncState);
152 
153     puncState->slot = FcitxInstanceAllocDataForIC(instance, PuncWhichAlloc,
154                                                   PuncWhichCopy, PuncWhichFree,
155                                                   puncState);
156 
157     FcitxInstanceRegisterWatchableContext(instance, CONTEXT_DISABLE_PUNC, FCT_Boolean, FCF_ResetOnInputMethodChange);
158 
159     FcitxPuncAddFunctions(instance);
160     return puncState;
161 }
162 
PuncWhichAlloc(void * arg)163 void* PuncWhichAlloc(void *arg)
164 {
165     FcitxPunc *puncState = arg;
166     PuncWhich *which = fcitx_utils_new(PuncWhich);
167     which->lastPunc = puncState->curPunc;
168     which->bitset = fcitx_bitset_new(256);
169     return which;
170 }
171 
PuncWhichCopy(void * arg,void * data,void * src)172 void* PuncWhichCopy(void* arg, void* data, void* src)
173 {
174     FCITX_UNUSED(arg);
175     PuncWhich *which = data;
176     PuncWhich *whichsrc = src;
177     which->lastPunc = whichsrc->lastPunc;
178     memcpy(which->bitset, whichsrc->bitset, fcitx_bitset_size(256));
179     return data;
180 }
181 
PuncWhichFree(void * arg,void * data)182 void PuncWhichFree(void* arg, void* data)
183 {
184     FCITX_UNUSED(arg);
185     PuncWhich *which = data;
186     free(which->bitset);
187     free(data);
188 }
189 
PuncLanguageChanged(void * arg,const void * value)190 void PuncLanguageChanged(void* arg, const void* value)
191 {
192     FcitxPuncState* puncState = (FcitxPuncState*) arg;
193     const char* lang = (const char*) value;
194     FcitxPunc* punc = NULL;
195     if (lang) {
196         HASH_FIND_STR(puncState->puncSet, lang, punc);
197         if (punc)
198             puncState->curPunc = punc->curPunc;
199         else
200             puncState->curPunc = NULL;
201     } else
202         puncState->curPunc = NULL;
203 
204     FcitxUISetStatusVisable (puncState->owner, "punc",  puncState->curPunc != NULL) ;
205 }
206 
207 static void
PuncGetPunc2(FcitxPuncState * puncState,int key,char ** p1,char ** p2)208 PuncGetPunc2(FcitxPuncState *puncState, int key, char **p1, char **p2)
209 {
210     int iIndex = 0;
211     WidePunc *curPunc = puncState->curPunc;
212 
213     if (!curPunc)
214         return;
215 
216     while (curPunc[iIndex].ASCII) {
217         if (curPunc[iIndex].ASCII == key) {
218             if (p1)
219                 *p1 = curPunc[iIndex].strWidePunc[0];
220             if (curPunc[iIndex].iCount > 1 && p2)
221                 *p2 = curPunc[iIndex].strWidePunc[1];
222             break;
223         }
224         iIndex++;
225     }
226 }
227 
ResetPunc(void * arg)228 void ResetPunc(void* arg)
229 {
230     FcitxPuncState* puncState = (FcitxPuncState*) arg;
231     puncState->bLastIsNumber = false;
232     puncState->cLastIsAutoConvert = '\0';
233 }
234 
ResetPuncWhichStatus(void * arg)235 void ResetPuncWhichStatus(void* arg)
236 {
237     FcitxPuncState* puncState = (FcitxPuncState*) arg;
238     WidePunc       *curPunc = puncState->curPunc;
239 
240     if (!curPunc)
241         return;
242 
243     FcitxInputContext* ic = FcitxInstanceGetCurrentIC(puncState->owner);
244     if (!ic)
245         return;
246     PuncWhich* puncWhich = FcitxInstanceGetICData(puncState->owner, ic, puncState->slot);
247     fcitx_bitset_clear(puncWhich->bitset);
248 }
249 
PuncPreFilter(void * arg,FcitxKeySym sym,unsigned int state,INPUT_RETURN_VALUE * retVal)250 boolean PuncPreFilter(void* arg, FcitxKeySym sym, unsigned int state,
251                       INPUT_RETURN_VALUE* retVal)
252 {
253     FCITX_UNUSED(retVal);
254     FcitxPuncState *puncState = (FcitxPuncState*)arg;
255     boolean disablePunc = FcitxInstanceGetContextBoolean(
256         puncState->owner, CONTEXT_DISABLE_PUNC);
257     if (disablePunc)
258         return false;
259 
260     if (FcitxHotkeyIsHotKeySimple(sym, state) &&
261         !FcitxHotkeyIsHotKeyDigit(sym, state) && !IsHotKeyPunc(sym, state))
262         puncState->bLastIsNumber = false;
263     return false;
264 }
265 
ProcessPunc(void * arg,FcitxKeySym sym,unsigned int state,INPUT_RETURN_VALUE * retVal)266 boolean ProcessPunc(void* arg, FcitxKeySym sym, unsigned int state, INPUT_RETURN_VALUE* retVal)
267 {
268     FcitxPuncState* puncState = (FcitxPuncState*) arg;
269     FcitxInstance* instance = puncState->owner;
270     FcitxInputState* input = FcitxInstanceGetInputState(puncState->owner);
271     FcitxProfile* profile = FcitxInstanceGetProfile(instance);
272     FcitxGlobalConfig* config = FcitxInstanceGetGlobalConfig(instance);
273 
274     char *pPunc = NULL;
275 
276     if (*retVal != IRV_TO_PROCESS)
277         return false;
278 
279     boolean disablePunc = FcitxInstanceGetContextBoolean(
280         puncState->owner, CONTEXT_DISABLE_PUNC);
281     if (disablePunc)
282         return false;
283 
284     FcitxCandidateWordList *candList = FcitxInputStateGetCandidateList(input);
285     if (FcitxCandidateWordGetListSize(candList) != 0) {
286         if (FcitxCandidateWordGetHasGoneToNextPage(candList) &&
287             FcitxHotkeyIsHotKey(sym, state,
288                                 FcitxConfigPrevPageKey(instance, config))) {
289             return false;
290         }
291         /*
292          * comparing with upper case, if paging is occupied,
293          * punc will not let next page pass
294          */
295         if (FcitxHotkeyIsHotKey(sym, state,
296                                 FcitxConfigNextPageKey(instance, config))) {
297             return false;
298         }
299     }
300 
301     FcitxKeySym origsym = sym;
302     sym = FcitxHotkeyPadToMain(sym);
303     if (profile->bUseWidePunc) {
304         if (puncState->bLastIsNumber && config->bEngPuncAfterNumber
305             && (FcitxHotkeyIsHotKey(origsym, state, FCITX_PERIOD)
306                 || FcitxHotkeyIsHotKey(origsym, state, FCITX_SEMICOLON)
307                 || FcitxHotkeyIsHotKey(origsym, state, FCITX_COMMA))) {
308             puncState->cLastIsAutoConvert = origsym;
309             puncState->bLastIsNumber = false;
310             *retVal = IRV_DONOT_PROCESS;
311             return true;
312         }
313         if (FcitxHotkeyIsHotKeySimple(sym, state))
314             pPunc = GetPunc(puncState, origsym);
315     }
316 
317     /*
318      * 在有候选词未输入的情况下,选择第一个候选词并输入标点
319      */
320     if (IsHotKeyPunc(sym, state)) {
321         FcitxInputStateGetOutputString(input)[0] = '\0';
322         INPUT_RETURN_VALUE ret = IRV_TO_PROCESS;
323         if (!FcitxInputStateGetIsInRemind(input))
324             ret = FcitxCandidateWordChooseByTotalIndex(FcitxInputStateGetCandidateList(input), 0);
325 
326         /* if there is nothing to commit */
327         if (ret == IRV_TO_PROCESS) {
328             if (pPunc) {
329                 strcat(FcitxInputStateGetOutputString(input), pPunc);
330                 *retVal = IRV_PUNC;
331                 FcitxInstanceCleanInputWindow(instance);
332                 return true;
333             } else
334                 return false;
335         } else {
336             if (pPunc)
337                 strcat(FcitxInputStateGetOutputString(input), pPunc);
338             else {
339                 char buf[2] = { sym, 0 };
340                 strcat(FcitxInputStateGetOutputString(input), buf);
341             }
342 
343             FcitxInstanceCleanInputWindow(instance);
344             *retVal = IRV_PUNC;
345             return true;
346         }
347 
348         return false;
349     }
350 
351     if (profile->bUseWidePunc) {
352         if (FcitxHotkeyIsHotKey(sym, state, FCITX_BACKSPACE)
353             && puncState->cLastIsAutoConvert) {
354             char *pPunc;
355 
356             FcitxInstanceForwardKey(puncState->owner, FcitxInstanceGetCurrentIC(instance), FCITX_PRESS_KEY, sym, state);
357             pPunc = GetPunc(puncState, puncState->cLastIsAutoConvert);
358             if (pPunc)
359                 FcitxInstanceCommitString(puncState->owner, FcitxInstanceGetCurrentIC(instance), pPunc);
360 
361             puncState->cLastIsAutoConvert = 0;
362             *retVal = IRV_DO_NOTHING;
363             return true;
364         } else if (FcitxHotkeyIsHotKeyDigit(sym, state)) {
365             puncState->bLastIsNumber = true;
366         } else {
367             puncState->bLastIsNumber = false;
368         }
369     }
370     puncState->cLastIsAutoConvert = 0;
371     return false;
372 }
373 
374 /**
375  * 加载标点词典
376  * @param void
377  * @return void
378  * @note 文件中数据的格式为: 对应的英文符号 中文标点 <中文标点>
379  * 加载标点词典。标点词典定义了一组标点转换,如输入‘.’就直接转换成‘。’
380  */
LoadPuncDict(FcitxPuncState * puncState)381 boolean LoadPuncDict(FcitxPuncState* puncState)
382 {
383     FcitxStringHashSet* puncfiles = FcitxXDGGetFiles("data", PUNC_DICT_FILENAME "." , NULL);
384     FcitxStringHashSet *curpuncfile = puncfiles;
385     FcitxPunc* punc;
386     while (curpuncfile) {
387         punc = LoadPuncFile(curpuncfile->name);
388         if (punc)
389             HASH_ADD_KEYPTR(hh, puncState->puncSet, punc->langCode, strlen(punc->langCode), punc);
390         curpuncfile = curpuncfile->hh.next;
391     }
392 
393     fcitx_utils_free_string_hash_set(puncfiles);
394     return true;
395 }
396 
LoadPuncFile(const char * filename)397 FcitxPunc* LoadPuncFile(const char* filename)
398 {
399     FILE           *fpDict;             // 词典文件指针
400     int             iRecordNo;
401     char            strText[4 + MAX_PUNC_LENGTH * UTF8_MAX_LENGTH];
402     char           *pstr;               // 临时指针
403     int             i;
404     fpDict = FcitxXDGGetFileWithPrefix("data", filename, "r", NULL);
405 
406     if (strlen(filename) < strlen(PUNC_DICT_FILENAME))
407         return NULL;
408 
409     if (!fpDict) {
410         FcitxLog(WARNING, _("Can't open punc file."));
411         return NULL;
412     }
413 
414     /* 计算词典里面有多少的数据
415      * 这个函数非常简单,就是计算该文件有多少行(包含空行)。
416      * 因为空行,在下面会略去,所以,这儿存在内存的浪费现象。
417      * 没有一个空行就是浪费sizeof (WidePunc)字节内存*/
418     iRecordNo = fcitx_utils_calculate_record_number(fpDict);
419     // 申请空间,用来存放这些数据。这儿没有检查是否申请到内存,严格说有小隐患
420     WidePunc* punc = (WidePunc *) fcitx_utils_malloc0(sizeof(WidePunc) * (iRecordNo + 1));
421 
422     iRecordNo = 0;
423 
424     // 下面这个循环,就是一行一行的读入词典文件的数据。并将其放入到curPunc里面去。
425     for (;;) {
426         if (!fgets(strText, (MAX_PUNC_LENGTH * UTF8_MAX_LENGTH + 3), fpDict))
427             break;
428         i = strlen(strText) - 1;
429 
430         // 先找到最后一个字符
431         while ((strText[i] == '\n') || (strText[i] == ' ')) {
432             if (!i)
433                 break;
434             i--;
435         }
436 
437         // 如果找到,进行出入。当是空行时,肯定找不到。所以,也就略过了空行的处理
438         if (i) {
439             strText[i + 1] = '\0';              // 在字符串的最后加个封口
440             pstr = strText;                     // 将pstr指向第一个非空字符
441             while (*pstr == ' ')
442                 pstr++;
443             punc[iRecordNo].ASCII = *pstr++; // 这个就是中文符号所对应的ASCII码值
444             while (*pstr == ' ')                // 然后,将pstr指向下一个非空字符
445                 pstr++;
446 
447             punc[iRecordNo].iCount = 0;      // 该符号有几个转化,比如英文"就可以转换成“和”
448             // 依次将该ASCII码所对应的符号放入到结构中
449             while (*pstr) {
450                 i = 0;
451                 // 因为中文符号都是多字节(这里读取并不像其他地方是固定两个,所以没有问题)的,所以,要一直往后读,知道空格或者字符串的末尾
452                 while (*pstr != ' ' && *pstr) {
453                     punc[iRecordNo].strWidePunc[punc[iRecordNo].iCount][i] = *pstr;
454                     i++;
455                     pstr++;
456                 }
457 
458                 // 每个中文符号用'\0'隔开
459                 punc[iRecordNo].strWidePunc[punc[iRecordNo].iCount][i] = '\0';
460                 while (*pstr == ' ')
461                     pstr++;
462                 punc[iRecordNo].iCount++;
463             }
464 
465             iRecordNo++;
466         }
467     }
468 
469     punc[iRecordNo].ASCII = '\0';
470     fclose(fpDict);
471 
472     FcitxPunc* p = fcitx_utils_malloc0(sizeof(FcitxPunc));
473     p->langCode = "";
474 
475     const char* langcode = filename + strlen(PUNC_DICT_FILENAME);
476     if (*langcode == '\0')
477         p->langCode = strdup("C");
478     else
479         p->langCode = strdup(langcode + 1);
480 
481     p->curPunc = punc;
482 
483     return p;
484 }
485 
FreePunc(FcitxPuncState * puncState)486 void FreePunc(FcitxPuncState* puncState)
487 {
488     puncState->curPunc = NULL;
489     FcitxPunc* cur;
490     while (puncState->puncSet) {
491         cur = puncState->puncSet;
492         HASH_DEL(puncState->puncSet, cur);
493         free(cur->langCode);
494         free(cur->curPunc);
495         free(cur);
496     }
497 }
498 
GetPuncWhich(FcitxPuncState * puncState,WidePunc * punc)499 static inline int GetPuncWhich(FcitxPuncState* puncState, WidePunc* punc)
500 {
501     FcitxInputContext* ic = FcitxInstanceGetCurrentIC(puncState->owner);
502     if (!ic)
503         return 0;
504     PuncWhich* puncWhich = FcitxInstanceGetICData(puncState->owner, ic, puncState->slot);
505     if (puncWhich->lastPunc != puncState->curPunc) {
506         fcitx_bitset_clear(puncWhich->bitset);
507         puncWhich->lastPunc = puncState->curPunc;
508     }
509     int result = fcitx_bitset_isset(puncWhich->bitset, punc->ASCII) ? 1 : 0;
510     if (result >= punc->iCount)
511         result = 0;
512     return result;
513 }
514 
SetPuncWhich(FcitxPuncState * puncState,WidePunc * punc)515 static inline void SetPuncWhich(FcitxPuncState* puncState, WidePunc* punc)
516 {
517     FcitxInputContext* ic = FcitxInstanceGetCurrentIC(puncState->owner);
518     if (!ic)
519         return;
520     PuncWhich* puncWhich = FcitxInstanceGetICData(puncState->owner, ic, puncState->slot);
521     FcitxBitSet* bitset = puncWhich->bitset;
522     if (punc->iCount == 1)
523         fcitx_bitset_unset(bitset, punc->ASCII);
524     else {
525         if (fcitx_bitset_isset(bitset, punc->ASCII))
526             fcitx_bitset_unset(bitset, punc->ASCII);
527         else
528             fcitx_bitset_set(bitset, punc->ASCII);
529     }
530 }
531 
532 /*
533  * 根据字符得到相应的标点符号
534  * 如果该字符不在标点符号集中,则返回NULL
535  */
536 static char*
GetPunc(FcitxPuncState * puncState,int iKey)537 GetPunc(FcitxPuncState *puncState, int iKey)
538 {
539     int iIndex = 0;
540     char *pPunc;
541     WidePunc *curPunc = puncState->curPunc;
542 
543     if (!curPunc)
544         return NULL;
545 
546     while (curPunc[iIndex].ASCII) {
547         if (curPunc[iIndex].ASCII == iKey) {
548             pPunc = curPunc[iIndex].strWidePunc[GetPuncWhich(puncState,
549                                                              &curPunc[iIndex])];
550             SetPuncWhich(puncState, &curPunc[iIndex]);
551             return pPunc;
552         }
553         iIndex++;
554     }
555 
556     return NULL;
557 }
558 
TogglePuncState(void * arg)559 void TogglePuncState(void* arg)
560 {
561     FcitxPuncState* puncState = (FcitxPuncState*)arg;
562     FcitxInstance* instance = puncState->owner;
563     FcitxProfile* profile = FcitxInstanceGetProfile(instance);
564     profile->bUseWidePunc = !profile->bUseWidePunc;
565 
566     FcitxUISetStatusString(puncState->owner, "punc",
567                            profile->bUseWidePunc ? _("Full width punct") :
568                            _("Latin punct"),
569                            _("Toggle Full Width Punctuation"));
570     FcitxProfileSave(profile);
571 }
572 
TogglePuncStateWithHotkey(void * arg)573 INPUT_RETURN_VALUE TogglePuncStateWithHotkey(void* arg)
574 {
575     FcitxPuncState *puncState = (FcitxPuncState*)arg;
576     FcitxInstance *instance = puncState->owner;
577     FcitxProfile *profile = FcitxInstanceGetProfile(instance);
578 
579     FcitxUIStatus *status = FcitxUIGetStatusByName(instance, "punc");
580     if (status->visible){
581         FcitxUIUpdateStatus(instance, "punc");
582         FcitxFreeDesktopNotifyShowAddonTip(
583             instance, "fcitx-punc-toggle",
584             profile->bUseWidePunc ? "fcitx-punc-active" : "fcitx-punc-inactive",
585             _("Punctuation Support"),
586             profile->bUseWidePunc ? _("Full width punctuations are used.") :
587                                     _("Latin punctuations are used."));
588         return IRV_DO_NOTHING;
589     } else {
590         return IRV_TO_PROCESS;
591     }
592 }
593 
GetPuncState(void * arg)594 boolean GetPuncState(void* arg)
595 {
596     FcitxPuncState* puncState = (FcitxPuncState*) arg;
597     FcitxInstance* instance = puncState->owner;
598     FcitxProfile* profile = FcitxInstanceGetProfile(instance);
599     return profile->bUseWidePunc;
600 }
601 
ReloadPunc(void * arg)602 void ReloadPunc(void* arg)
603 {
604     FcitxPuncState* puncState = (FcitxPuncState*) arg;
605     FreePunc(puncState);
606     LoadPuncDict(puncState);
607 
608     PuncLanguageChanged(puncState, FcitxInstanceGetContextString(puncState->owner, CONTEXT_IM_LANGUAGE));
609 }
610 
IsHotKeyPunc(FcitxKeySym sym,unsigned int state)611 boolean IsHotKeyPunc(FcitxKeySym sym, unsigned int state)
612 {
613     if (FcitxHotkeyIsHotKeySimple(sym, state)
614         && !FcitxHotkeyIsHotKeyDigit(sym, state)
615         && !FcitxHotkeyIsHotKeyLAZ(sym, state)
616         && !FcitxHotkeyIsHotKeyUAZ(sym, state)
617         && !FcitxHotkeyIsHotKey(sym, state, FCITX_SPACE))
618         return true;
619 
620     return false;
621 }
622 #include "fcitx-punc-addfunctions.h"
623