/* * * UNICON - The Console Chinese & I18N * Copyright (c) 1999-2002 * * This file is part of UNICON, a console Chinese & I18N * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * See the file COPYING directory of this archive * Author: see CREDITS */ #include #include #include #include #include #include #include #include #include #define error printf static void UnloadInputMethod (hz_input_table *p); static void ResetInput (HzInputTable_T *pClient); static int LoadInputMethod(HzInputTable_T *pClient,char *filename); static void LoadPhrase (HzInputTable_T *pClient, int phrno, char *tt); static void FindMatchKey (HzInputTable_T *pClient); static void FillMatchChars (HzInputTable_T *pClient, int j); /*************************************************************************** * variable defines * ***************************************************************************/ /* 6 bit a key mask */ unsigned long mask[]= { 0x00000000, 0xFC000000, 0xFFF00000, 0xFFFFC000, 0xFFFFFF00, 0xFFFFFF00, 0xFFFFFF00, 0xFFFFFF00, 0xFFFFFF00, 0xFFFFFF00, 0xFFFFFF00, 0xFFFFFF00, 0xFFFFFF00, 0xFFFFFF00, 0xFFFFFF00, 0xFFFFFF00, 0xFFFFFF00, 0xFFFFFF00 }; unsigned long mask2[]= { 0x03FFFFFF, 0xFC0FFFFF, 0xFFF03FFF, 0xFFFFC0FF, 0xFFFFFFFF }; /*************************************************************************** * public function * ***************************************************************************/ static void Key2Str(HzInputTable_T *pClient,u_long key, char *str) { int i; unsigned long ik; for (i=0;i<4;i++) { if((ik = key >> (26-i*6) & 0x3F) != 0) str[i]=pClient->cur_table->KeyName[ik]; else str[i]='\0'; } } static int LoadInputMethod(HzInputTable_T *pClient, char *filename) { int nread; FILE *fd; char phrase_filename[100]; hz_input_table *table; char *pht; int *phi; table = malloc(sizeof(hz_input_table)); if (table == NULL) { error("Out of memory in LoadInputMethod"); return 1; } fd = fopen(filename, "r"); if (fd == NULL) { error("Cannot open input method %s", filename); fclose(fd); free(table); return 1; } nread = fread(table, sizeof(hz_input_table),1,fd); if (nread != 1) { error("Cannot read file header %s", filename); fclose( fd ); free(table); return 1; } if( strcmp(MAGIC_NUMBER, table->magic_number) ) { printf("is not a valid tab file\n\n"); fclose( fd ); free(table); return 1; } table->item = (ITEM *)malloc(sizeof(ITEM ) * table->TotalChar); //warn("Totalchar=%d\n",table->TotalChar); if ( table->item == NULL ) { error("Gosh, cannot malloc enough memory"); fclose( fd ); free(table); return 1; } if (fread(table->item, sizeof(ITEM) , table->TotalChar,fd )!= table->TotalChar) { error("Cannot read file %s", filename);; fclose( fd ); free(table->item); free(table); return 1; } fclose( fd ); /*Load phrase tabel*/ strcpy( phrase_filename, filename ); strcat( phrase_filename, ".phr" ); fd = fopen( phrase_filename, "r" ); if (fd == NULL ) { printf("Load Phrase File error!\n"); fclose( fd ); free(table->item); free(table); return 1; } fread(&nread,sizeof(int),1,fd); if (nread != table->PhraseNum) { printf("Not a valid phrase file:%s\n", phrase_filename); fclose( fd ); free(table->item); free(table); return 1; } if ((phi=(int *)malloc(sizeof(int)*nread))==NULL) { printf("Not enough memory\n"); fclose( fd ); free(table->item); free(table); return 1; } if (nread!=fread(phi,sizeof(int),nread,fd)) { printf("Bad phrase file: %s\n",phrase_filename); fclose( fd ); free(phi); free(table->item); free(table); return 1; } nread=phi[nread-1]; if ((pht=(char *)malloc(nread))==NULL) { printf("Not enough memory\n"); fclose( fd ); free(phi); free(table->item); free(table); return 1; } if (nread!=fread(pht,sizeof(char),nread,fd)) { printf("Bad phrase file: %s\n",phrase_filename); fclose( fd ); free(pht); free(phi); free(table->item); free(table); return 1; } table->Phrasetable=pht; table->Phraseindex=phi; pClient->cur_table=table; fclose( fd ); return 0; } static void ResetInput (HzInputTable_T *pClient) { bzero (pClient->InpKey, sizeof(pClient->InpKey) ); bzero (pClient->seltab, sizeof(pClient->seltab) ); bzero (pClient->seltabkey, sizeof(pClient->seltabkey)); bzero (pClient->save_InpKey, sizeof(pClient->save_InpKey)); bzero (pClient->LXchar, sizeof(pClient->LXchar)); bzero (pClient->PassedPage, sizeof(pClient->PassedPage)); bzero (pClient->CharIndex, sizeof(pClient->CharIndex)); pClient->val1=pClient->key1=0; pClient->Qmask=0xFFFFFFFF; pClient->CurSelNum = 0, pClient->InputCount = 0, pClient->InputMatch = 0; pClient->PageNum = 0; pClient->MultiPageMode = 0; pClient->NextPageIndex = 0, pClient->CurrentPageIndex = 0; pClient->StartKey = 0; pClient->EndKey = 0; pClient->save_StartKey=0; pClient->save_EndKey=0; pClient->save_MultiPageMode=0; pClient->save_NextPageIndex=0; pClient->save_CurrentPageIndex=0; pClient->QMode=0; pClient->LXon=0; } /* phrno: Phrase Number, return in tt */ static void LoadPhrase (HzInputTable_T *pClient, int phrno, char *tt ) { char *pht = pClient->cur_table->Phrasetable; int *phi = pClient->cur_table->Phraseindex; int ofs, len; ofs=phi[phrno]; len = phi[phrno+1] - ofs; if ( len > 128 || len <= 0 ) { error( "phrase error %d,%d\n" , len ,phrno); strcpy( tt, "error" ); return; } memcpy( tt, pht+ofs, len); tt[len] = 0; } /* After add/delete a char, search the matched char/phrase, update the pClient->StartKey/pClient->EndKey key, save the related keys at first, if no match is found, we may restore its original value */ static void FindMatchKey (HzInputTable_T *pClient) { int i,zps; pClient->save_StartKey = pClient->StartKey; pClient->save_EndKey = pClient->EndKey; pClient->save_MultiPageMode = pClient->MultiPageMode; pClient->save_NextPageIndex = pClient->NextPageIndex; pClient->save_CurrentPageIndex = pClient->CurrentPageIndex; pClient->val1 = ((pClient->InpKey[3]&0x3F)<<8 ) | ((pClient->InpKey[2]&0x3F)<<14) | ((pClient->InpKey[1]&0x3F)<<20) | ((pClient->InpKey[0]&0x3F)<<26); if (pClient->QMode) { pClient->Qmask=0xFFFFFFFF; for (i=3;i>=0;i--) if (pClient->InpKey[i]&& pClient->InpKey[i]==pClient->cur_table->KeyMap['z']) { zps=i; pClient->Qmask &= mask2[zps]; } pClient->val1 &= pClient->Qmask; } if (pClient->InputCount == 1) { if (pClient->QMode && zps==0) pClient->StartKey = pClient->cur_table->KeyIndex[0]; else pClient->StartKey = pClient->cur_table->KeyIndex[pClient->InpKey[0]]; } else pClient->StartKey = pClient->CharIndex[pClient->InputCount-1]; if (pClient->QMode && zps==0) pClient->EndKey = pClient->cur_table->KeyIndex[pClient->cur_table->TotalKey]; else pClient->EndKey = pClient->cur_table->KeyIndex[pClient->InpKey[0]+1]; for (; pClient->StartKey < pClient->EndKey; pClient->StartKey++) { pClient->key1 = (pClient->cur_table->item[pClient->StartKey].key & mask[pClient->InputCount]); if (pClient->key1 > pClient->val1) break; if (pClient->key1 < pClient->val1) continue; break; } pClient->CharIndex[pClient->InputCount] = pClient->StartKey; } /* Find the matched chars/phrases and fill it into SelTab The starting checked index is j The Selection Line 1xxx 2xxx, 80-20=60 60/2=30 chinese chars only 0-9 Selection can contain only 30 chinese chars SelectionXMax-SelectionX-20 #define SelectionXMax 78 #define MAX_SEL_LENGTH (SelectionXMax-SelectionX-18) */ static void FillMatchChars (HzInputTable_T *pClient, int j) { int SelNum = 0, CurLen = 0; unsigned long qmask=0xFFFFFFFF; char phbuf[MAX_PHRASE_LENGTH]; char *lxch; if (pClient->QMode) qmask=pClient->Qmask; if (pClient->LXon) { lxch=pClient->LXchar; pClient->val1=0; qmask=0; while (SelNum < pClient->cur_table->MaxDupSel && j < pClient->EndKey && (CurLen+2*SelNum+1) < pClient->MaxSelectLen && pClient->InputCount < 5) { if(pClient->cur_table->item[j].phindex==0xFFFF) { j++; continue; } LoadPhrase (pClient, pClient->cur_table->item[j].phindex, phbuf); if (!strncmp(phbuf,lxch,strlen(lxch))&&strlen(lxch)seltab[SelNum],phbuf); SelNum++; CurLen += strlen(pClient->seltab[SelNum]); } j++; } } else { while (SelNum < pClient->cur_table->MaxDupSel && j < pClient->EndKey && (CurLen+2*SelNum+1) < pClient->MaxSelectLen && pClient->InputCount < 5) { if ((pClient->cur_table->item[j].key & mask[pClient->InputCount] & qmask) != pClient->val1) { j++; continue; } if (pClient->cur_table->item[j].phindex != 0xFFFF) LoadPhrase (pClient, pClient->cur_table->item[j].phindex, pClient->seltab[SelNum]); else { memcpy (&pClient->seltab[SelNum], &(pClient->cur_table->item[j].ch), 2); pClient->seltab[SelNum][2] = '\0'; } CurLen += strlen(pClient->seltab[SelNum]); if ((pClient->HTMode || pClient->QMode) && !pClient->LXon && strlen(pClient->seltab[SelNum]) < 14) { Key2Str(pClient,pClient->cur_table->item[j].key & mask[4], pClient->seltabkey[SelNum]); CurLen += strlen(pClient->seltabkey[SelNum]); } else pClient->seltabkey[SelNum][0]='\0'; SelNum++; j++; } } if ((CurLen+2*SelNum+1) >= pClient->MaxSelectLen){ SelNum--; j--; } if (SelNum == 0) /* some match found */ { pClient->StartKey = pClient->save_StartKey; pClient->EndKey = pClient->save_EndKey; pClient->MultiPageMode = pClient->save_MultiPageMode; pClient->NextPageIndex = pClient->save_NextPageIndex; pClient->CurrentPageIndex = pClient->save_CurrentPageIndex; if (pClient->LXon) ResetInput (pClient); return; /* keep the original selection */ } pClient->CurSelNum = SelNum; for(SelNum = pClient->CurSelNum; SelNum < 16; SelNum++) pClient->seltab[SelNum][0] = '\0'; /* zero out the unused area */ pClient->InputMatch = pClient->InputCount; /* until now we have some matches */ /* check if more than one page */ while ((pClient->QMode && (pClient->cur_table->item[j].key & mask[pClient->InputCount] & qmask) != pClient->val1)&&j < pClient->EndKey) j++; while (pClient->LXon && j < pClient->EndKey) { if (pClient->cur_table->item[j].phindex==0xFFFF) { j++; continue; } LoadPhrase (pClient, pClient->cur_table->item[j].phindex, phbuf); if (!strncmp(phbuf,lxch,strlen(lxch))) break; j++; } if (j < pClient->EndKey && (pClient->cur_table->item[j].key & mask[pClient->InputCount] & qmask) == pClient->val1 && (CurLen+pClient->CurSelNum*2+3 >= pClient->MaxSelectLen || pClient->CurSelNum == pClient->cur_table->MaxDupSel)) { /* has another matched key, so enter pClient->MultiPageMode, has more pages */ pClient->NextPageIndex = j; pClient->MultiPageMode = 1; } else if (pClient->MultiPageMode) { // pClient->NextPageIndex = pClient->StartKey; /* rotate selection */ pClient->NextPageIndex = 0; /* rotate selection */ } else pClient->MultiPageMode = 0; } void Simulate_putstr (char *p, HzInputTable_T *pClient) { if (pClient->InputCount <= pClient->InputMatch) /* All Match */ { if (pClient->LXMode&&pClient->InputCount) { unsigned long stky=pClient->InpKey[0]; ResetInput (pClient); pClient->StartKey=pClient->cur_table->KeyIndex[stky]; pClient->EndKey=pClient->cur_table->KeyIndex[stky+1]; pClient->LXon=1; strcpy(pClient->LXchar,p); pClient->CurrentPageIndex = pClient->StartKey; FillMatchChars (pClient, pClient->StartKey); } else ResetInput (pClient); } else { int nCount = pClient->InputCount - pClient->InputMatch, nMatch = pClient->InputMatch,i; pClient->MultiPageMode = pClient->NextPageIndex = pClient->CurrentPageIndex = 0; pClient->InputCount = pClient->InputMatch = 0; pClient->QMode=0; pClient->LXon=0; for(i = 0; i < nCount; i++) pClient->save_InpKey[i] = pClient->InpKey[nMatch+i]; bzero(pClient->InpKey, sizeof(pClient->InpKey)); for(i = 1; i <= nCount; i++) /* feed the additional keys */ { if (pClient->save_InpKey[pClient->InputCount] == pClient->cur_table->KeyMap['z']) pClient->QMode=1; pClient->InpKey[pClient->InputCount] = pClient->save_InpKey[pClient->InputCount++]; if (pClient->InputCount <= pClient->InputMatch+1) { FindMatchKey (pClient); pClient->MultiPageMode = 0; pClient->CurrentPageIndex = pClient->StartKey; FillMatchChars (pClient, pClient->StartKey); } } if (pClient->InputMatch == 0) /* left key has no match, delete */ { ResetInput (pClient); } } return; } int CCE_KeyFilter (HzInputTable_T *pClient, u_char key, char *buf, int *len) { int inkey = 0,vv; char *is_sel_key = (char*)0; char buftmp[MAX_PHRASE_LENGTH]; // long b = 0; switch ( key ) { case '\010': /* BackSpace Ctrl+H */ case '\177': /* BackSpace */ if ( pClient->InputCount > 0 ) { if (pClient->InpKey[pClient->InputCount-1]== pClient->cur_table->KeyMap['z']) pClient->QMode=0; pClient->InpKey[--pClient->InputCount]=0; if (pClient->InputCount == 0) { ResetInput (pClient); } else if (pClient->InputCount < pClient->InputMatch) { FindMatchKey (pClient); pClient->MultiPageMode = 0; pClient->CurrentPageIndex = pClient->StartKey; FillMatchChars (pClient, pClient->StartKey); } return 1; } else { ResetInput (pClient); return 0; } break; case '\033': /* ESCAPE */ /* case 0x09: */ /* tab key */ if ( pClient->LXon || pClient->InputCount > 0 ) { ResetInput (pClient); return 1; } else return 0; break; case ',': case '[': case '<': case '-': if ( (pClient->LXon && key == ',') || !pClient->MultiPageMode ) { ResetInput(pClient); return 0; } else { if ( pClient->CurrentPageIndex > pClient->StartKey) { if (pClient->LXon) pClient->CurrentPageIndex = pClient->PassedPage[--pClient->PageNum]; else pClient->CurrentPageIndex = pClient->CurrentPageIndex - pClient->cur_table->MaxDupSel; } else pClient->CurrentPageIndex = pClient->StartKey; FillMatchChars (pClient, pClient->CurrentPageIndex); return 1; } break; case '.': case '>': case ']': case '=': if ( pClient->LXon && key == '.' ) { ResetInput(pClient); return 0; } if ( pClient->MultiPageMode && pClient->NextPageIndex !=0) { if (pClient->LXon) pClient->PassedPage[pClient->PageNum++]= pClient->CurrentPageIndex; pClient->CurrentPageIndex = pClient->NextPageIndex; FillMatchChars (pClient, pClient->CurrentPageIndex); return 1; } else { ResetInput(pClient); return 0; } break; case ' ': if ( pClient->CurSelNum == 0 ) return 0; if ( pClient->seltab[0][0] ) { strcpy (buftmp, pClient->seltab[0]); if (pClient->LXon) { int ofs=strlen(pClient->LXchar); strcpy(buf,buftmp+ofs); } else strcpy(buf,buftmp); *len = strlen (buftmp); Simulate_putstr (buftmp, pClient); return 2; } break; default: inkey = pClient->cur_table->KeyMap[key]; is_sel_key = strchr( pClient->cur_table->selkey, key); vv = is_sel_key - pClient->cur_table->selkey; /* selkey index, strchr may return NULL */ /* if a key is simultaneously inkey & is_sel_key, then selkey first?*/ if (!is_sel_key && pClient->LXon) { pClient->LXon=0; } if ( (!inkey && !is_sel_key) || (!inkey && is_sel_key && (pClient->CurSelNum == 0 || pClient->seltab[vv][0] == 0)) ) { ResetInput (pClient); return 0; } if (is_sel_key && pClient->CurSelNum > 0 && pClient->seltab[vv][0]) { strcpy (buftmp, pClient->seltab[vv]); if (pClient->LXon) { int ofs=strlen(pClient->LXchar); strcpy(buf,buftmp+ofs); } else strcpy(buf,buftmp); *len = strlen (buftmp); Simulate_putstr (buftmp, pClient); return 2; } /* now it must be inkey? */ if (inkey == pClient->cur_table->KeyMap['z']) pClient->QMode=1; if ( inkey >= 1 && pClient->InputCount < MAX_INPUT_LENGTH ) pClient->InpKey[pClient->InputCount++] = inkey; if (pClient->InputCount <= pClient->InputMatch+1) { FindMatchKey (pClient); pClient->CurrentPageIndex = pClient->StartKey; pClient->MultiPageMode = 0; FillMatchChars(pClient, pClient->StartKey); if (pClient->cur_table->last_full && (pClient->InputCount > pClient->cur_table->MaxPress || (pClient->InputCount == pClient->cur_table->MaxPress && pClient->CurSelNum == 1))) { // left only one selection strcpy (buf, pClient->seltab[0]); *len = strlen (buf); Simulate_putstr (buf, pClient); return 2; } // printf ("key::%c::0x%x\n", key, key); return 1; } return 1; } /* switch */ return 0; } char *szGetSelItem (HzInputTable_T *pClient, int vv) { if (pClient->CurSelNum > 0 && pClient->seltab[vv][0]) return pClient->seltab[vv]; return NULL; } /************************************************************************* * public function * *************************************************************************/ int CCE_InputInit (HzInputTable_T *p, char* szName) { if (p == NULL) return 1; memset (p, 0, sizeof (HzInputTable_T)); p->MaxSelectLen = 70; p->MAX_SEL_LENGTH = p->MaxSelectLen - 8; p->QMode=0; p->LXMode=1; p->LXon=0; p->HTMode=1; if (!LoadInputMethod (p,szName)) return 1; return 0; } void CCE_Flush (HzInputTable_T *p) { ResetInput(p); } static void InputCleanup (hz_input_table *p) { UnloadInputMethod (p); // UnloadSysPhrase (); // UnloadUserPhrase (); } static void UnloadInputMethod (hz_input_table *p) { if (p == NULL) return; free (p->Phrasetable); free (p->Phraseindex); free (p->item); free (p); } void CCE_UnloadMethod (hz_input_table *p) { InputCleanup (p); } int CCE_ConfigureInputArea (HzInputTable_T *p, int MaxSelectLen) { p->MaxSelectLen = MaxSelectLen; p->MAX_SEL_LENGTH = p->MaxSelectLen - 8; return 1; } int CCE_GetInputDisplay (HzInputTable_T * p, char *buf) { int i, len = p->InputCount; char c; char *q = buf; if (p->LXon) { strcpy(q,"ÁªÏëģʽ"); q[8] = '\0'; return 1; } if (p->InputCount == 0) return 0; for( i = 0; i <= len ; i++) { if (i < p->InputCount) c = p->cur_table->KeyName[p->InpKey[i]]; else c= ' '; if (i == p->InputMatch && p->InputCount > p->InputMatch && i != 0) *q++ = '-'; *q++ = c; } *q = '\0'; return 1; } int CCE_GetSelectDisplay (HzInputTable_T * p, char *buf) { int i, pos = 0, len; char buf1[256]; buf[0] = '\0'; if (p->CurSelNum == 0) return 0; /* not first page */ if (p->MultiPageMode && p->CurrentPageIndex != p->StartKey) strcat (buf, "< "); for (i = 0; i < p->CurSelNum; i++) { if (!p->seltab[i][0]) { if (i == 0) continue; else break; } if (i != 9) sprintf (buf1, "%d%s", i + 1, p->seltab[i]); else sprintf (buf1, "0%s", p->seltab[i]); if ((p->HTMode||p->QMode) && !p->LXon) sprintf (buf1, "%s%s ", buf1, p->seltabkey[i]); else sprintf (buf1, "%s ", buf1); len = strlen(buf1); if (pos+len+1 >= p->MaxSelectLen) { break; } strcat (buf, buf1); pos += len; } /* not last page */ if (p->MultiPageMode && p->NextPageIndex != 0) strcat (buf, "> "); return i; }