2013-09-26 17:14:40 +02:00

521 lines
13 KiB
Plaintext
Raw Blame History

$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 <chewing/chewing.h>
+#include <string.h>
+
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+#include "xcintool.h"
+#include "module.h"
+
+#include <iconv.h>
+#include <langinfo.h>
+
+/* 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("<22>s<EFBFBD>ŭ<EFBFBD>", 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; count<pgo->chiSymbolBufLen; count++)
+ label[count] = count ;
+
+ for(i=0; i<pgo->nDispInterval; i++) {
+ len = pgo->dispInterval[i].to - pgo->dispInterval[i].from ;
+
+ if( len > 1) {
+ for(k=pgo->dispInterval[i].from; k<pgo->dispInterval[i].to; k++)
+ label[k] = count ;
+ count++ ;
+ }
+ }
+
+ // begin to set lcch_grouping by the label
+ nGroup = 0 ;
+ begin = 0 ;
+ for(i=1; i<pgo->chiSymbolBufLen; 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, "<22><>") ;
+ else
+ strcpy( (char *)inpinfo->s_keystroke[0].s, "<22>^") ;
+
+ inpinfo->s_keystroke[1].s[0] = ' ' ;
+ for(i=0,a=2; i<ZUIN_SIZE; i++) */
+ for(i=0,a=0; i<ZUIN_SIZE; i++)
+ if(pgo->zuinBuf[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 <lckung@iis.sinica.edu.tw>,\n"
+ "Kang-pen Chen <kpchen@iis.sinica.edu.tw>, 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
+};
+