Back to index

im-sdk  12.3.91
neima_interface.c
Go to the documentation of this file.
00001 /*
00002 * Neima输入法,支持:
00003 *   (1) 目前提供简体中文GB2312,GBK,GB18030和繁体中文BIG5。
00004 *       具体charset决定于session的属性。
00005 *   (2) 简体中文输入法使用自绘制的Canidates-UI,反映新的输入法
00006 *       接口的性质:
00007 *       a) 三种简体内码输入成为一种输入法
00008 *          但是三种繁体内码各自成为一种输入法
00009 *       b) 简体输入法使用自绘制的candidate界面
00010 *       c) 使用用户配置决定是否显示(utf-8, unicode)提示
00011 */
00012 #include <stdio.h>
00013 
00014 #include "ime.h"
00015 #include "ime_buffer.h"
00016 
00017 /**************************************************************************
00018 * IME Methods according to the IME.h
00019 ***************************************************************************/
00020 ImeResult neima_Initialize(ImeInfo ime_info);
00021 ImeResult neima_Destroy(ImeInfo ime_info);
00022 ImeResult neima_Create_Session(ImeInputContext ic);
00023 ImeResult neima_Destroy_Session(ImeInputContext ic);
00024 ImeResult neima_Process_Key_Event(ImeInputContext ic, ImeKey key_event);
00025 ImeResult neima_FocusIn(ImeInputContext ic);
00026 ImeResult neima_FocusOut(ImeInputContext ic);
00027 ImeResult neima_Create_User(ImeInputContext ic);
00028 ImeResult neima_Destroy_User(ImeInputContext ic);
00029 ImeResult neima_Create_Desktop(ImeInputContext ic);
00030 ImeResult neima_Destroy_Desktop(ImeInputContext ic);
00031 
00032 ImeMethodsRec neima_methods = {
00033     100,                              /* version */
00034     neima_Initialize,                 /* ImeInitialize */
00035     neima_Destroy,                    /* ImeDestroy  */
00036     neima_Process_Key_Event,          /* ImeProcessKeyEvent */
00037     NULL,                             /* ImeProcessAuxEvent  */
00038     neima_Create_Session,             /* ImeAttachSession */
00039     neima_Destroy_Session,            /* ImeDetachSession */
00040     neima_FocusIn,                    /* ImeFocusIn  */
00041     neima_FocusOut,                   /* ImeFocusOut */
00042     neima_Create_User,                /* ImeAttachUser */
00043     neima_Destroy_User,               /* ImeDetachUser */
00044     neima_Create_Desktop,             /* ImeAttachDesktop */
00045     neima_Destroy_Desktop,            /* ImeDeta chDesktop */
00046     NULL,                             /* ImeGetErrorMsg */
00047 };
00048 
00049 ImmServices imm_services = NULL;
00050 
00051 // Typedefine for data saved in user scope
00052 // do not used bit mask, just for demostration
00053 typedef struct _TUserPreference {
00054     int    show_utf8_value;
00055     int    show_unicode_value;
00056 } TUserPreference;
00057 
00058 // Typedefine for data saved in desktop scope
00059 enum {
00060     LANG_NONE           = 0,
00061     LANG_ZHCN           = ENCODE_GB18030,
00062     LANG_ZHTW_BIG5      = ENCODE_BIG5,
00063     LANG_ZHTW_BIG5HKSCS = ENCODE_BIG5HKSCS,
00064     LANG_ZHTW_EUCTW     = ENCODE_EUCTW
00065 };
00066 
00067 #ifdef WIN32
00068 #define EXPORT extern __declspec(dllexport)
00069 EXPORT
00070 #endif
00071 ImeResult RegisterIME(ImmServices srvs, ImeInfo* ppinfo, ImeMethods* pmthds, int argc, char **argv)
00072 {
00073     int enc, lang = LANG_NONE;
00074     ImeInfoRec *ime_info = NULL;
00075 
00076     DEBUG_printf("    ====>Register NeiMa IM: argc: %d\n", argc);
00077     if (argc == 1) { // IMM should not load it twice for same parameter
00078         if (strcmp(argv[0], "zh_CN") == 0) {
00079             lang = LANG_ZHCN;
00080         } else if (strcmp(argv[0], "BIG5") == 0) {
00081             lang = LANG_ZHTW_BIG5;
00082         } else if (strcmp(argv[0], "BIG5HKSCS") == 0) {
00083             lang = LANG_ZHTW_BIG5HKSCS;
00084         } else if (strcmp(argv[0], "EUCTW") == 0) {
00085             lang = LANG_ZHTW_EUCTW;
00086         }
00087     }
00088     if (argc != 1 || lang == LANG_NONE){
00089         DEBUG_printf("        ====>Please using argument [zh_CN|BIG5|BIG5HKSCS|EUCTW]\n");
00090         return IME_FAIL;
00091     }
00092 
00093     ime_info = (ImeInfoRec *)malloc(sizeof(ImeInfoRec)); //suppose success
00094 
00095     ime_info->version             = 100;
00096     ime_info->mt_safe             = 0;
00097     ime_info->encoding            = lang;
00098     ime_info->uuid                = "neima-1d76e189-9a54-4a24-8cf7-5d611f3d555f";
00099     ime_info->author              = "Phill Zhang <Phill.Zhang@sun.com>";
00100     ime_info->copyright           = "Copyright (c) 2005 Sun Microsystems";;
00101     ime_info->icon_file           = "neima.xpm";
00102     ime_info->pl                  = NULL;
00103     ime_info->specific_data       = (void*)lang;
00104     ime_info->hinting             = NULL;
00105 
00106     switch (lang) {
00107     case LANG_ZHCN:
00108         ime_info->name       = "";
00109         ime_info->support_locales = "zh,zh_CN,zh_CN.GB2312,zh_CN.GBK,zh_CN.UTF-8,zh_CN.GB18030";
00110         break;
00111     case LANG_ZHTW_BIG5:
00112         ime_info->name       = "BIG5X";
00113         ime_info->support_locales = "zh_TW,zh_TW.BIG5,zh_TW.UTF-8";
00114         break;
00115     case LANG_ZHTW_BIG5HKSCS:
00116         ime_info->name       = "BIG5HKSCSX";
00117         ime_info->support_locales = "zh_HK,zh_HK.BIG5HKSCS,zh_HK.UTF-8";
00118         break;
00119     case LANG_ZHTW_EUCTW:
00120         ime_info->name       = "EUC";
00121         ime_info->support_locales = "zh_TW.EUCTW,zh_TW.UTF-8";
00122         break;
00123     }
00124     *ppinfo = ime_info;
00125     *pmthds = &neima_methods;
00126     imm_services = srvs;
00127 
00128     return (IME_OK);
00129 }
00130 
00131 static
00132 int get_ime_language(ImeInputContext ic)
00133 {
00134     ImeInfo ime_info = imm_services->ImmGetImeInfo(ic);
00135     return (ime_info)?((int)ime_info->specific_data):(LANG_NONE);
00136 }
00137 
00138 static
00139 ImHandle get_candidate_aux(ImeInputContext ic)
00140 {
00141     return (ImHandle)imm_services->ImmGetData(ic, IME_SCOPE_DESKTOP);
00142 }
00143 
00144 ImeResult neima_Initialize(ImeInfo ime_info)
00145 {
00146     DEBUG_printf("    ====>neima_Initialize for language %d\n", ime_info->specific_data);
00147 
00148     return (IME_OK);
00149 }
00150 
00151 ImeResult neima_Destroy(ImeInfo ime_info)
00152 {
00153     DEBUG_printf("    ====>neima_Destroy\n");
00154 
00155     if (ime_info != NULL)
00156         free(ime_info);
00157 
00158     return (IME_OK);
00159 }
00160 
00161 static
00162 ImeResult my_update_candidates(ImeInputContext ic, ImeBufferRec *ime_buffer)
00163 {
00164     int sz = 0;
00165     ImeEventRec         event;
00166 
00167     ime_buffer->candidates.horizental = 0;
00168 
00169     event.any_event.ic = ic;
00170     event.any_event.peer = get_candidate_aux(ic);
00171     if (ime_buffer) sz = ime_buffer->candidates.count;
00172     if ((get_ime_language(ic) == LANG_ZHCN) && (event.any_event.peer != 0)) { //make sure the aux start successfully
00173         if (sz == 0) {
00174             event.type = IME_EVENT_EXPOSE;
00175             event.any_event.param = 0;    //hide candidates
00176             imm_services->ImmSendUiMessage(&event);
00177         } else {
00178             event.type = IME_EVENT_EXPOSE;
00179             event.any_event.param = IMUI_STATE_SHOW;    //show candidates
00180             imm_services->ImmSendUiMessage(&event);
00181             event.type = IME_EVENT_CANDI_DATA;
00182             event.any_event.param = ENCODE_GB18030;
00183             event.candidate_data_event.candidates = &(ime_buffer->candidates);
00184             imm_services->ImmSendUiMessage(&event);
00185         }
00186     } else {
00187         if (sz == 0)
00188             imm_services->ImmHideCandidates(ic);
00189         else {
00190             imm_services->ImmShowCandidates(ic);
00191             imm_services->ImmUpdateCandidates(ic, &ime_buffer->candidates);
00192         }
00193     }
00194 
00195     return IME_OK;
00196 }
00197 
00198 //infact 9/16/5/1/5
00199 #define MAX_PREEDIT_BYTES               16
00200 #define MAX_CANDIDATES_NUM              16
00201 #define MAX_CANDIDATE_BYTES             16
00202 #define MAX_NUMBERING_BYTES             4
00203 #define MAX_COMMIT_BYTES                16
00204 
00205 ImeResult neima_Create_Session(ImeInputContext ic)
00206 {
00207     int i;
00208     ImmResult imm_result;
00209     ImeBufferRec *ime_buffer = NULL;
00210 
00211     DEBUG_printf("    ====>neima_Create_Session ======= begin calloc for ime_buffer\n");
00212     ime_buffer = alloc_ime_buffer(MAX_PREEDIT_BYTES, MAX_CANDIDATES_NUM, MAX_CANDIDATE_BYTES, MAX_NUMBERING_BYTES, MAX_COMMIT_BYTES);
00213     if (ime_buffer == NULL)
00214         return (IME_FAIL);
00215 
00216     imm_result = imm_services->ImmSetData(ic, IME_SCOPE_SESSION, ime_buffer);
00217     if (imm_result == IMM_FAIL) {
00218         free(ime_buffer);
00219         return (IME_FAIL);
00220     }
00221 
00222     return (IME_OK);
00223 }
00224 
00225 ImeResult neima_Destroy_Session(ImeInputContext ic)
00226 {
00227     ImeBufferRec *ime_buffer = (ImeBufferRec *)imm_services->ImmGetData(ic, IME_SCOPE_SESSION);
00228     DEBUG_printf("    ====>neima_Destroy_Session ======= begin get ime_session_data: 0x%x\n", ime_buffer);
00229 
00230     free_ime_buffer(ime_buffer);
00231 
00232     return (IME_OK);
00233 }
00234 
00235 ImeResult neima_Create_User(ImeInputContext ic)
00236 {
00237     int  sz;
00238     unsigned char* buf = NULL;
00239     TUserPreference* pup = NULL;
00240 
00241     if (pup = (TUserPreference*)malloc(sizeof(TUserPreference))) {
00242         memset(pup, 0, sizeof(TUserPreference));
00243         buf = (unsigned char*)imm_services->ImmLoadUserProfile(ic, "preference", &sz);
00244         if (buf) {
00245             if (sscanf(buf, "%d", &sz) == 1) {
00246                 pup->show_utf8_value = (sz & 1);
00247                 pup->show_unicode_value = (sz & 2);
00248             }
00249             imm_services->ImmFreeUserProfile(buf);
00250         }
00251         imm_services->ImmSetData(ic, IME_SCOPE_USER, pup);
00252         return IME_OK;
00253     }
00254     return IME_FAIL;
00255 }
00256 
00257 ImeResult neima_Destroy_User(ImeInputContext ic)
00258 {
00259     int  pref = 0;
00260     char valstr[32];
00261     TUserPreference* pup = (TUserPreference*)imm_services->ImmGetData(ic, IME_SCOPE_USER);
00262     if (pup) {
00263         if (pup->show_utf8_value) pref |= 1;
00264         if (pup->show_unicode_value) pref |= 2;
00265         snprintf(valstr, 32, "%d\n", pref);
00266         return ImmSaveUserProfile(ic, "preference", valstr, strlen(valstr));
00267     }
00268     return IME_OK;
00269 }
00270 
00271 ImeResult neima_Create_Desktop(ImeInputContext ic)
00272 {
00273     static const char *aux_name = "com.sun.iiim.cle.aux.neima";
00274 
00275     DEBUG_printf("    ====>neima: call neima_Create_Desktop()\n");
00276 
00277     if (get_ime_language(ic) == LANG_ZHCN) {
00278         ImHandle candi_aux = imm_services->ImmStartUI(ic, aux_name);
00279         imm_services->ImmSetData(ic, IME_SCOPE_DESKTOP, (void*)candi_aux);
00280     }
00281 }
00282 
00283 ImeResult neima_Destroy_Desktop(ImeInputContext ic)
00284 {
00285     DEBUG_printf("    ====>neima: call neima_Destroy_Desktop()\n");
00286 
00287     if (get_ime_language(ic) == LANG_ZHCN) {
00288         ImHandle candi_aux = (ImHandle)imm_services->ImmGetData(ic, IME_SCOPE_DESKTOP);
00289         imm_services->ImmCloseUI(ic, candi_aux);
00290     }
00291 }
00292 
00293 ImeResult neima_FocusIn(ImeInputContext ic)
00294 {
00295     DEBUG_printf("    ====>neima: call neima_FocusIn()\n");
00296 
00297     ImeBufferRec *ime_buffer = NULL;
00298     if (get_ime_language(ic) == LANG_ZHCN) {
00299         ime_buffer = (ImeBufferRec *)imm_services->ImmGetData(ic, IME_SCOPE_SESSION);
00300         if (ime_buffer && ime_buffer->candidates.count)
00301             return my_update_candidates(ic, ime_buffer);
00302     }
00303 
00304     return IME_OK;
00305 }
00306 
00307 ImeResult neima_FocusOut(ImeInputContext ic)
00308 {
00309     ImeEventRec event;
00310 
00311     DEBUG_printf("    ====>neima: call neima_FocusOut()\n");
00312 
00313     if (get_ime_language(ic) == LANG_ZHCN) {
00314         event.type              = IME_EVENT_EXPOSE;
00315         event.any_event.peer    = get_candidate_aux(ic);
00316         if (event.any_event.peer) {
00317             event.any_event.ic      = ic;
00318             event.any_event.param   = 0;    //hide it
00319             imm_services->ImmSendUiMessage(&event);
00320         }
00321     }
00322     return(IME_OK);
00323 }
00324 
00325 /* process key input event */
00326 /* return value:  IME_UNUSED_KEY:  if IME not use this key, return this key to systerm directly */
00327 /*                IME_OK:      if IME has used this key */
00328 ImeResult neima_Process_Key_Event(ImeInputContext ic, ImeKey key_event)
00329 {
00330     unsigned char   key;
00331     int             lang, ret, encoding = 0;
00332     ImeBufferRec   *ime_buffer = NULL;
00333 
00334     DEBUG_printf("    ====>neima_Process_Key_Event: ic: 0x%x\n", ic);
00335     ime_buffer = (ImeBufferRec *)imm_services->ImmGetData(ic, IME_SCOPE_SESSION);
00336     if (ime_buffer == NULL){
00337         DEBUG_printf("      ====>neima: ime_buffer is null.\n");
00338         return (IME_UNUSED_KEY);
00339     }
00340 
00341     ime_buffer->return_status = 0;
00342 
00343     lang = get_ime_language(ic);
00344     if (lang == LANG_ZHCN) {
00345         DEBUG_printf("      ====>neima: language is zh_CN.\n");
00346         encoding = imm_services->ImmGetSessionEncoding(ic);
00347         if (encoding != ENCODE_GB2312 && encoding != ENCODE_GBK)
00348             encoding = lang;
00349     } else
00350         encoding = lang;
00351 
00352     key = imm_services->ImmPrefilterKey(key_event);
00353     if (key == IME_FILTERED_KEY_UNUSED)
00354        return (IME_UNUSED_KEY);
00355 
00356     ret = neima_filter(encoding, key, ime_buffer);
00357     if (ret == IME_UNUSED_KEY) {
00358         DEBUG_printf("      ====>neima: key is not used.\n");
00359        return (IME_UNUSED_KEY);
00360     }
00361 
00362     DEBUG_printf("      ====>neima: key is used.\n");
00363     if (ime_buffer->return_status & IME_PREEDIT_AREA) {
00364         if (ime_buffer->preedit.preedit.text[0] != '\0') {
00365             imm_services->ImmShowPreedit(ic);
00366             imm_services->ImmUpdatePreedit(ic, &ime_buffer->preedit);
00367         } else {
00368             imm_services->ImmHidePreedit(ic);
00369         }
00370     }
00371 
00372     if (ime_buffer->return_status & IME_LOOKUP_AREA)
00373         my_update_candidates(ic, ime_buffer);
00374 
00375     if (ime_buffer->return_status & IME_COMMIT)
00376         imm_services->ImmCommit(ic, ime_buffer->commit_buf);
00377 
00378     return (IME_OK);
00379 }