/* ### ### This file is part of ### ### TurboLinux ZWinPro ### ### Copyright (C) 1999-2000 TurboLinux, Inc. ### All Rights Reserved ### Distributed under the terms of the GNU General Public License (GPL) ### ### ### Authors: TurboLinux Chinese Development Team: ### Justin Yu ### Sean Chen ### Daniel Fang ### */ //Why onthespot: //onthespot provide a close interaction between the applications //and the user. In onthespot style, the user's feeling is to edit //on the insertion place. //Important: //onthespot style is not a good choice for many input methods, such //as pinyin, which has multi-selection for one PinYin. //Important: //The current IMdkit has bugs in on-the-spot implementation. //Please make sure you use the modified version from //http://www.turbolinux.com.cn/~justiny/project-chinput.html //OnTheSpot Style works for Java JDK, Mozilla(default style) and //some simple demos. Motif's internal TextField/Text widgets can //work but still has some problems in IC focus. // //OnTheSpot is the best style for some input methods, but don't //expect it work on any applications, because the programmers are //too lazy to add on-the-spot support on their programs :) // //The order for preedit callback and commit string is: // (1). Commit String // (2). Update Preedit Callbacks //which is expected by most applications. //it maybe in the reverse order to some other IM server //so in such case, the application will do the following // (1) when composed text exits, clear the text // (2) Commit text // (3) when composed text exits, redraw the existing preedit //as described in Mozilla. //FIXME or FIXMOZILLA //mozilla's another bug: //In Chinput's onthespot style, status area and auxiliary //area(candidate area) are all necessary. If using the status area as both //status and candidate window, the user cannot input conveniently. So it is //better to popup the candidate window. candidate window and status window all //want to floating up, so it cause the application crashing. //This happened on the recent snapshot of mozilla, but M16 is fine. //Suggestion: //To extend the XIM protocol to support spot location in the //onthespot style!!! #include "all.h" char *mbstocts(char *s) { XTextProperty tp; XmbTextListToTextProperty(display, &s, 1, XCompoundTextStyle, &tp); return tp.value; } void HZonspotPreeditStart() { //client usually does not support this callback IMPreeditCBStruct data; IC *ic = (IC *)FindIC(last_icid); if(!ic) return; data.major_code = XIM_PREEDIT_START; data.connect_id = ic->connect_id; data.icid = ic->id; IMCallCallback(this_xims, (XPointer)&data); } void HZonspotPreeditDone() { //client usually does not support this callback IMPreeditCBStruct data; IC *ic = (IC *)FindIC(last_icid); if(!ic) return; data.major_code = XIM_PREEDIT_DONE; data.connect_id = ic->connect_id; data.icid = ic->id; IMCallCallback(this_xims, (XPointer)&data); } void HZonspotPreeditCaret() { //Chinput does not need caret operation for the time being //because it extracts preedit string and status/candidate string //from IME, and replace the whole client string } void HZonspotPreeditDraw(char *s, int len) { int i; char *buf; IC *ic = (IC *)FindIC(last_icid); IMPreeditCBStruct data; XIMText text; XIMFeedback feedback[128] = {0}; char *convtext = s; char tbuf[80]; if(!ic) return; //trim spaces while(len > 0 && s[len-1] == ' ') len--; s[len] = '\0'; data.major_code = XIM_PREEDIT_DRAW; data.connect_id = ic->connect_id; data.icid = ic->id; for(i=0; i<128; i++) feedback[i] = XIMUnderline; feedback[len] = 0; //data.todo.draw.caret = ic->len+1; data.todo.draw.caret = 0; data.todo.draw.chg_first = 0; data.todo.draw.chg_length = ic->len; //the previous length for clear data.todo.draw.text = &text; //the input server only support multibyte string. //so the client should support both multibyte and widechar text.encoding_is_wchar = False; //flag_encoding = FindEncByID(ic->id); flag_encoding = ic->encoding; if((HZServer.encoding == HZSERVER_ENCODING_GB && flag_encoding == HZSERVER_ENCODING_BIG5 && flag_lock == LOCK_NONE) || (HZServer.encoding == HZSERVER_ENCODING_GB && flag_encoding == HZSERVER_ENCODING_GB && flag_lock == LOCK_BIG5)){ //filter to big5 encoding gbmixstring_big5mixstring(convtext, tbuf, len); strncpy(convtext, tbuf, len); } else if((HZServer.encoding == HZSERVER_ENCODING_BIG5 && flag_encoding == HZSERVER_ENCODING_GB && flag_lock == LOCK_NONE) || (HZServer.encoding == HZSERVER_ENCODING_BIG5 && flag_encoding == HZSERVER_ENCODING_BIG5 && flag_lock == LOCK_GB)){ //filter to gb encoding big5mixstring_gbmixstring(convtext, tbuf, len); strncpy(convtext, tbuf, len); } convtext[len] = 0; if(flag_encoding == HZSERVER_ENCODING_GB) setlocale(LC_CTYPE, gblocale); else setlocale(LC_CTYPE, big5locale); buf = mbstocts(convtext); text.string.multi_byte = buf; text.length = strlen(buf); text.feedback = feedback; IMCallCallback(this_xims, (XPointer)&data); XFree(buf); ic->len = mb_strlen(s, -1); } void HZonspotPreeditClear() { IC *ic = (IC *)FindIC(last_icid); //char *buf; IMPreeditCBStruct data; XIMText text; XIMFeedback feedback[1] = {0}; if(!ic) return; if(ic->len == 0) return; data.major_code = XIM_PREEDIT_DRAW; data.connect_id = ic->connect_id; data.icid = ic->id; data.todo.draw.caret = 0; data.todo.draw.chg_first = 0; data.todo.draw.chg_length = ic->len; //clear length data.todo.draw.text = &text; //replace string to NULL text.feedback = feedback; text.length = 0; text.string.multi_byte = ""; IMCallCallback(this_xims, (XPointer)&data); ic->len = 0; } void HZonspotStatusStart() { //client usually does not support this } void HZonspotStatusDone() { //client usually does not support this } void HZonspotStatusDraw(char *s, int len) { int i; IC *ic = (IC *)FindIC(last_icid); IMStatusCBStruct data; XIMFeedback feedback[128]={0}; char tmp[256]; char tbuf[256]; XIMText text; char *convtext; char *buf; //if no status area, popup the candidate window if(!ic) return; //if(!(ic->input_style & XIMStatusCallbacks)) return; candidate_preprocess(s); strcpy(tmp, ""); if(flag_corner) strcat(tmp, "【全"); else strcat(tmp, "【半"); if(flag_punct) strcat(tmp, "o】"); else strcat(tmp, " .】"); strcat(tmp, chinputime[cur_inputmethod].namegb); //if popup candidate window, then we need not put selection on //the status window if(cmode != HZSERVER_CMODE_AUTO){ strcat(tmp, ":"); strcat(tmp, s); } len = strlen(tmp); //buf = mbstocts(tmp); convtext = tmp; if((HZServer.encoding == HZSERVER_ENCODING_GB && flag_encoding == HZSERVER_ENCODING_BIG5 && flag_lock == LOCK_NONE) || (HZServer.encoding == HZSERVER_ENCODING_GB && flag_encoding == HZSERVER_ENCODING_GB && flag_lock == LOCK_BIG5)){ //filter to big5 encoding gbmixstring_big5mixstring(convtext, tbuf, len); strncpy(convtext, tbuf, len); } else if((HZServer.encoding == HZSERVER_ENCODING_BIG5 && flag_encoding == HZSERVER_ENCODING_GB && flag_lock == LOCK_NONE) || (HZServer.encoding == HZSERVER_ENCODING_BIG5 && flag_encoding == HZSERVER_ENCODING_BIG5 && flag_lock == LOCK_GB)){ //filter to gb encoding big5mixstring_gbmixstring(convtext, tbuf, len); strncpy(convtext, tbuf, len); } convtext[len] = 0; if(flag_encoding == HZSERVER_ENCODING_GB) setlocale(LC_CTYPE, gblocale); else setlocale(LC_CTYPE, big5locale); buf = mbstocts(convtext); data.todo.draw.type = XIMTextType; data.connect_id = ic->connect_id; data.icid = ic->id; data.major_code = XIM_STATUS_DRAW; data.todo.draw.data.text = &text; for(i=0; i<128; i++) feedback[i] = XIMUnderline; feedback[len] = 0; text.string.multi_byte = buf; text.length = strlen(buf); text.feedback = feedback; IMCallCallback(this_xims, (XPointer)&data); XFree(buf); //If no callbacks, then we have no way to draw the candidate //area for Chinese input. Thus, I provide a root window //to let the users choose the word/phrases. //You can moving the root window anywhere within the screen. //kinput2 popup a root window around the lower left corner //of the screen, but it is not the best way. if(cmode == HZSERVER_CMODE_AUTO) HZoverspotDrawCandidateArea(s, len); } void HZonspotClear(void) { int i; IC *ic = (IC *)FindIC(last_icid); IMStatusCBStruct data; XIMFeedback feedback[256]={0}; char tmp[256]; XIMText text; char *convtext; char *buf; int len; //if no status area, popup the candidate window if(!ic) return; if(!(ic->input_style & XIMStatusCallbacks))return; strcpy(tmp, ""); if(flag_corner) strcat(tmp, "【全"); else strcat(tmp, "【半"); if(flag_punct) strcat(tmp, "o】"); else strcat(tmp, " .】"); if(map_mode == 0) strcat(tmp, "西文输入"); else strcat(tmp, chinputime[cur_inputmethod].namegb); //strcat(tmp, " "); len = strlen(tmp); convtext = tmp; if((HZServer.encoding == HZSERVER_ENCODING_GB && flag_encoding == HZSERVER_ENCODING_BIG5 && flag_lock == LOCK_NONE) || (HZServer.encoding == HZSERVER_ENCODING_GB && flag_encoding == HZSERVER_ENCODING_GB && flag_lock == LOCK_BIG5)){ //filter to big5 encoding char tbuf[256]; gbmixstring_big5mixstring(convtext, tbuf, len); strncpy(convtext, tbuf, len); } else if((HZServer.encoding == HZSERVER_ENCODING_BIG5 && flag_encoding == HZSERVER_ENCODING_GB && flag_lock == LOCK_NONE) || (HZServer.encoding == HZSERVER_ENCODING_BIG5 && flag_encoding == HZSERVER_ENCODING_BIG5 && flag_lock == LOCK_GB)){ //filter to gb encoding char tbuf[256]; big5mixstring_gbmixstring(convtext, tbuf, len); strncpy(convtext, tbuf, len); } convtext[len] = 0; if(flag_encoding == HZSERVER_ENCODING_GB) setlocale(LC_CTYPE, gblocale); else setlocale(LC_CTYPE, big5locale); buf = mbstocts(convtext); data.todo.draw.type = XIMTextType; data.connect_id = ic->connect_id; data.icid = ic->id; data.major_code = XIM_STATUS_DRAW; data.todo.draw.data.text = &text; for(i=0; i<256; i++) feedback[i] = XIMUnderline; feedback[len] = 0; text.string.multi_byte = buf; text.length = strlen(buf); text.feedback = feedback; IMCallCallback(this_xims, (XPointer)&data); XFree(buf); } void HZonspotFlush(void) { char mbuf[256]; //if(flag_refresh)return; bzero(mbuf, 256); if(flag_english) strcpy(mbuf, input_buf); else IMM_GetInputDisplay (chinput_imm, mbuf, sizeof (mbuf)); HZonspotPreeditDraw(mbuf, strlen(mbuf)); //in general, status window only display current status //of input method. but if we have no way to display the //candidate window(e.g., the use disabled the candidate window) //we have to display the candidate list in status window IMM_GetSelectDisplay (chinput_imm, mbuf, sizeof (mbuf)); HZonspotStatusDraw(mbuf, strlen(mbuf)); }