$NetBSD: patch-ag,v 1.2 2006/03/14 15:11:54 rxg Exp $ --- src/Cinput/chewing/xcin_chewing.c.orig 2006-03-13 22:26:59.000000000 +0800 +++ src/Cinput/chewing/xcin_chewing.c @@ -0,0 +1,515 @@ +/* + * Bridge interface between libchewing and xcin + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include +#include +#include "xcintool.h" +#include "module.h" + +#include +#include + +/* the following keystate masks are defined by xcin */ +#define CAPS_MASK (2) +#define CTRL_MASK (4) + +#define XCIN_BYTE_NATIVE 2 +#define XCIN_BYTE_UTF8 3 + +static int chewing_codeset; +void preconvert(char *input, char *output, int n_char); +wchar_t convert(wchar_t input); + +static char selKey_define[11] = "1234567890\0"; /* Default */ +static int bAddPhraseForward = 0; + +int MakeInpinfo(inpinfo_t *inpinfo, ChewingOutput *pgo); + +int CallSetConfig(inpinfo_t *inpinfo, ChewingData *pgdata) +{ + ConfigData config; + int i; + + config.selectAreaLen = 40; + config.maxChiSymbolLen = 16; + config.bAddPhraseForward = bAddPhraseForward; + + for (i = 0; i < 10;i++) + config.selKey[i] = selKey_define[i]; + + SetConfig(pgdata, &config); + return 0; +} + +static int +ChewingInit(void *conf, char *objname, xcin_rc_t *xc) +{ + char *cmd[2], kb_type_str[256], *cname; + ChewingConf *cf = (ChewingConf *)conf ; + + char *prefix = CHEWING_DATA_DIR; + + /* + * Because libchewing uses BIG-5 encoding for all its structure + * so we need to check if it is UTF-8 locale and do any conv + */ + chewing_codeset = (! strcasecmp(xc->locale.encoding,"utf-8")) ? + XCIN_BYTE_UTF8 : + XCIN_BYTE_NATIVE; + cname = (char *) calloc(3, sizeof(char) * chewing_codeset); + + cmd[0] = objname ; + cmd[1] = "KB_TYPE" ; + kb_type_str[0] = '\0'; + get_resource(xc, cmd, kb_type_str, 200, 2); + cf->kb_type = KBStr2Num(kb_type_str); + + /* Support selection key definitions */ + cmd[1] = "SELECTION_KEYS_DEFINE"; + if (get_resource(xc, cmd, kb_type_str, 256, 2)) { + if (strlen(kb_type_str) == 10) { + strcpy(selKey_define, kb_type_str); + selKey_define[11] = '\0'; + } + } + cmd[1] = "ADD_PHRASE_FORWARD"; + if (get_resource(xc, cmd, kb_type_str, 256, 2)) { + if (atoi(kb_type_str) == 1) { + bAddPhraseForward = 1; + } + } + + preconvert("·s»Å­µ", cname, 6); + cf->inp_cname = strdup(cname); + cf->inp_ename = strdup("Chewing"); + + /* Initialize Chewing */ + ReadTree(prefix); + InitChar(prefix); + InitDict(prefix); + ReadHash(prefix); + + return True; +} + +static int +ChewingXimInit(void *conf, inpinfo_t *inpinfo) +{ + static char cchBuffer[MAX_PHONE_SEQ_LEN]; + ChewingConf *cf = (ChewingConf *) conf; + int i; + + inpinfo->iccf = (ChewingData *) calloc(1, sizeof(ChewingData)); + + InitChewing(inpinfo->iccf, cf); + CallSetConfig(inpinfo, (ChewingData *) inpinfo->iccf); + + inpinfo->lcch = (wch_t *) calloc(MAX_PHONE_SEQ_LEN, sizeof(wch_t)); + inpinfo->lcch_grouping = (ubyte_t *) calloc(MAX_PHONE_SEQ_LEN, sizeof(ubyte_t)); + inpinfo->cch = cchBuffer; + + inpinfo->inp_cname = cf->inp_cname; + inpinfo->inp_ename = cf->inp_ename; + inpinfo->area3_len = 2 * ZUIN_SIZE + 4; + inpinfo->guimode = GUIMOD_LISTCHAR | GUIMOD_SELKEYSPOT; + inpinfo->keystroke_len = 0; + inpinfo->s_keystroke = (wch_t *) calloc(3 + MAX_PHRASE_LEN, sizeof(wch_t)); + + inpinfo->mcch = (wch_t *) calloc(MAX_CHOICE_BUF, sizeof(wch_t)); + inpinfo->mcch_grouping = (ubyte_t *) calloc( MAX_SELKEY, sizeof(ubyte_t)); + inpinfo->n_mcch = 0; + + inpinfo->n_lcch = 0; + inpinfo->edit_pos = 0; + inpinfo->cch_publish.wch = (wchar_t) 0; + + // check_winsize(inpinfo, iccf); + // [yet] check winsize is under construction. + + inpinfo->n_selkey = 10; + inpinfo->s_selkey = (wch_t *) calloc(MAX_SELKEY, sizeof(wch_t)); + + for (i = 0; i < 10; i++) { + inpinfo->s_selkey[i].wch = (wchar_t) 0; + inpinfo->s_selkey[i].s[0] = selKey_define[i]; + } + + return True; +} + +void CommitString(inpinfo_t *inpinfo, ChewingOutput *pgo) +{ + int i ; + char *str; + char *output; + memset(inpinfo->cch, 0, sizeof(char)*MAX_PHONE_SEQ_LEN); + str = (char *) calloc(MAX_PHONE_SEQ_LEN,sizeof(char)); + output = (char *) calloc(MAX_PHONE_SEQ_LEN / 2 * chewing_codeset, sizeof(char)); + for (i = 0; i < pgo->nCommitStr; i++) + strcat(str, (const char *) pgo->commitStr[i].s); + preconvert(str, output, strlen(str)); + strcat(inpinfo->cch, output); + free(str); + free(output); +} + +static unsigned int +ChewingXimEnd(void *conf, inpinfo_t *inpinfo) +{ + ChewingOutput gOut ; + int rtn ; + + /* if preedit exists, commit the string */ + OnKeyEnter(inpinfo->iccf, &gOut); + + rtn = MakeInpinfo(inpinfo, &gOut); + free(inpinfo->iccf); + free(inpinfo->s_keystroke); + free(inpinfo->lcch); + free(inpinfo->mcch); + free(inpinfo->mcch_grouping); + + inpinfo->iccf = NULL; + inpinfo->s_keystroke = NULL; + inpinfo->lcch = NULL; + + return rtn ; +} + +void ShowChoose(inpinfo_t *inpinfo, ChoiceInfo *pci, ChewingOutput *pgo) +{ + int i,no,k,len, kk; + char *output; + + // for new xcin, there is no need to modify the lcch buffer + // instead, we put phrase to choose in mcch + no = pci->pageNo * pci->nChoicePerPage; + len = 0; + + for (i = 0;i < pci->nChoicePerPage; no++,i++) { + + // in the last page, no will exceed nTotalChoice + if( no >= pci->nTotalChoice ) + break; + output = (char *) calloc( + strlen(pci->totalChoiceStr[no]) * chewing_codeset + 1, + sizeof(char)); + preconvert( + pci->totalChoiceStr[no], output, + strlen(pci->totalChoiceStr[no])); + // for each char in the phrase, copy to mcch + for (k = 0, kk = 0; output[k] != '\0'; k += chewing_codeset, kk++) { + memcpy(inpinfo->mcch[len++].s, &(output[k]), chewing_codeset) ; + } + free(output); + // set grouping to the length of the phrase + inpinfo->mcch_grouping[i+1] = kk; + } + // i stores how many choices are available + inpinfo->mcch_grouping[0] = i; + + // set pgstate according to pci->pageNo & pci->nPage + if( pci->nPage == 1) { + inpinfo->mcch_pgstate = MCCH_ONEPG; + } + else { + if( pci->pageNo == 0 ) + inpinfo->mcch_pgstate = MCCH_BEGIN; + else if( pci->pageNo == pci->nPage - 1) + inpinfo->mcch_pgstate = MCCH_END; + else + inpinfo->mcch_pgstate = MCCH_MIDDLE; + } + + inpinfo->n_mcch = len ; +} + +void ShowText(inpinfo_t *inpinfo, ChewingOutput *pgo) +{ + int i; + memset(inpinfo->lcch, 0, sizeof(wch_t)*MAX_PHONE_SEQ_LEN) ; + for (i = 0; i < pgo->chiSymbolBufLen; i++) + pgo->chiSymbolBuf[i].wch = convert(pgo->chiSymbolBuf[i].wch); + memcpy(inpinfo->lcch, pgo->chiSymbolBuf, sizeof(wch_t) * pgo->chiSymbolBufLen) ; + inpinfo->n_lcch = pgo->chiSymbolBufLen ; +} + +void ShowInterval(inpinfo_t *inpinfo, ChewingOutput *pgo) +{ + int i, k, begin, len, count, nGroup ; + int label[MAX_PHONE_SEQ_LEN] ; + + if( pgo->chiSymbolBufLen == 0) { + inpinfo->lcch_grouping[0] = 0 ; + return ; + } + + // set label + for(count=0; countchiSymbolBufLen; count++) + label[count] = count ; + + for(i=0; inDispInterval; i++) { + len = pgo->dispInterval[i].to - pgo->dispInterval[i].from ; + + if( len > 1) { + for(k=pgo->dispInterval[i].from; kdispInterval[i].to; k++) + label[k] = count ; + count++ ; + } + } + + // begin to set lcch_grouping by the label + nGroup = 0 ; + begin = 0 ; + for(i=1; ichiSymbolBufLen; i++) { + if( label[i] != label[begin] ) { + inpinfo->lcch_grouping[++nGroup] = ( i - begin ) ; + begin = i ; + } + } + inpinfo->lcch_grouping[++nGroup] = ( i - begin ) ; + inpinfo->lcch_grouping[0] = nGroup ; +} + +void ShowStateAndZuin(inpinfo_t *inpinfo, ChewingOutput *pgo) +{ + int i, a , len = 0; + memset( inpinfo->s_keystroke, 0, sizeof(wch_t)*(3 + MAX_PHRASE_LEN)) ; + if(pgo->bShowMsg) { + for(i = 0; i < pgo->showMsgLen; i++) + pgo->showMsg[i].wch = convert(pgo->showMsg[i].wch); + memcpy( inpinfo->s_keystroke, pgo->showMsg, sizeof(wch_t)*pgo->showMsgLen) ; + inpinfo->keystroke_len = pgo->showMsgLen ; + } + else { + /* if(pgo->bChiSym) + strcpy( (char *)inpinfo->s_keystroke[0].s, "¤¤") ; + else + strcpy( (char *)inpinfo->s_keystroke[0].s, "­^") ; + + inpinfo->s_keystroke[1].s[0] = ' ' ; + for(i=0,a=2; izuinBuf[i].s[0] != '\0') { + inpinfo->s_keystroke[a++].wch = convert( + pgo->zuinBuf[i].wch) ; + ++ len; + } + inpinfo->keystroke_len = len; + } +} + +void SetCursor(inpinfo_t *inpinfo, ChewingOutput *pgo) +{ + inpinfo->edit_pos = pgo->chiSymbolCursor; +} + +int MakeInpinfo(inpinfo_t *inpinfo, ChewingOutput *pgo) +{ + int rtnValue = 0 ; + + if(pgo->keystrokeRtn & KEYSTROKE_ABSORB) + rtnValue |= IMKEY_ABSORB; + if(pgo->keystrokeRtn & KEYSTROKE_IGNORE) + rtnValue |= IMKEY_IGNORE; + if(pgo->keystrokeRtn & KEYSTROKE_BELL) + rtnValue |= IMKEY_BELL; + if(pgo->keystrokeRtn & KEYSTROKE_COMMIT) { + rtnValue |= IMKEY_COMMIT; + CommitString(inpinfo, pgo); + } + + if(pgo->pci->nPage != 0) { // in selection mode + ShowChoose(inpinfo,pgo->pci,pgo); + inpinfo->guimode &= ~GUIMOD_LISTCHAR; + } + else { // not in selection mode + ShowText(inpinfo, pgo); + ShowInterval(inpinfo, pgo); + inpinfo->guimode |= GUIMOD_LISTCHAR; + } + ShowStateAndZuin(inpinfo, pgo); + SetCursor(inpinfo, pgo); + return rtnValue; +} + +static unsigned int +ChewingKeystroke(void *conf, inpinfo_t *inpinfo, keyinfo_t *keyinfo) +{ + KeySym keysym = keyinfo->keysym; + ChewingOutput gOut ; + int rtn ; + static KeySym last_key = 0; + + // set Chinese / English mode by keystate + if( keyinfo->keystate & CAPS_MASK ) { // uppercase + SetChiEngMode( inpinfo->iccf, SYMBOL_MODE); + } + else { // lower case + SetChiEngMode( inpinfo->iccf, CHINESE_MODE); + } + + + // check no ctrl key was pressed + if(keyinfo->keystate >= 0 && !(keyinfo->keystate & CTRL_MASK ) && !(keyinfo->keystate & ShiftMask) ) { + switch(keysym) { + case XK_Escape: + OnKeyEsc(inpinfo->iccf, &gOut) ; + inpinfo->n_mcch = 0; + break ; + case XK_Return: + OnKeyEnter(inpinfo->iccf, &gOut) ; + inpinfo->n_mcch = 0; + break ; + case XK_Delete: + OnKeyDel(inpinfo->iccf, &gOut) ; + break ; + case XK_BackSpace: + OnKeyBackspace(inpinfo->iccf, &gOut) ; + break ; + case XK_Up: + OnKeyUp(inpinfo->iccf, &gOut); + break ; + case XK_Down: + OnKeyDown(inpinfo->iccf, &gOut) ; + break ; + case XK_Left: + OnKeyLeft(inpinfo->iccf, &gOut) ; + break ; + case XK_Right: + OnKeyRight(inpinfo->iccf, &gOut) ; + break ; + case XK_Home: + OnKeyHome(inpinfo->iccf, &gOut); + break; + case XK_End: + OnKeyEnd(inpinfo->iccf, &gOut); + break; + + case XK_Tab: + if (last_key == XK_Tab) // double click TAB + OnKeyDblTab(inpinfo->iccf, &gOut); + else + OnKeyTab(inpinfo->iccf, &gOut); + break; + case XK_Caps_Lock: + OnKeyCapslock(inpinfo->iccf, &gOut); + break; + case ' ': /* Space */ + OnKeySpace(inpinfo->iccf, &gOut); + break; + default: + OnKeyDefault(inpinfo->iccf, keysym, &gOut); + inpinfo->n_mcch = 0; + break; + } + } + else if (keyinfo->keystate & ShiftMask) { + switch ( keysym ) { + case XK_Left: + OnKeyShiftLeft(inpinfo->iccf, &gOut) ; + break ; + case XK_Right: + OnKeyShiftRight(inpinfo->iccf, &gOut) ; + break; + default: + OnKeyDefault(inpinfo->iccf, keysym, &gOut); + inpinfo->n_mcch = 0; + } + } + else if (keyinfo->keystate & CTRL_MASK) { // Ctrl-key Mask + // We need to fill the 'gOut' variable for output. + if (keysym <= '9' && keysym >= '0') + OnKeyCtrlNum(inpinfo->iccf,keysym,&gOut); + else + OnKeyCtrlOption(inpinfo->iccf, keysym - 'a' + 1, &gOut); + } + + + last_key = keysym; + rtn = MakeInpinfo(inpinfo, &gOut); + return rtn ; +} + +static int +ChewingShowKeystroke(void *conf, simdinfo_t *simdinfo) +{ + simdinfo->s_keystroke = NULL; + return False; +} + +/* UTF-8 support */ +void +preconvert(char *input, char *output, int n_char) +{ + if (chewing_codeset == XCIN_BYTE_UTF8) { + const char *inptr = input; + size_t inbytesleft = n_char; + size_t outbytesleft = n_char / 2 * 3 + 1; + + char *outptr = output; + iconv_t cd; + + cd = iconv_open("UTF-8", "BIG-5"); + iconv (cd, (char **)&inptr, &inbytesleft, &outptr, &outbytesleft); + + iconv_close(cd); + } else + strncpy(output, input, n_char); +} + +wchar_t +convert(wchar_t input) +{ + wch_t output; + wch_t temp; + + temp.wch = input; + if (chewing_codeset == XCIN_BYTE_UTF8) { + const char *inptr = temp.s; + size_t inbytesleft = 2; + size_t outbytesleft = 3; + char *outptr = output.s; + iconv_t cd; + cd = iconv_open("UTF-8", "BIG-5"); + iconv (cd, (char **)&inptr, &inbytesleft, &outptr, &outbytesleft); + iconv_close(cd); + output.s[3] = '\0'; + return output.wch; + } + + return input; +} + +static char zh_chewing_comments[] = + "Chewing : a smart phonetic input method module for XCIN.\n" + "By Lu-chuan Kung ,\n" + "Kang-pen Chen , and others.\n"; + +static char *zh_chewing_valid_objname[] = { "chewing", NULL }; + +module_t module_ptr = { + { + MTYPE_IM, + "zh_chewing", /* name */ + MODULE_VERSION, /* version */ + zh_chewing_comments + }, /* comments */ + zh_chewing_valid_objname, /* valid_objname */ + sizeof(ChewingConf), /* conf_size */ + ChewingInit, /* init */ + ChewingXimInit, /* xim_init */ + ChewingXimEnd, /* xim_end */ + ChewingKeystroke, /* keystroke */ + ChewingShowKeystroke, /* show_keystroke */ + NULL +}; +