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

521 lines
13 KiB
Plaintext
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
$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("·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; 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, "¤¤") ;
+ else
+ strcpy( (char *)inpinfo->s_keystroke[0].s, "­^") ;
+
+ 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
+};
+