/* vi: set sw=4 ts=4: */ /* * CCE - Console Chinese Environment - * Copyright (C) 1998-2003 Rui He (rhe@3eti.com) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include #include "defs.h" #include "vc.h" #include "vga.h" #include "hzinput.h" #include "pinyin.h" #include "zhuyin.h" #include "term.h" #include "font.h" #include "getcap.h" #include "errors.h" #include "encfilter.h" int IsHanziInput; /* 0 for ascii, 1 for hanzi input */ int IsFullChar; /* 0 for half char, 1 for full char */ int IsChinesePunct; /* 0 for english punctuation, 1 for Chinese punct */ int current_method = -1; /* no one yet */ hz_input_table *input_table[NR_INPUTMETHOD],*cur_table = NULL; int IsAssocEnable = 1; int IsAssociateMode; /* currently it's in AssociateMode */ int ZhiyinKeyboardMode; int ZhuyinKeyboardMode; int ConfigInputMethod(const char *str) { char *p, *lx, *lxend; int i = 0, defmethod; p = strtok((char *)str, "\n"); while(p && i < NR_INPUTMETHOD) { p = skip_space(p); defmethod = 0; if (*p && *p != '#') /* comment line doesn't occupy one input slot */ { if (strncasecmp(p, EMPTY_SLOT_STRING, sizeof(EMPTY_SLOT_STRING)-1)) /* not beginning with "EMPTY" */ { if (*p == '*') /* indicate it's the default input method */ { p++; defmethod = 1; } lx = to_space(p); if (*lx && *lx != '#') *lx++ = '\0'; /* terminate the input method filename and advance lx */ else lx = NULL; input_table[i] = LoadInputMethod(p); message("Loading input method %d %s: %s",i,p, input_table[i] ? "Succeeded.\n" : "Failed!\n"); if (input_table[i] && (defmethod || current_method == -1)) current_method = i; if (input_table[i] && lx) { lx = skip_space(lx); lxend = to_space(lx); /* go to next space */ *lxend = '\0'; /* terminated it */ if (*lx && *lx != '#') LoadAssociateFile(input_table[i], lx); } } i++; /* even if we can't load it, it'll occupy one slot */ } p = strtok((char *)NULL, "\n"); } if (current_method >= 0) cur_table = input_table[current_method]; return SUCCESS; } static int ConfigFuzzyPinyin(const char *confstr) { bool value = BoolConf(confstr); EnableFuzzyPinyin = value; if (value) { message("zh/z-ch/c-sh/s fuzzy pinyin enabled.\r\n"); } return SUCCESS; } static int ConfigZhiyinKeyboard(const char *confstr) { ZhiyinKeyboardMode = atoi(confstr); if ( ZhiyinKeyboardMode < 0) ZhiyinKeyboardMode = 0; return SUCCESS; } static int ConfigZhuyinKeyboard(const char *confstr) { ZhuyinKeyboardMode = atoi(confstr); if ( ZhuyinKeyboardMode < 0) ZhuyinKeyboardMode = 0; return SUCCESS; } static int ConfigShuangPinMap(const char *confstr) { if (confstr) { u_char *p = strtok((char *)confstr, " #\t\r\n"); LoadShuangPinData(p); /* it's optional, so failure doesn't hurt */ } return SUCCESS; } void InputInit(void) { IsHanziInput = 0; /* default is ascii input */ IsFullChar = 0; DefineCap("FuzzyPinyin",ConfigFuzzyPinyin,"Off"); DefineCap("ZhiyinKeyboard", ConfigZhiyinKeyboard, "0"); DefineCap("CiyinKeyboard", ConfigZhuyinKeyboard, "0"); DefineCap("ShuangPinMap", ConfigShuangPinMap, ""); } void InputCleanup(void) { int i; IsHanziInput = 0; ResetInput(0,0); /* do we need this one? */ for (i = 0; i < NR_INPUTMETHOD; i++) { if (input_table[i]) UnloadInputMethod(i); } #ifdef CONVTABLE_USE_MMAP MunmapConvertTable(); /* clean up the conver table */ #endif } void InputSwitchEncoding(int encoding) { int i; if (encoding <= 0 || encoding >= CODE_NUM) return; /* invalid entry */ IsHanziInput = 0; ResetInput(0,0); for (i = 0; i < NR_INPUTMETHOD; i++) { if (!input_table[i]) continue; switch(input_table[i]->InputType) { case INPUT_TYPE_INTCODE: /* always use lInfo.sysCoding */ input_table[i]->encoding = encoding; strcpy(input_table[i]->cname, IntCode_CNameStr[encoding]); break; case INPUT_TYPE_TABLE: /* use its own encoding ? */ if (input_table[i]->encoding == CODE_GB && encoding == CODE_GBK) input_table[i]->encoding = CODE_GBK; break; case INPUT_TYPE_PINYIN: case INPUT_TYPE_ZHUYIN: /* always use lInfo.sysCoding */ input_table[i]->encoding = encoding; cur_table = input_table[i]; /* necessary for ChangeKeyboardMap */ strcpy(cur_table->cname, cur_table->InputType == INPUT_TYPE_PINYIN ? Pinyin_CNameStr[encoding] : Zhuyin_CNameStr[encoding]); cur_table->ChangeKeyboardMap(0); /* same one if possible */ break; } } } void ToggleHalfFull(void) { IsFullChar ^= 1; RefreshInputArea(FALSE); /* do not need to clear it */ } void ToggleAssociateMode() { IsAssocEnable ^= 1; if (IsAssociateMode) /* IsAssocEnable should be 1 now */ { ResetInput(1,1); } } void ToggleChinesePunct() { int i; IsChinesePunct ^= 1; RefreshInputArea(FALSE); /* do not need to clear it */ if (IsChinesePunct) { for(i = 0; Punct3Str[i].ch[0]; i++) Punct3Str[i].count = 0; /* output outmost one */ for(i = 0; Punct2Str[i].ch; i++) Punct2Str[i].index = 0; /* output first one */ } } void ToggleInputMethod(void) { if (!IsHanziInput) /* not HZinput now */ { IsChinesePunct = 1; /* force Chinese ,. */ SetCurrentInputMethod(current_method); } else { IsHanziInput = 0; IsChinesePunct = 0; /* force English ,. */ ResetInput(0,0); RefreshInputArea(TRUE); } } int SetCurrentInputMethod(int curMethod) { if (curMethod >= 0 && input_table[curMethod]) { if (!input_table[curMethod]->FontMapped) { if (MmapFont(input_table[curMethod]->encoding, NULL)) return -1; /* failed to map font */ input_table[curMethod]->FontMapped = 1; } if (input_table[curMethod]->item == NULL && MmapInputTable(input_table[curMethod])) return -1; /* failed to map it */ if (current_method != curMethod || !IsHanziInput) { ResetInput(0,0); switch(input_table[curMethod]->InputType) { case INPUT_TYPE_PINYIN: ResetPinyinInput((PinyinModule *)input_table[curMethod]->PrivateData); break; case INPUT_TYPE_ZHUYIN: ResetZhuyinInput((ZhuyinModule *)input_table[curMethod]->PrivateData); break; } } current_method = curMethod; cur_table = input_table[curMethod]; IsHanziInput = 1; RefreshInputArea(TRUE); return 0; } return -1; } void SwitchInputMethod(void) { int method = current_method; if (!IsHanziInput) /* just turn on */ { SetCurrentInputMethod(current_method); } else /* swith to next one */ { if (method < 0) method = -1; /* start from 0 */ do { method = (method+1) % 10; /*[0-8]9 -> [1-9]0 */ } while ( (!input_table[method] || SetCurrentInputMethod(method)) && method != current_method) ; } } void ChangePinyinZhuyinKeyboardMap(void) { if (IsHanziInput && cur_table && cur_table->ChangeKeyboardMap) { ResetInput(0, 0); /* clear associate candidates if it's available */ cur_table->ChangeKeyboardMap(1); } } void InputAreaOutput(int encoding, int x, u_char *string, int fg, int bg) { while (*string) { if (iskanji( encoding, string[0], string[1])) /* depends on lInfo.sysCoding */ { pVideoInfo->input_wput(encoding, x,*string,*(string+1),fg,bg); x += 2; string += 2; } else pVideoInfo->input_sput(x++,*string++,fg,bg); } } static void GetCurrentTime(char *buffer, int len) { static char *day[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; static char *month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; time_t curTime; struct tm *pTM; if (dispInfo.gxdim < 640) /* 800) */ { snprintf(buffer, len, "CCE Ver " VERSION); } else { time(&curTime); pTM = localtime(&curTime); #if 0 /* including seconds */ sprintf(buffer, "CCE Ver " VERSION " %s %s %d %02d:%02d:%02d", day[pTM->tm_wday], month[pTM->tm_mon], pTM->tm_mday, pTM->tm_hour, pTM->tm_min, pTM->tm_sec); #else snprintf(buffer, len, "CCE Ver " VERSION " %s %s %d %02d:%02d" /* :%02d" */, day[pTM->tm_wday], month[pTM->tm_mon], pTM->tm_mday, pTM->tm_hour, pTM->tm_min /*, pTM->tm_sec*/ ); #endif } } void RefreshInputArea(int ClearInput) { char buf[256], timebuf[55]; if (ClearInput) pVideoInfo->clear(CLEAR_INPUT, INPUT_BGCOLOR); /* 1 blue */ if (!IsHanziInput) { GetCurrentTime(timebuf, sizeof(timebuf)); #if defined(__QNX__) snprintf(buf, sizeof(buf), "[ENGNUM%s]%s", " ", CurCoding[lInfo.sysCoding]); /* 5 spaces */ #else snprintf(buf, sizeof(buf), EngNumStr[lInfo.sysCoding], " ", CurCoding[lInfo.sysCoding]); /* 5 spaces */ #endif InputAreaOutput(lInfo.sysCoding, 0, buf, INPUT_FGCOLOR,INPUT_BGCOLOR); pVideoInfo->input_draw_icon(7, HalfFullIcons[IsFullChar], 16, 16, INPUT_FGCOLOR, INPUT_BGCOLOR); /* half/full width */ pVideoInfo->input_draw_icon(9, ChEngPunctIcons[IsChinesePunct], 16, 16, INPUT_FGCOLOR, INPUT_BGCOLOR); /* chinese/eng punct */ InputAreaOutput(lInfo.sysCoding, (dispInfo.tx_avail-strlen(timebuf))/2+1, timebuf, INPUT_FGCOLOR, INPUT_BGCOLOR); #if defined(__QNX__) snprintf(buf, sizeof(buf), "[Term %d][Window %d]", VtNum, curCon ? curCon->window : 0); #else snprintf(buf, sizeof(buf), WindowStr[lInfo.sysCoding], VtNum, curCon ? curCon->window : 0); #endif InputAreaOutput(lInfo.sysCoding, dispInfo.tx_avail-WINDOW_TERMINAL_STR_WIDTH, buf, INPUT_FGCOLOR, INPUT_BGCOLOR); } else { int len; len = strlen(cur_table->cname); #if defined(__QNX__) snprintf(buf, sizeof(buf), " [%s%s] ", cur_table->cname, dispInfo.show_terminal ? " " : "" ); #else snprintf(buf, sizeof(buf), InpNameStr[cur_table->encoding], cur_table->cname, dispInfo.show_terminal ? " " : "" ); #endif InputAreaOutput(cur_table->encoding, 0, buf, INPUT_FGCOLOR,INPUT_BGCOLOR); if (dispInfo.show_terminal) { pVideoInfo->input_draw_icon(len+3, HalfFullIcons[IsFullChar], 16, 16, INPUT_FGCOLOR, INPUT_BGCOLOR); /* half/full width */ pVideoInfo->input_draw_icon(len+5, ChEngPunctIcons[IsChinesePunct], 16, 16, INPUT_FGCOLOR, INPUT_BGCOLOR); /* chinese/eng punct */ } #if 1 /* def SUPPORT_ASSOCIATE */ if (IsAssociateMode) { DisplayAssociateInput(); DisplaySelection(); /* Associate Input is using the table input's engine */ } else #endif if (cur_table->RefreshInput) (*cur_table->RefreshInput)(); else { DisplayInput(); DisplaySelection(); } if (dispInfo.show_terminal) { #if defined(__QNX__) snprintf(buf, sizeof(buf), "[Term %d][Window %d]", VtNum, curCon ? curCon->window : 0); #else snprintf(buf, sizeof(buf), WindowStr[cur_table->encoding],VtNum, curCon ? curCon->window :0); #endif InputAreaOutput(cur_table->encoding, dispInfo.tx_avail-WINDOW_TERMINAL_STR_WIDTH, buf, INPUT_FGCOLOR, INPUT_BGCOLOR); } } } void ClearSelectionArea(void) { int i, pos = cur_table->SelAreaX; for(i = pos; i < pos + cur_table->SelAreaWidth ; i++) pVideoInfo->input_sput(i,' ',INPUT_BGCOLOR,INPUT_BGCOLOR); } void ClearInputArea(void) { int i, pos = cur_table->InputAreaX; for(i = pos; i < pos + cur_table->InputAreaWidth ; i++) pVideoInfo->input_sput(i,' ',INPUT_BGCOLOR,INPUT_BGCOLOR); } void OutputCJKStr(int tty_fd, unsigned char *buf, int count) { #ifdef SUPPORT_ENCODING_FILTER if (UseEncodingFilter) { DoEncodingFilter(CONVERT_TO_FILTER, buf, count); /* ignore the unconvertible bytes */ if (EncodingFilterLen > 0) write(tty_fd, EncodingFilterBuff, EncodingFilterLen); } else #endif write(tty_fd, buf, count); } void OutputEngChar(int tty_fd, unsigned char c) { int key; char *p = NULL; int i, index; #ifdef DEBUG fprintf(stderr, "Now in hzinput.c's OutputEngChar, tty_fd=%d, c=0x%x IsFullChar=%d\n", tty_fd, c, IsFullChar); #endif if (IsChinesePunct) { for(i = 0; Punct3Str[i].ch[0]; i++) { if (c == Punct3Str[i].ch[0]) index = 0; /* '<' => << < */ else if (c == Punct3Str[i].ch[1]) index = 1; /* '>' => >> > */ else continue; p = Punct3Str[i].punct[index][Punct3Str[i].count > 0 ][lInfo.sysCoding]; if (p) /* not NULL */ { OutputCJKStr(tty_fd, p, strlen(p)); if (index == 1 && Punct3Str[i].count > 0) Punct3Str[i].count--; else if (index == 0 && Punct3Str[i].count < 255) Punct3Str[i].count++; return; } } for(i = 0; Punct2Str[i].ch; i++) if (c == Punct2Str[i].ch) { p = Punct2Str[i].punct[ Punct2Str[i].index ][ lInfo.sysCoding ]; if (p) /* not NULL */ { OutputCJKStr(tty_fd, p, strlen(p)); Punct2Str[i].index ^= 1; /* alternate */ return; } } for(i = 0; Punct1Str[i].ch; i++) if (c == Punct1Str[i].ch) { p = Punct1Str[i].punct[ lInfo.sysCoding ]; if (p) { OutputCJKStr(tty_fd, p, strlen(p)); return; } } } if (IsFullChar && FullCharMap[lInfo.sysCoding] /* Mapping not NULL */ && c >= ' ' && c < 0x7F) /* 0x7F is DEL, not printable ASCII */ { key = (c - ' ') << 1; OutputCJKStr(tty_fd, FullCharMap[lInfo.sysCoding]+key, 2); } else write(tty_fd,&c,1); } void HZFilter(int tty_fd, unsigned char key) { int handled = 0; if (IsHanziInput) { if (IsAssociateMode) handled = Associate_HZFilter(tty_fd, key); if (!handled) handled = cur_table->HZFilter(tty_fd, key); /* will call the correct filter function */ } if (!handled) OutputEngChar(tty_fd, key); }