Back to index

im-sdk  12.3.91
composer.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2003   Choe Hwanjin <krisna@kldp.org>
00003  *
00004  * This library is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Library General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2 of the License, or (at your option) any later version.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * Library General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Library General Public
00015  * License along with this library; if not, write to the
00016  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00017  * Boston, MA 02111-1307, USA.
00018  */
00019 
00020 #ifdef HAVE_CONFIG_H
00021 #include <config.h>
00022 #endif
00023 
00024 #include <stdio.h>
00025 #include <stdlib.h>
00026 #include <stdarg.h>
00027 #include <string.h>
00028 #include <wchar.h>
00029 #include <ctype.h>
00030 #include <X11/Xmd.h>
00031 
00032 #define CARD32BIT CARD32
00033 
00034 #include <SunIM.h>
00035 
00036 #include "composer.h"
00037 #include "hangul.h"
00038 
00039 #include "keyboard.h"
00040 
00041 #define HANGUL_CONFIG_FILENAME (IM_LEIFDIR "/hangul/hangul.conf")
00042 #define CANDIDATE_TABLE_FILENAME (IM_LEIFDIR "/hangul/tables/candidate.txt")
00043 
00044 typedef struct _CandidateItem  CandidateItem;
00045 typedef struct _CandidateTable CandidateTable;
00046 
00047 struct _CandidateItem {
00048     UTFCHAR ch;
00049     UTFCHAR *comment;
00050     int len;
00051     struct _CandidateItem *next;
00052     struct _CandidateItem *next_key;
00053 };
00054 
00055 struct _CandidateTable {
00056     int size;
00057     struct _CandidateItem ***data;
00058 };
00059 
00060 typedef struct _HangulLEConfig {
00061     const UTFCHAR *keyboard;
00062     Bool (*composer)(iml_session_t *, IMKeyEventStruct *);
00063 } HangulLEConfig;
00064 
00065 static HangulLEConfig config;
00066 static CandidateTable candidate_table;
00067 
00068 static Bool hangul_composer_2(iml_session_t *s, IMKeyEventStruct *key);
00069 static Bool hangul_composer_3(iml_session_t *s, IMKeyEventStruct *key);
00070 
00071 static int output_mode = 0;
00072 
00073 static Bool
00074 hangul_is_empty(Session *hsession)
00075 {
00076     return (hsession->choseong[0]  == 0 &&       \
00077            hsession->jungseong[0] == 0 && \
00078            hsession->jongseong[0] == 0 );
00079 }
00080 
00081 static void
00082 hangul_push (Session *hsession, UTFCHAR ch)
00083 {
00084     hsession->stack[++hsession->stack_index] = ch;
00085 }
00086 
00087 static UTFCHAR
00088 hangul_peek (Session *hsession)
00089 {
00090     if (hsession->stack_index < 0)
00091        return 0;
00092     return hsession->stack[hsession->stack_index];
00093 }
00094 
00095 static UTFCHAR
00096 hangul_pop (Session *hsession)
00097 {
00098     if (hsession->stack_index < 0)
00099        return 0;
00100     return hsession->stack[hsession->stack_index--];
00101 }
00102 
00103 static Bool
00104 hangul_add_choseong (Session *hsession, UTFCHAR ch)
00105 {
00106     if (hsession->lindex >= 3)
00107         return False;
00108     hsession->lindex++;
00109     hsession->choseong[hsession->lindex] = ch;
00110     return True;
00111 }
00112 
00113 static Bool
00114 hangul_add_jungseong (Session *hsession, UTFCHAR ch)
00115 {
00116     if (hsession->vindex >= 3)
00117         return False;
00118     hsession->vindex++;
00119     hsession->jungseong[hsession->vindex] = ch;
00120     return True;
00121 }
00122 
00123 static Bool
00124 hangul_add_jongseong (Session *hsession, UTFCHAR ch)
00125 {
00126     if (hsession->tindex >= 3)
00127         return False;
00128     hsession->tindex++;
00129     hsession->jongseong[hsession->tindex] = ch;
00130     return True;
00131 }
00132 
00133 static Bool
00134 hangul_sub_choseong (Session *hsession)
00135 {
00136     hsession->choseong[hsession->lindex] = 0;
00137     if (hsession->lindex <= 0)
00138         return False;
00139     hsession->lindex--;
00140     return True;
00141 }
00142 
00143 static Bool
00144 hangul_sub_jungseong (Session *hsession)
00145 {
00146     hsession->jungseong[hsession->vindex] = 0;
00147     if (hsession->vindex <= 0)
00148         return False;
00149     hsession->vindex--;
00150     return True;
00151 }
00152 
00153 static Bool
00154 hangul_sub_jongseong (Session *hsession)
00155 {
00156     hsession->jongseong[hsession->tindex] = 0;
00157     if (hsession->tindex <= 0)
00158         return False;
00159     hsession->tindex--;
00160     return True;
00161 }
00162 
00163 static IMFeedbackList*
00164 feedbacklist_new(iml_session_t *s, int len)
00165 {
00166     int i;
00167     IMFeedbackList *feedbacklist;
00168     IMFeedback *feedback;
00169 
00170     feedbacklist = (IMFeedbackList*)
00171                      s->If->m->iml_new(s, sizeof(IMFeedbackList) * len);
00172     for (i = 0; i < len; i++) {
00173        feedbacklist[i].count_feedbacks = 1;
00174        feedback = s->If->m->iml_new(s,
00175                   sizeof(IMFeedback) * feedbacklist[i].count_feedbacks);
00176        feedbacklist[i].feedbacks = feedback;
00177        IM_FEEDBACK_TYPE(feedback) = IM_DECORATION_FEEDBACK;
00178        IM_FEEDBACK_VALUE(feedback) = IMNormal;
00179     }
00180 
00181     return feedbacklist;
00182 }
00183 
00184 static void
00185 feedback_set_properties(iml_session_t *s,
00186                      IMFeedbackList *feedbacks, int nproperties, ...)
00187 {
00188     int i;
00189     va_list args;
00190     IMFeedback *feedback;
00191 
00192     if (feedbacks->count_feedbacks < nproperties) {
00193        /* realloc */
00194        feedbacks->count_feedbacks = nproperties;
00195        feedbacks->feedbacks = (IMFeedback*)s->If->m->iml_new(s,
00196               sizeof(IMFeedback) * feedbacks->count_feedbacks);
00197        memset(feedbacks->feedbacks, 0,
00198               sizeof(IMFeedback) * feedbacks->count_feedbacks);
00199     }
00200 
00201     va_start(args, nproperties);
00202     for (i = 0; i < nproperties; i++) {
00203        feedback = &feedbacks->feedbacks[i];
00204        IM_FEEDBACK_TYPE(feedback) = va_arg(args, int);
00205        IM_FEEDBACK_VALUE(feedback) = va_arg(args, int);
00206     }
00207     va_end(args);
00208 }
00209 
00210 static IMFeedbackList*
00211 feedbacklist_new_underline(iml_session_t *s, int len)
00212 {
00213     int i;
00214     IMFeedbackList *feedbacklist;
00215 
00216     feedbacklist = feedbacklist_new(s, len);
00217     for (i = 0; i < len; i++) {
00218        feedback_set_properties(s, &feedbacklist[i], 1,
00219                             IM_DECORATION_FEEDBACK, IMUnderline);
00220     }
00221 
00222     return feedbacklist;
00223 }
00224 
00225 static IMFeedbackList*
00226 feedbacklist_new_reverse(iml_session_t *s, int len)
00227 {
00228     int i;
00229     IMFeedbackList *feedbacklist;
00230 
00231     feedbacklist = feedbacklist_new(s, len);
00232     for (i = 0; i < len; i++) {
00233        feedback_set_properties(s, &feedbacklist[i], 1,
00234                             IM_DECORATION_FEEDBACK, IMReverse);
00235     }
00236 
00237     return feedbacklist;
00238 }
00239 
00240 static IMText *
00241 imtext_new(iml_session_t *s, UTFCHAR *str, int len, IMFeedbackList *feedbacks)
00242 {
00243     IMText *text;
00244 
00245     text = (IMText *) s->If->m->iml_new(s, sizeof(IMText));
00246     text->encoding = UTF16_CODESET;
00247     text->char_length = len;
00248     text->text.utf_chars = (UTFCHAR*)s->If->m->iml_new(s,
00249                             sizeof(UTFCHAR) * (len + 1));
00250     memcpy(text->text.utf_chars, str, sizeof(UTFCHAR) * len);
00251     text->text.utf_chars[len] = '\0';
00252     text->feedback = feedbacks;
00253     text->count_annotations = 0;
00254     text->annotations = NULL;
00255 
00256     return text;
00257 }
00258 
00259 static UTFCHAR
00260 get_preedit_char(iml_session_t *s)
00261 {
00262     UTFCHAR ch;
00263     Session *hsession = (Session*) s->specific_data;
00264 
00265     if (hangul_is_empty(hsession))
00266        return 0;
00267 
00268     /* use hangul syllables   (U+AC00 - U+D7AF) */
00269     ch = hangul_jamo_to_syllable (hsession->choseong[0],
00270                               hsession->jungseong[0],
00271                               hsession->jongseong[0]);
00272      
00273     return ch;
00274 }
00275 
00276 
00277 #define OUTPUT_MODE_JAMO_EXT  1
00278 #define OUTPUT_MODE_JAMO  1
00279 
00280 static int
00281 get_preedit_string(iml_session_t *s, UTFCHAR *buf)
00282 {
00283     int i;
00284     int n = 0;
00285     Session *hsession = (Session*) s->specific_data;
00286 
00287     if (hangul_is_empty(hsession))
00288        return 0;
00289 
00290     if (output_mode & OUTPUT_MODE_JAMO_EXT) {
00291          /* we use conjoining jamo, U+1100 - U+11FF */
00292        if (hsession->choseong[0] == 0) {
00293            buf[n++] = HCF;
00294        } else {
00295            for (i = 0; i <= hsession->lindex; i++)
00296               buf[n++] = hsession->choseong[i];
00297        }
00298 
00299        if (hsession->jungseong[0] == 0)
00300            buf[n++] = HJF;
00301        else {
00302            for (i = 0; i <= hsession->vindex; i++)
00303               buf[n++] = hsession->jungseong[i];
00304        }
00305 
00306        if (hsession->jongseong[0] != 0) {
00307            for (i = 0; i <= hsession->tindex; i++)
00308               buf[n++] = hsession->jongseong[i];
00309        }
00310     } else if (output_mode & OUTPUT_MODE_JAMO) {
00311        /* we use conjoining jamo, U+1100 - U+11FF */
00312        if (hsession->choseong[0] == 0)
00313            buf[n++] = HCF;
00314        else
00315            buf[n++] = hsession->choseong[0];
00316         
00317        if (hsession->jungseong[0] == 0)
00318            buf[n++] = HJF;
00319        else
00320            buf[n++] = hsession->jungseong[0];
00321         
00322        if (hsession->jongseong[0] != 0)
00323            buf[n++] = hsession->jongseong[0];
00324     } else {
00325        /* use hangul syllables   (U+AC00 - U+D7AF)
00326         * and compatibility jamo (U+3130 - U+318F) */
00327        UTFCHAR ch;
00328        ch = hangul_jamo_to_syllable (hsession->choseong[0],
00329                                   hsession->jungseong[0],
00330                                   hsession->jongseong[0]);
00331         
00332        if (ch) {
00333            buf[n++] = ch;
00334        } else {
00335            if (hsession->choseong[0]) {
00336               ch = hangul_choseong_to_cjamo (hsession->choseong[0]);
00337               buf[n++] = ch;
00338            }
00339            if (hsession->jungseong[0]) {
00340               ch = hangul_jungseong_to_cjamo (hsession->jungseong[0]);
00341               buf[n++] = ch;
00342            }
00343            if (hsession->jongseong[0]) {
00344               ch = hangul_jongseong_to_cjamo (hsession->jongseong[0]);
00345               buf[n++] = ch;
00346            }
00347        }
00348     }
00349 
00350     return n;
00351 }
00352 
00353 static void
00354 hangul_preedit_update(iml_session_t *s)
00355 {
00356     iml_inst *lp;
00357     int len;
00358     UTFCHAR buf[12];
00359     Session *hsession = (Session*) s->specific_data;
00360 
00361     len = get_preedit_string(s, buf);
00362     if (len == 0) {
00363        lp = s->If->m->iml_make_preedit_erase_inst(s);
00364        s->If->m->iml_link_inst_tail(&hsession->rrv, lp);
00365     } else {
00366        IMText *text;
00367 
00368        text = imtext_new(s, buf, len, feedbacklist_new_reverse(s, len));
00369        lp = s->If->m->iml_make_preedit_draw_inst(s, text);
00370        s->If->m->iml_link_inst_tail(&hsession->rrv, lp);
00371     }
00372 }
00373 
00374 static void
00375 hangul_commit_utfchar(iml_session_t *s, UTFCHAR ch)
00376 {
00377     iml_inst *lp;
00378     IMText *text;
00379     Session *hsession = (Session*) s->specific_data;
00380 
00381     text = imtext_new(s, &ch, 1, feedbacklist_new(s, 1));
00382 
00383     lp = s->If->m->iml_make_commit_inst(s, text);
00384     s->If->m->iml_link_inst_tail(&hsession->rrv, lp);
00385 }
00386 
00387 static void
00388 hangul_commit_utfstr(iml_session_t *s, UTFCHAR *str, int len)
00389 {
00390     iml_inst *lp;
00391     IMText *text;
00392     Session *hsession = (Session*) s->specific_data;
00393 
00394     text = imtext_new(s, str, len, feedbacklist_new(s, len));
00395 
00396     lp = s->If->m->iml_make_commit_inst(s, text);
00397     s->If->m->iml_link_inst_tail(&hsession->rrv, lp);
00398 }
00399 
00400 static void
00401 hangul_hsession_clear(Session *hsession)
00402 {
00403     hsession->stack_index = -1;
00404     hsession->stack[0] = 0;
00405     hsession->stack[1] = 0;
00406     hsession->stack[2] = 0;
00407     hsession->stack[3] = 0;
00408     hsession->stack[4] = 0;
00409     hsession->stack[5] = 0;
00410     hsession->stack[6] = 0;
00411     hsession->stack[7] = 0;
00412     hsession->stack[8] = 0;
00413     hsession->stack[9] = 0;
00414     hsession->stack[10] = 0;
00415     hsession->stack[11] = 0;
00416 
00417     hsession->lindex = 0;
00418     hsession->choseong[0] = 0;
00419     hsession->choseong[1] = 0;
00420     hsession->choseong[2] = 0;
00421     hsession->choseong[3] = 0;
00422 
00423     hsession->vindex = 0;
00424     hsession->jungseong[0] = 0;
00425     hsession->jungseong[1] = 0;
00426     hsession->jungseong[2] = 0;
00427     hsession->jungseong[3] = 0;
00428 
00429     hsession->tindex = 0;
00430     hsession->jongseong[0] = 0;
00431     hsession->jongseong[1] = 0;
00432     hsession->jongseong[2] = 0;
00433     hsession->jongseong[3] = 0;
00434 }
00435 
00436 static int
00437 hangul_get_commit_string(iml_session_t *s, UTFCHAR *buf, int len)
00438 {
00439     int i;
00440     int n = 0;
00441     Session *hsession = (Session*) s->specific_data;
00442 
00443     if (output_mode & OUTPUT_MODE_JAMO_EXT) {
00444          /* we use conjoining jamo, U+1100 - U+11FF */
00445        if (hsession->choseong[0] == 0) {
00446            buf[n++] = HCF;
00447        } else {
00448            for (i = 0; i <= hsession->lindex; i++)
00449               buf[n++] = hsession->choseong[i];
00450        }
00451 
00452        if (hsession->jungseong[0] == 0)
00453            buf[n++] = HJF;
00454        else {
00455            for (i = 0; i <= hsession->vindex; i++)
00456               buf[n++] = hsession->jungseong[i];
00457        }
00458 
00459        if (hsession->jongseong[0] != 0) {
00460            for (i = 0; i <= hsession->tindex; i++)
00461               buf[n++] = hsession->jongseong[i];
00462        }
00463     } else if (output_mode & OUTPUT_MODE_JAMO) {
00464        /* we use conjoining jamo, U+1100 - U+11FF */
00465        if (hsession->choseong[0] == 0)
00466            buf[n++] = HCF;
00467        else
00468            buf[n++] = hsession->choseong[0];
00469         
00470        if (hsession->jungseong[0] == 0)
00471            buf[n++] = HJF;
00472        else
00473            buf[n++] = hsession->jungseong[0];
00474         
00475        if (hsession->jongseong[0] != 0)
00476            buf[n++] = hsession->jongseong[0];
00477     } else {
00478        /* use hangul syllables   (U+AC00 - U+D7AF)
00479         * and compatibility jamo (U+3130 - U+318F) */
00480        UTFCHAR ch;
00481        ch = hangul_jamo_to_syllable (hsession->choseong[0],
00482                                   hsession->jungseong[0],
00483                                   hsession->jongseong[0]);
00484         
00485        if (ch) {
00486            buf[n++] = ch;
00487        } else {
00488            if (hsession->choseong[0]) {
00489               ch = hangul_choseong_to_cjamo (hsession->choseong[0]);
00490               buf[n++] = ch;
00491            }
00492            if (hsession->jungseong[0]) {
00493               ch = hangul_jungseong_to_cjamo (hsession->jungseong[0]);
00494               buf[n++] = ch;
00495            }
00496            if (hsession->jongseong[0]) {
00497               ch = hangul_jongseong_to_cjamo (hsession->jongseong[0]);
00498               buf[n++] = ch;
00499            }
00500        }
00501     }
00502 
00503     return n;
00504 }
00505 
00506 static int
00507 hangul_commit(iml_session_t *s)
00508 {
00509     int len = 0;
00510     UTFCHAR buf[12];
00511     Session *hsession = (Session*) s->specific_data;
00512 
00513     if (hangul_is_empty(hsession))
00514        return 0;
00515 
00516     len = hangul_get_commit_string(s, buf, sizeof(buf));
00517 
00518     hangul_hsession_clear(hsession);
00519     hangul_preedit_update(s);
00520     hangul_commit_utfstr(s, buf, len);
00521 
00522     return len;
00523 }
00524 
00525 static const HangulCombination compose_table_default[] = {
00526   { 0x11001100, 0x1101 }, /* choseong  kiyeok + kiyeok  = ssangkiyeok */
00527   { 0x11031103, 0x1104 }, /* choseong  tikeut + tikeut  = ssangtikeut */
00528   { 0x11071107, 0x1108 }, /* choseong  pieup  + pieup   = ssangpieup  */
00529   { 0x11091109, 0x110a }, /* choseong  sios   + sios    = ssangsios   */
00530   { 0x110c110c, 0x110d }, /* choseong  cieuc  + cieuc   = ssangcieuc  */
00531   { 0x11691161, 0x116a }, /* jungseong o      + a       = wa          */
00532   { 0x11691162, 0x116b }, /* jungseong o      + ae      = wae         */
00533   { 0x11691175, 0x116c }, /* jungseong o      + i       = oe          */
00534   { 0x116e1165, 0x116f }, /* jungseong u      + eo      = weo         */
00535   { 0x116e1166, 0x1170 }, /* jungseong u      + e       = we          */
00536   { 0x116e1175, 0x1171 }, /* jungseong u      + i       = wi          */
00537   { 0x11731175, 0x1174 }, /* jungseong eu     + i       = yi          */
00538   { 0x11a811a8, 0x11a9 }, /* jongseong kiyeok + kiyeok  = ssangekiyeok       */
00539   { 0x11a811ba, 0x11aa }, /* jongseong kiyeok + sios    = kiyeok-sois */
00540   { 0x11ab11bd, 0x11ac }, /* jongseong nieun  + cieuc   = nieun-cieuc */
00541   { 0x11ab11c2, 0x11ad }, /* jongseong nieun  + hieuh   = nieun-hieuh */
00542   { 0x11af11a8, 0x11b0 }, /* jongseong rieul  + kiyeok  = rieul-kiyeok       */
00543   { 0x11af11b7, 0x11b1 }, /* jongseong rieul  + mieum   = rieul-mieum */
00544   { 0x11af11b8, 0x11b2 }, /* jongseong rieul  + pieup   = rieul-pieup */
00545   { 0x11af11ba, 0x11b3 }, /* jongseong rieul  + sios    = rieul-sios  */
00546   { 0x11af11c0, 0x11b4 }, /* jongseong rieul  + thieuth = rieul-thieuth      */
00547   { 0x11af11c1, 0x11b5 }, /* jongseong rieul  + phieuph = rieul-phieuph      */
00548   { 0x11af11c2, 0x11b6 }, /* jongseong rieul  + hieuh   = rieul-hieuh */
00549   { 0x11b811ba, 0x11b9 }, /* jongseong pieup  + sios    = pieup-sios  */
00550   { 0x11ba11ba, 0x11bb }, /* jongseong sios   + sios    = ssangsios   */
00551 };
00552 
00553 static UTFCHAR
00554 hangul_compose (Session *hsession, UTFCHAR first, UTFCHAR last)
00555 {
00556     int min, max, mid;
00557     uint32_t key;
00558  
00559     /* make key */
00560     key = first << 16 | last;
00561 
00562     /* binary search in table */
00563     min = 0;
00564     max = hsession->compose_table_size - 1;
00565 
00566     while (max >= min) {
00567        mid = (min + max) / 2;
00568        if (hsession->compose_table[mid].key < key)
00569            min = mid + 1;
00570        else if (hsession->compose_table[mid].key > key)
00571            max = mid - 1;
00572        else
00573            return hsession->compose_table[mid].code;
00574     }
00575 
00576     return 0;
00577 }
00578 
00579 static UTFCHAR
00580 hangul_key_mapping(Session *hsession, IMKeyEventStruct *key)
00581 {
00582     int keyChar = key->keyChar;
00583 
00584     if (keyChar >= '!' && keyChar <= '~') {
00585        if (key->modifier & IM_SHIFT_MASK) {
00586            if (keyChar >= 'a' && keyChar <= 'z')
00587               keyChar -= ('a' - 'A');
00588        } else {
00589            if (keyChar >= 'A' && keyChar <= 'Z')
00590               keyChar += ('a' - 'A');
00591        }
00592        return hsession->keyboard[keyChar - '!'];
00593     }
00594     return 0;
00595 }
00596 
00597 static Bool
00598 hangul_is_candidate_key(IMKeyEventStruct *key)
00599 {
00600     if (key->keyCode == IM_VK_F9 || key->keyCode == IM_VK_HANJA)
00601        return True;
00602     return False;
00603 }
00604 
00605 static Bool
00606 hangul_is_backspace(IMKeyEventStruct *key)
00607 {
00608     if (key->keyCode == IM_VK_BACK_SPACE)
00609        return True;
00610     return False;
00611 }
00612 
00613 static Bool
00614 hangul_process_nonhangul(iml_session_t *s, UTFCHAR ch, IMKeyEventStruct *key)
00615 {
00616     int len = 0;
00617     UTFCHAR buf[16] = { 0, };
00618     Session *hsession = (Session*) s->specific_data;
00619 
00620     if (!hangul_is_empty(hsession)) {
00621        len = hangul_get_commit_string(s, buf, sizeof(buf));
00622        hangul_hsession_clear(hsession);
00623        hangul_preedit_update(s);
00624     }
00625 
00626     if (ch != 0) {   /* for sebeol(3 set) keymap */
00627        buf[len++] = ch;
00628        hangul_commit_utfstr(s, buf, len);
00629        return True;
00630     }
00631 
00632     hangul_commit_utfstr(s, buf, len);
00633 
00634     return False;
00635 }
00636 
00637 static Bool
00638 hangul_composer_2(iml_session_t *s, IMKeyEventStruct *key)
00639 {
00640     UTFCHAR ch;
00641     UTFCHAR comp_ch;
00642     UTFCHAR jong_ch;
00643     Session *hsession = (Session*) s->specific_data;
00644 
00645     ch = hangul_key_mapping(hsession, key);
00646 
00647     if (hsession->jongseong[0]) {
00648        if (hangul_is_choseong (ch)) {
00649            jong_ch = hangul_choseong_to_jongseong (ch);
00650            comp_ch = hangul_compose (hsession, 
00651                             hsession->jongseong[0], jong_ch);
00652            if (hangul_is_jongseong (comp_ch)) {
00653               hsession->jongseong[0] = comp_ch;
00654               hangul_push (hsession, comp_ch);
00655            } else {
00656               hangul_commit (s);
00657               hsession->choseong[0] = ch;
00658               hangul_push (hsession, ch);
00659            }
00660            goto done;
00661        }
00662        if (hangul_is_jungseong (ch)) {
00663            UTFCHAR pop, peek;
00664            pop = hangul_pop (hsession);
00665            peek = hangul_peek (hsession);
00666            if (hangul_is_jungseong (peek)) {
00667               hsession->jongseong[0] = 0;
00668               hangul_commit (s);
00669               hsession->choseong[0] = hangul_jongseong_to_choseong (pop);
00670               hsession->jungseong[0] = ch;
00671               hangul_push (hsession, hsession->choseong[0]);
00672               hangul_push (hsession, ch);
00673            } else {
00674               wchar_t choseong, jongseong; 
00675               hangul_jongseong_dicompose (hsession->jongseong[0],
00676                                     &jongseong, &choseong);
00677               hsession->jongseong[0] = jongseong;
00678               hangul_commit (s);
00679               hsession->choseong[0] = choseong;
00680               hsession->jungseong[0] = ch;
00681               hangul_push (hsession, choseong);
00682               hangul_push (hsession, ch);
00683            }
00684            goto done;
00685        }
00686     } else if (hsession->jungseong[0]) {
00687        if (hangul_is_choseong (ch)) {
00688            if (hsession->choseong[0]) {
00689               jong_ch = hangul_choseong_to_jongseong (ch);
00690               if (hangul_is_jongseong (jong_ch)) {
00691                   hsession->jongseong[0] = jong_ch;
00692                   hangul_push (hsession, jong_ch);
00693               } else {
00694                   hangul_commit (s);
00695                   hsession->choseong[0] = ch;
00696                   hangul_push (hsession, ch);
00697               }
00698            } else {
00699               hsession->choseong[0] = ch;
00700               hangul_push (hsession, ch);
00701            }
00702            goto done;
00703        }
00704        if (hangul_is_jungseong (ch)) {
00705            comp_ch = hangul_compose (hsession,
00706                             hsession->jungseong[0], ch);
00707            if (hangul_is_jungseong (comp_ch)) {
00708               hsession->jungseong[0] = comp_ch;
00709               hangul_push (hsession, comp_ch);
00710            } else {
00711               hangul_commit (s);
00712               hsession->jungseong[0] = ch;
00713               hangul_push (hsession, ch);
00714            }
00715            goto done;
00716        }
00717     } else if (hsession->choseong[0]) {
00718        if (hangul_is_choseong (ch)) {
00719            comp_ch = hangul_compose (hsession,
00720                             hsession->choseong[0], ch);
00721            if (hangul_is_choseong (comp_ch)) {
00722               hsession->choseong[0] = comp_ch;
00723               hangul_push (hsession, comp_ch);
00724            } else {
00725               hangul_commit (s);
00726               hsession->choseong[0] = ch;
00727               hangul_push (hsession, ch);
00728            }
00729            goto done;
00730        }
00731        if (hangul_is_jungseong (ch)) {
00732            hsession->jungseong[0] = ch;
00733            hangul_push (hsession, ch);
00734            goto done;
00735        }
00736     } else {
00737        if (hangul_is_choseong (ch)) {
00738            hsession->choseong[0] = ch;
00739            hangul_push (hsession, ch);
00740            goto done;
00741        }
00742        if (hangul_is_jungseong (ch)) {
00743            hsession->jungseong[0] = ch;
00744            hangul_push (hsession, ch);
00745            goto done;
00746        }
00747     }
00748 
00749     /* treat backspace */
00750     if (hangul_is_backspace (key)) {
00751        ch = hangul_pop (hsession);
00752        if (ch != 0) {
00753            if (hangul_is_choseong (ch)) {
00754               ch = hangul_peek (hsession);
00755               hsession->choseong[0] = hangul_is_choseong (ch) ? ch : 0;
00756               goto done;
00757            }
00758            if (hangul_is_jungseong (ch)) {
00759               ch = hangul_peek (hsession);
00760               hsession->jungseong[0] = hangul_is_jungseong (ch) ? ch : 0;
00761               goto done;
00762            }
00763            if (hangul_is_jongseong (ch)) {
00764               ch = hangul_peek (hsession);
00765               hsession->jongseong[0] = hangul_is_jongseong (ch) ? ch : 0;
00766               goto done;
00767            }
00768        }
00769     }
00770 
00771     return hangul_process_nonhangul (s, ch, key); /* english */
00772 
00773 done:
00774     hangul_preedit_update (s);
00775     return True;
00776 }
00777 
00778 static Bool
00779 hangul_composer_3 (iml_session_t *s, IMKeyEventStruct *key)
00780 {
00781     UTFCHAR ch;
00782     Session *hsession = (Session*) s->specific_data;
00783 
00784     ch = hangul_key_mapping (hsession, key);
00785 
00786     if (output_mode & OUTPUT_MODE_JAMO_EXT) {
00787        if (hsession->jongseong[0]) {
00788            if (hangul_is_choseong (ch)) {
00789               hangul_commit (s);
00790               hsession->choseong[0] = ch;
00791               hangul_push (hsession, ch);
00792               goto done;
00793            }
00794            if (hangul_is_jungseong (ch)) {
00795               hangul_commit (s);
00796               hsession->jungseong[0] = ch;
00797               hangul_push (hsession, ch);
00798               goto done;
00799            }
00800            if (hangul_is_jongseong (ch)) {
00801               if (!hangul_add_jongseong (hsession, ch)) {
00802                   hangul_commit (s);
00803                   hsession->jongseong[0] = ch;
00804               }
00805               hangul_push (hsession, ch);
00806               goto done;
00807            }
00808        } else if (hsession->jungseong[0]) {
00809            if (hangul_is_choseong (ch)) {
00810               hangul_commit (s);
00811               hsession->choseong[0] = ch;
00812               hangul_push (hsession, ch);
00813               goto done;
00814            }
00815            if (hangul_is_jungseong (ch)) {
00816               if (!hangul_add_jungseong (hsession, ch)) {
00817                   hangul_commit (s);
00818                   hsession->jungseong[0] = ch;
00819               }
00820               hangul_push (hsession, ch);
00821               goto done;
00822            }
00823            if (hangul_is_jongseong (ch)) {
00824               hsession->jongseong[0] = ch;
00825               hangul_push (hsession, ch);
00826               goto done;
00827            }
00828        } else if (hsession->choseong[0]) {
00829            if (hangul_is_choseong (ch)) {
00830               if (!hangul_add_choseong (hsession, ch)) {
00831                   hangul_commit (s);
00832                   hsession->choseong[0] = ch;
00833               }
00834               hangul_push (hsession, ch);
00835               goto done;
00836            }
00837            if (hangul_is_jungseong (ch)) {
00838               hsession->jungseong[0] = ch;
00839               hangul_push (hsession, ch);
00840               goto done;
00841            }
00842            if (hangul_is_jongseong (ch)) {
00843               hangul_commit (s);
00844               hsession->jongseong[0] = ch;
00845               hangul_push (hsession, ch);
00846               goto done;
00847            }
00848        } else {
00849            if (hangul_is_choseong (ch)) {
00850               hsession->choseong[0] = ch;
00851               hangul_push (hsession, ch);
00852               goto done;
00853            }
00854            if (hangul_is_jungseong (ch)) {
00855               hsession->jungseong[0] = ch;
00856               hangul_push (hsession, ch);
00857               goto done;
00858            }
00859            if (hangul_is_jongseong (ch)) {
00860               hsession->jongseong[0] = ch;
00861               hangul_push (hsession, ch);
00862               goto done;
00863            }
00864        }
00865 
00866        /* treat backspace */
00867        if (hangul_is_backspace (key)) {
00868            ch = hangul_pop (hsession);
00869            if (ch != 0) {
00870               if (hangul_is_choseong (ch)) {
00871                   hangul_sub_choseong (hsession);
00872                   goto done;
00873               }
00874               if (hangul_is_jungseong (ch)) {
00875                   hangul_sub_jungseong (hsession);
00876                   goto done;
00877               }
00878               if (hangul_is_jongseong (ch)) {
00879                   hangul_sub_jongseong (hsession);
00880                   goto done;
00881               }
00882            }
00883        }
00884     } else {
00885        /* choseong */
00886        if (hangul_is_choseong (ch)) {
00887            if (hsession->choseong[0] == 0) {
00888               hsession->choseong[0] = ch;
00889               hangul_push (hsession, ch);
00890               goto done;
00891            }
00892            if (hangul_is_choseong (hangul_peek (hsession))) {
00893               UTFCHAR choseong = hangul_compose (hsession,
00894                                              hsession->choseong[0], ch);
00895               if (choseong) {
00896                   hsession->choseong[0] = choseong;
00897                   hangul_push (hsession, choseong);
00898                   goto done;
00899               }
00900            }
00901            hangul_commit (s);
00902            hsession->choseong[0] = ch;
00903            hangul_push (hsession, ch);
00904            goto done;
00905        }
00906        /* junseong */
00907        if (hangul_is_jungseong (ch)) {
00908            if (hsession->jungseong[0] == 0) {
00909               hsession->jungseong[0] = ch;
00910               hangul_push (hsession, ch);
00911               goto done;
00912            }
00913            if (hangul_is_jungseong (hangul_peek (hsession))) {
00914               UTFCHAR jungseong = hangul_compose (hsession,
00915                                               hsession->jungseong[0],
00916                                               ch);
00917               if (jungseong) {
00918                   hsession->jungseong[0] = jungseong;
00919                   hangul_push (hsession, jungseong);
00920                   goto done;
00921               }
00922            }
00923            hangul_commit (s);
00924            hsession->jungseong[0] = ch;
00925            hangul_push (hsession, ch);
00926            goto done;
00927        }
00928        /* jongseong */
00929        if (hangul_is_jongseong (ch)) {
00930            if (hsession->jongseong[0] == 0) {
00931               hsession->jongseong[0] = ch;
00932               hangul_push (hsession, ch);
00933               goto done;
00934            }
00935            if (hangul_is_jongseong (hangul_peek (hsession))) {
00936               UTFCHAR jongseong = hangul_compose (hsession,
00937                                               hsession->jongseong[0],
00938                                               ch);
00939               if (jongseong) {
00940                   hsession->jongseong[0] = jongseong;
00941                   hangul_push (hsession, jongseong);
00942                   goto done;
00943               }
00944            }
00945            hangul_commit (s);
00946            hsession->jongseong[0] = ch;
00947            hangul_push (hsession, ch);
00948            goto done;
00949        }
00950        /* treat backspace */
00951        if (hangul_is_backspace (key)) {
00952            ch = hangul_pop (hsession);
00953            if (ch != 0) {
00954               if (hangul_is_choseong (ch)) {
00955                   ch = hangul_peek (hsession);
00956                   hsession->choseong[0] = hangul_is_choseong (ch) ? ch : 0;
00957                   goto done;
00958               }
00959               if (hangul_is_jungseong (ch)) {
00960                   ch = hangul_peek (hsession);
00961                   hsession->jungseong[0] = hangul_is_jungseong (ch) ? ch : 0;
00962                   goto done;
00963               }
00964               if (hangul_is_jongseong (ch)) {
00965                   ch = hangul_peek (hsession);
00966                   hsession->jongseong[0] = hangul_is_jongseong (ch) ? ch : 0;
00967                   goto done;
00968               }
00969            }
00970        }
00971     }
00972 
00973     return hangul_process_nonhangul (s, ch, key);
00974 
00975 done:
00976     hangul_preedit_update(s);
00977     return True;
00978 }
00979 
00980 /* candidate routine */
00981 const UTFCHAR UTFCHAR_EOF = ~0;
00982 
00983 Bool
00984 utfchar_is_little_endian(void)
00985 {
00986     union {
00987        unsigned char mb[sizeof(UTFCHAR)];
00988        UTFCHAR       ch;
00989     } test;
00990 
00991     test.ch = 0xFEFF;
00992     return test.mb[0] == 0xFF;
00993 }
00994 
00995 inline UTFCHAR
00996 utfchar_byteswap(UTFCHAR ch)
00997 {
00998     return (ch << 8 & 0xFF00) | (ch >> 8 & 0xFF);
00999 }
01000 
01001 UTFCHAR
01002 utfchar_getc(FILE *stream, Bool need_swap)
01003 {
01004     UTFCHAR ch;
01005 
01006     if (fread(&ch, sizeof(ch), 1, stream) == 1) {
01007        if (need_swap)
01008            ch = utfchar_byteswap(ch);
01009        return ch;
01010     } else
01011        return UTFCHAR_EOF;
01012 }
01013 
01014 UTFCHAR*
01015 utfchar_gets(UTFCHAR *buf, int size, FILE *stream, Bool need_swap)
01016 {
01017     int i, len;
01018     UTFCHAR ch;
01019 
01020     len = size / sizeof(buf[0]) - 1;
01021     for (i = 0; i < len; i++) {
01022        ch = utfchar_getc(stream, need_swap);
01023        if (ch == UTFCHAR_EOF)
01024            break;
01025        if (ch == '\n')
01026            break;
01027        buf[i] = ch;
01028     }
01029     buf[i] = 0;
01030 
01031     if (i == 0)
01032        return NULL;
01033     else
01034        return buf;
01035 }
01036 
01037 UTFCHAR*
01038 utfchar_strchr(UTFCHAR* str, UTFCHAR c)
01039 {
01040     while (*str != 0) {
01041        if (*str == c)
01042            return str;
01043        str++;
01044     }
01045     return NULL;
01046 }
01047 
01048 int
01049 utfchar_strlen(UTFCHAR* str)
01050 {
01051     int len = 0;
01052 
01053     while (*str != 0) {
01054        len++;
01055        str++;
01056     }
01057     return len;
01058 }
01059 
01060 UTFCHAR*
01061 utfchar_strdup(UTFCHAR* str)
01062 {
01063     UTFCHAR *ret;
01064     int size = (utfchar_strlen(str) + 1) * sizeof(UTFCHAR);
01065 
01066     ret = (UTFCHAR*)malloc(size);
01067     memcpy(ret, str, size);
01068     return ret;
01069 }
01070 
01071 CandidateItem*
01072 candidate_item_new(UTFCHAR ch, UTFCHAR *comment)
01073 {
01074     CandidateItem *item;
01075 
01076     item = (CandidateItem*)malloc(sizeof(CandidateItem));
01077     item->ch = ch;
01078     if (comment != NULL)
01079        item->comment = utfchar_strdup(comment);
01080     else
01081        item->comment = NULL;
01082 
01083     item->len = 0;
01084     item->next = NULL;
01085     item->next_key = NULL;
01086     return item;
01087 }
01088 
01089 void
01090 candidate_item_delete(CandidateItem *item)
01091 {
01092     if (item) {
01093        free(item->comment);
01094        free(item);
01095     }
01096 }
01097 
01098 int
01099 candidate_item_length(CandidateItem *item)
01100 {
01101     int len = 0;
01102     while (item != NULL) {
01103        len++;
01104        item = item->next;
01105     }
01106     return len;
01107 }
01108 
01109 int
01110 candidate_item_key_length(CandidateItem *item)
01111 {
01112     int len = 0;
01113     while (item != NULL) {
01114        len++;
01115        item = item->next_key;
01116     }
01117     return len;
01118 }
01119 
01120 int
01121 candidate_table_compare(const void *first, const void *last)
01122 {
01123     return ((CandidateItem***)first)[0][0]->ch - 
01124           ((CandidateItem***)last)[0][0]->ch;
01125 }
01126 
01127 static inline UTFCHAR*
01128 skip_space(UTFCHAR* p)
01129 {
01130     while (*p == ' '  || *p == '\t' || *p == '\v' ||
01131           *p == '\n' || *p == '\r' || *p == '\f')
01132        p++;
01133     return p;
01134 }
01135 
01136 Bool
01137 candidate_table_load(CandidateTable *table, const char *filename)
01138 {
01139     FILE *file;
01140     int n, i, j;
01141     Bool need_swap;
01142     UTFCHAR bom;
01143     UTFCHAR *p;
01144     UTFCHAR buf[256];
01145     UTFCHAR ch;
01146     UTFCHAR key;
01147 
01148     CandidateItem *item;
01149     CandidateItem *list = NULL;
01150     CandidateItem *list_last = NULL;
01151     CandidateItem *items = NULL;
01152     CandidateItem *items_last = NULL;
01153 
01154     file = fopen(filename, "r");
01155     if (file == NULL) {
01156        printf("Failed to open candidate file: %s\n", filename);
01157        return False;
01158     }
01159 
01160     /* check byte order */
01161     bom = utfchar_getc(file, False);
01162     if (bom == 0xFEFF)
01163        need_swap = False;
01164     else if (bom == 0xFFFE)
01165        need_swap = True;
01166     else {
01167        /* candidate table file should be BE */
01168        need_swap = utfchar_is_little_endian();
01169        rewind(file);
01170     }
01171 
01172     while (!feof(file)) {
01173        p = utfchar_gets(buf, sizeof(buf), file, need_swap);
01174        if (p == NULL)
01175            break;
01176 
01177        p = skip_space(p);
01178        if (*p == 0 || *p == ';' || *p == '#')
01179            continue;
01180 
01181        if (*p == '[') {
01182            p++;
01183            key = *p;
01184            item = candidate_item_new(key, NULL);
01185            items = item;
01186            items_last = item;
01187            if (list == NULL) {
01188               list = items;
01189               list_last = items;
01190            } else {
01191               list_last->next_key = items;
01192               list_last = items;
01193            }
01194        } else {
01195            ch = *p;
01196            p = utfchar_strchr(p, '=');
01197            if (p != NULL) {
01198               p = skip_space(p + 1);
01199               item = candidate_item_new(ch, p);
01200            } else {
01201               item = candidate_item_new(ch, NULL);
01202            }
01203            if (items_last != NULL) {
01204               items_last->next = item;
01205               items_last = item;
01206            }
01207        }
01208     }
01209     fclose(file);
01210 
01211     table->size = candidate_item_key_length(list);
01212     table->data = (CandidateItem***)
01213                 malloc(sizeof(CandidateItem**) * table->size);
01214 
01215     items = list;
01216     for (i = 0; i < table->size; i++) {
01217        n = candidate_item_length(items);
01218        items->len = n - 1;
01219        table->data[i] = (CandidateItem**)
01220                        malloc(sizeof(CandidateItem*) * (n + 1));
01221        item = items;
01222        for (j = 0;  j < n; j++) {
01223            table->data[i][j] = item;
01224            item = item->next;
01225        }
01226        table->data[i][j] = NULL;
01227        items = items->next_key;
01228     }
01229 
01230     qsort(table->data, table->size, sizeof(table->data[0]),
01231          candidate_table_compare);
01232 
01233     return True;
01234 }
01235 
01236 static int
01237 candidate_table_get_index (UTFCHAR ch)
01238 {
01239     int first, last, mid;
01240 
01241     /* binary search */
01242     first = 0;
01243     last = candidate_table.size;
01244     while (first <= last) {
01245        mid = (first + last) / 2;
01246 
01247        if (ch == candidate_table.data[mid][0]->ch)
01248            return mid;
01249 
01250        if (ch < candidate_table.data[mid][0]->ch)
01251            last = mid - 1;
01252        else
01253            first = mid + 1;
01254     }
01255 
01256     return -1;
01257 }
01258 
01259 static IMLookupDrawCallbackStruct*
01260 hangul_lookup_draw_new(iml_session_t *s)
01261 {
01262     int i;
01263     int first, last, n, len;
01264     UTFCHAR label;
01265     UTFCHAR *buf;
01266     CandidateItem *item;
01267     IMText *text;
01268     IMLookupDrawCallbackStruct *draw;
01269     Session *hsession = (Session*) s->specific_data;
01270 
01271     first = hsession->candidate - (hsession->candidate % 10);
01272     last = (first + 9 < hsession->candidate_length - 1) ? 
01273            first + 9 : hsession->candidate_length - 1;
01274     n = last - first + 1;
01275 
01276     draw = (IMLookupDrawCallbackStruct *) s->If->m->iml_new(s,
01277                       sizeof(IMLookupDrawCallbackStruct));
01278     draw->index_of_first_candidate = 0;
01279     draw->index_of_last_candidate = n - 1;
01280     draw->n_choices = n;
01281     draw->title = imtext_new(s, (UTFCHAR*)&hsession->candidate_char, 1,
01282                             feedbacklist_new(s, 1)); 
01283     draw->choices = (IMChoiceObject *) s->If->m->iml_new(s,
01284             draw->n_choices * sizeof(IMChoiceObject));
01285 
01286     for (i = 0; i < n; i++) {
01287        item = candidate_table.data[hsession->candidate_index][first + i + 1];
01288        len = utfchar_strlen(item->comment) + 2;
01289        buf = (UTFCHAR*) s->If->m->iml_new(s, sizeof(UTFCHAR) * len);
01290        buf[0] = item->ch;
01291        buf[1] = ' ';
01292        memcpy(&buf[2], item->comment, (len - 2) * sizeof(UTFCHAR));
01293        if (first + i == hsession->candidate)
01294            text = imtext_new(s, buf, len, feedbacklist_new(s, len));
01295        else
01296            text = imtext_new(s, buf, len, feedbacklist_new_reverse(s, len));
01297        draw->choices[i].value = text;
01298 
01299        if (i == 9)
01300            label = '0';
01301        else
01302            label = '1' + i;
01303        text = imtext_new(s, &label, 1, feedbacklist_new(s, 1));
01304        draw->choices[i].label = text;
01305     }
01306     draw->max_len = 1;
01307     draw->index_of_current_candidate = hsession->candidate - first;
01308 
01309     return draw;
01310 }
01311 
01312 static void
01313 hangul_lookup_prev(iml_session_t *s)
01314 {
01315     iml_inst *lp;
01316     IMLookupDrawCallbackStruct *draw;
01317     Session *hsession = (Session*) s->specific_data;
01318 
01319     if (hsession->candidate > 0)
01320        hsession->candidate--;
01321     draw = hangul_lookup_draw_new(s);
01322 
01323     lp = s->If->m->iml_make_lookup_draw_inst(s, draw);
01324     s->If->m->iml_link_inst_tail(&hsession->rrv, lp);
01325 }
01326 
01327 static void
01328 hangul_lookup_next(iml_session_t *s)
01329 {
01330     iml_inst *lp;
01331     IMLookupDrawCallbackStruct *draw;
01332     Session *hsession = (Session*) s->specific_data;
01333 
01334     if (hsession->candidate < hsession->candidate_length - 1)
01335        hsession->candidate++;
01336     draw = hangul_lookup_draw_new(s);
01337 
01338     lp = s->If->m->iml_make_lookup_draw_inst(s, draw);
01339     s->If->m->iml_link_inst_tail(&hsession->rrv, lp);
01340 }
01341 
01342 static void
01343 hangul_lookup_prev_page(iml_session_t *s)
01344 {
01345     iml_inst *lp;
01346     IMLookupDrawCallbackStruct *draw;
01347     Session *hsession = (Session*) s->specific_data;
01348 
01349     hsession->candidate -= 10;
01350     if (hsession->candidate < 0)
01351        hsession->candidate = 0;
01352     draw = hangul_lookup_draw_new(s);
01353 
01354     lp = s->If->m->iml_make_lookup_draw_inst(s, draw);
01355     s->If->m->iml_link_inst_tail(&hsession->rrv, lp);
01356 }
01357 
01358 static void
01359 hangul_lookup_next_page(iml_session_t *s)
01360 {
01361     iml_inst *lp;
01362     IMLookupDrawCallbackStruct *draw;
01363     Session *hsession = (Session*) s->specific_data;
01364 
01365     hsession->candidate += 10;
01366     if (hsession->candidate >= hsession->candidate_length)
01367        hsession->candidate = hsession->candidate_length - 1;
01368     draw = hangul_lookup_draw_new(s);
01369 
01370     lp = s->If->m->iml_make_lookup_draw_inst(s, draw);
01371     s->If->m->iml_link_inst_tail(&hsession->rrv, lp);
01372 }
01373 
01374 static void
01375 hangul_lookup_start(iml_session_t *s, IMKeyEventStruct *key)
01376 {
01377     iml_inst *lp;
01378     IMLookupStartCallbackStruct *start;
01379     IMLookupDrawCallbackStruct *draw;
01380     Session *hsession = (Session*) s->specific_data;
01381 
01382     /* find candidate */
01383     hsession->candidate_char = get_preedit_char(s);
01384     hsession->candidate_index = candidate_table_get_index(hsession->candidate_char);
01385     if (hsession->candidate_index < 0) {
01386        /* fail to find candidate */
01387        hsession->candidate_char = 0;
01388        hsession->candidate_index = 0;
01389        return;
01390     }
01391 
01392     hsession->candidate_length = candidate_table.data[hsession->candidate_index][0]->len;
01393     hsession->candidate = 0;
01394     printf("hanja: %x (%d)\n",
01395            candidate_table.data[hsession->candidate_index][0]->ch,
01396            hsession->candidate_length);
01397 
01398     hsession->state = HANGUL_STATE_HANJA;
01399 
01400     /* send Lookup Start */
01401     start = (IMLookupStartCallbackStruct *)s->If->m->iml_new(s,
01402               sizeof(IMLookupStartCallbackStruct));
01403 
01404     start->whoIsMaster = IMIsMaster;
01405     start->IMPreference = (LayoutInfo *)s->If->m->iml_new(s,
01406               sizeof(LayoutInfo));
01407     start->IMPreference->choice_per_window = 10;
01408     start->IMPreference->ncolumns = 1;
01409     start->IMPreference->nrows = 10;
01410     start->IMPreference->drawUpDirection = DrawUpVertically;
01411     start->IMPreference->whoOwnsLabel = IMOwnsLabel;
01412 
01413     lp = s->If->m->iml_make_lookup_start_inst(s, start);
01414     s->If->m->iml_link_inst_tail(&hsession->rrv, lp);
01415 
01416     draw = hangul_lookup_draw_new(s);
01417 
01418     lp = s->If->m->iml_make_lookup_draw_inst(s, draw);
01419     s->If->m->iml_link_inst_tail(&hsession->rrv, lp);
01420 }
01421 
01422 static void
01423 hangul_lookup_done(iml_session_t *s)
01424 {
01425     iml_inst *lp;
01426     Session *hsession = (Session*) s->specific_data;
01427 
01428     hsession->candidate_char = 0;
01429     hsession->candidate_index = 0;
01430     hsession->candidate_length = 0;
01431     hsession->candidate = 0;
01432     hsession->state = HANGUL_STATE_HANGUL;
01433 
01434     lp = s->If->m->iml_make_lookup_done_inst(s);
01435     s->If->m->iml_link_inst_tail(&hsession->rrv, lp);
01436 }
01437 
01438 static void
01439 hangul_lookup_commit(iml_session_t *s)
01440 {
01441     UTFCHAR ch;
01442     Session *hsession = (Session*) s->specific_data;
01443 
01444     ch = candidate_table.data[hsession->candidate_index][hsession->candidate + 1]->ch;
01445     hangul_lookup_done(s);
01446     hangul_hsession_clear(hsession);
01447     hangul_preedit_update(s);
01448     hangul_commit_utfchar(s, ch);
01449     hsession->state = HANGUL_STATE_HANGUL;
01450 }
01451 
01452 static void
01453 hangul_lookup_commit_nth(iml_session_t *s, int n)
01454 {
01455     int first;
01456     UTFCHAR ch;
01457     Session *hsession = (Session*) s->specific_data;
01458 
01459     first = hsession->candidate - (hsession->candidate % 10);
01460     ch = candidate_table.data[hsession->candidate_index][first + n + 1]->ch;
01461     hangul_lookup_done(s);
01462     hangul_hsession_clear(hsession);
01463     hangul_preedit_update(s);
01464     hangul_commit_utfchar(s, ch);
01465     hsession->state = HANGUL_STATE_HANGUL;
01466 }
01467 
01468 static void
01469 get_striped(char *src, char *dest)
01470 {
01471     char *p;
01472 
01473     /* ignore white space from start */
01474     while (isspace(*src))
01475        src++;
01476 
01477     /* ignore white space at the end */
01478     for (p = src; !isspace(*p); p++)
01479        continue;
01480     *p = 0;
01481 
01482     strcpy(dest, src);
01483 }
01484 
01485 static void
01486 get_key_value(char *buf, char *key, char *value)
01487 {
01488     char *p;
01489     char *end = NULL;
01490 
01491     /* we silently ignore that has no '=' mark */
01492     p = strchr(buf, '=');
01493     if (p == NULL)
01494        return;
01495 
01496     p = strchr(buf, '#');
01497     if (p != NULL)
01498        *p = 0;
01499 
01500     p = strtok_r(buf, "=", &end);
01501     if (p != NULL)
01502        get_striped(p, key);
01503 
01504     p = strtok_r(NULL, "=", &end);
01505     if (p != NULL)
01506        get_striped(p, value);
01507 }
01508 
01509 static void
01510 hangul_load_config(void)
01511 {
01512     const char *conf_filename = HANGUL_CONFIG_FILENAME;
01513     FILE *conf_file;
01514     char key[64];
01515     char value[512];
01516     char buf[1024];
01517     char *p;
01518 
01519     /* default values */
01520     config.keyboard = keyboard_map_2;
01521     config.composer = hangul_composer_2;
01522 
01523     conf_file = fopen(conf_filename, "r");
01524     if (conf_file == NULL) {
01525        perror(conf_filename);
01526        return;
01527     }
01528 
01529     while (!feof(conf_file)) {
01530        p = fgets(buf, sizeof(buf), conf_file);
01531 
01532        if (p == NULL)
01533            break;
01534 
01535        /* check comment */
01536        if (buf[0] == '#')
01537            continue;
01538 
01539        buf[1023] = 0;
01540        get_key_value(buf, key, value);
01541 
01542        if (strcmp(key, "keyboard") == 0) {
01543            if (strcmp(value, "2") == 0) {
01544               config.keyboard = keyboard_map_2;
01545               config.composer = hangul_composer_2;
01546            } else if (strcmp(value, "32") == 0) {
01547               config.keyboard = keyboard_map_32;
01548               config.composer = hangul_composer_3;
01549            } else if (strcmp(value, "39") == 0) {
01550               config.keyboard = keyboard_map_390;
01551               config.composer = hangul_composer_3;
01552            } else if (strcmp(value, "3f") == 0) {
01553               config.keyboard = keyboard_map_3final;
01554               config.composer = hangul_composer_3;
01555            } else if (strcmp(value, "3s") == 0) {
01556               config.keyboard = keyboard_map_3sun;
01557               config.composer = hangul_composer_3;
01558            }
01559        }
01560     }
01561 
01562     fclose(conf_file);
01563 }
01564 
01565 static void
01566 hangul_load_candidate_table(void)
01567 {
01568     candidate_table_load(&candidate_table, CANDIDATE_TABLE_FILENAME);
01569 }
01570 
01571 void
01572 hangul_le_init()
01573 {
01574     hangul_load_config();
01575     hangul_load_candidate_table();
01576 }
01577 
01578 void
01579 hangul_desktop_init(iml_desktop_t *desktop)
01580 {
01581     Desktop *desktop_data;
01582 
01583     if (desktop->specific_data != NULL)
01584        free(desktop->specific_data);
01585 
01586     desktop_data = (Desktop *) calloc(1, sizeof(Desktop));
01587     desktop_data->state = HANGUL_STATE_ENGLISH;
01588     desktop->specific_data = desktop_data;
01589 }
01590 
01591 void
01592 hangul_desktop_finalize(iml_desktop_t *desktop)
01593 {
01594     if (desktop->specific_data != NULL) {
01595        free(desktop->specific_data);
01596        desktop->specific_data = NULL;
01597     }
01598 }
01599 
01600 void
01601 hangul_session_init(iml_session_t *s)
01602 {
01603     Session *hsession;
01604 
01605     if (s->specific_data != NULL)
01606        free(s->specific_data);
01607 
01608     hsession = (Session *)calloc(1, sizeof(Session));
01609     hsession->state = HANGUL_STATE_ENGLISH;
01610 
01611     hsession->keyboard = config.keyboard;
01612     hsession->composer = config.composer;
01613     hsession->compose_table_size = sizeof(compose_table_default) 
01614                             / sizeof(compose_table_default[0]);
01615     hsession->compose_table = compose_table_default;
01616 
01617     hsession->stack_index = -1;
01618 
01619     hsession->candidate_char = 0;
01620     hsession->candidate_index = 0;
01621     hsession->candidate_length = 0;
01622     hsession->candidate = 0;
01623 
01624     hsession->rrv = NULL;
01625 
01626     s->specific_data = hsession;
01627 }
01628 
01629 void
01630 hangul_session_finalize(iml_session_t *s)
01631 {
01632     if (s->specific_data != NULL) {
01633        free(s->specific_data);
01634        s->specific_data = NULL;
01635     }
01636 }
01637 
01638 IMText *
01639 hangul_session_reset(iml_session_t *s)
01640 {
01641     int len = 0;
01642     UTFCHAR buf[12];
01643     Session *hsession = (Session*) s->specific_data;
01644 
01645     if (hangul_is_empty(hsession))
01646        return NULL;
01647 
01648     len = hangul_get_commit_string(s, buf, sizeof(buf));
01649     hangul_hsession_clear(hsession);
01650     hangul_preedit_update(s);
01651     return imtext_new(s, buf, len, feedbacklist_new(s, len));
01652 }
01653 
01654 static UTFCHAR *
01655 get_status_string(iml_session_t *s)
01656 {
01657     static UTFCHAR status_str_english[] = { '\0' };
01658     static UTFCHAR status_str_hangul[] = { 0xd55c, 0xae00 };
01659     Session *hsession = (Session*) s->specific_data;
01660     
01661     switch (hsession->state) {
01662     case HANGUL_STATE_NONE:
01663     case HANGUL_STATE_ENGLISH:
01664        return status_str_english;
01665     case HANGUL_STATE_HANGUL:
01666     case HANGUL_STATE_HANJA:
01667        return status_str_hangul;
01668     }
01669     return status_str_english;
01670 }
01671 
01672 void
01673 hangul_prep(iml_session_t *s)
01674 {
01675     Session *hsession = (Session*) s->specific_data;
01676     hsession->rrv = NULL;
01677 }
01678 
01679 void
01680 hangul_exec(iml_session_t *s)
01681 {
01682     Session *hsession = (Session*) s->specific_data;
01683     if (hsession->rrv != NULL)
01684        s->If->m->iml_execute(s, &hsession->rrv);
01685 }
01686 
01687 void
01688 hangul_foward_keyevent(iml_session_t *s, IMKeyEventStruct *key)
01689 {
01690     iml_inst *lp;
01691     Session *hsession = (Session*) s->specific_data;
01692 
01693     lp = s->If->m->iml_make_keypress_inst(s, key);
01694     s->If->m->iml_link_inst_tail(&hsession->rrv, lp);
01695 }
01696 
01697 void
01698 hangul_focus(iml_session_t *s)
01699 {
01700     iml_inst *lp;
01701     int len;
01702     IMText *text;
01703     UTFCHAR *status_str;
01704     Session *hsession = (Session*) s->specific_data;
01705 
01706     lp = s->If->m->iml_make_status_start_inst(s);
01707     s->If->m->iml_link_inst_tail(&hsession->rrv, lp);
01708     status_str = get_status_string(s);
01709     len = utfchar_strlen(status_str);
01710     text = imtext_new(s, status_str, len, feedbacklist_new(s, len));
01711     lp = s->If->m->iml_make_status_draw_inst(s, text);
01712     s->If->m->iml_link_inst_tail(&hsession->rrv, lp);
01713 }
01714 
01715 void
01716 hangul_unfocus(iml_session_t *s)
01717 {
01718     iml_inst *lp;
01719     Session *hsession = (Session*) s->specific_data;
01720 
01721     lp = s->If->m->iml_make_status_done_inst(s);
01722     s->If->m->iml_link_inst_tail(&hsession->rrv, lp);
01723 }
01724 
01725 void
01726 hangul_conversion_on(iml_session_t *s)
01727 {
01728     iml_inst *lp;
01729     int len;
01730     IMText *text;
01731     UTFCHAR *status_str;
01732     Session *hsession = (Session*) s->specific_data;
01733 
01734     hsession->state = HANGUL_STATE_HANGUL;
01735     if (s->desktop && s->desktop->specific_data)
01736        ((Desktop*)s->desktop->specific_data)->state = HANGUL_STATE_HANGUL;
01737 
01738     lp = s->If->m->iml_make_start_conversion_inst(s);
01739     s->If->m->iml_link_inst_tail(&hsession->rrv, lp);
01740     lp = s->If->m->iml_make_preedit_start_inst(s);
01741     s->If->m->iml_link_inst_tail(&hsession->rrv, lp);
01742 
01743     status_str = get_status_string(s);
01744     len = utfchar_strlen(status_str);
01745     text = imtext_new(s, status_str, len, feedbacklist_new(s, len));
01746     lp = s->If->m->iml_make_status_draw_inst(s, text);
01747     s->If->m->iml_link_inst_tail(&hsession->rrv, lp);
01748 }
01749 
01750 void
01751 hangul_conversion_off(iml_session_t *s)
01752 {
01753     iml_inst *lp;
01754     int len;
01755     IMText *text;
01756     UTFCHAR *status_str;
01757     Session *hsession = (Session*) s->specific_data;
01758 
01759     hangul_commit (s);
01760 
01761     hsession->state = HANGUL_STATE_ENGLISH;
01762     if (s->desktop && s->desktop->specific_data)
01763        ((Desktop*)s->desktop->specific_data)->state = HANGUL_STATE_ENGLISH;
01764 
01765     status_str = get_status_string(s);
01766     len = utfchar_strlen(status_str);
01767     text = imtext_new(s, status_str, len, feedbacklist_new(s, len));
01768     lp = s->If->m->iml_make_status_draw_inst(s, text);
01769     s->If->m->iml_link_inst_tail(&hsession->rrv, lp);
01770 
01771     lp = s->If->m->iml_make_preedit_done_inst(s);
01772     s->If->m->iml_link_inst_tail(&hsession->rrv, lp);
01773     lp = s->If->m->iml_make_end_conversion_inst(s);
01774     s->If->m->iml_link_inst_tail(&hsession->rrv, lp);
01775 }
01776 
01777 Bool
01778 hangul_composer(iml_session_t *s, IMKeyEventStruct *key)
01779 {
01780     Session *hsession = (Session*) s->specific_data;
01781 
01782     if (hsession->state == HANGUL_STATE_HANJA) {
01783        switch (key->keyCode) {
01784        case IM_VK_0:
01785            hangul_lookup_commit_nth(s, 9);
01786            break;
01787        case IM_VK_1:
01788        case IM_VK_2:
01789        case IM_VK_3:
01790        case IM_VK_4:
01791        case IM_VK_5:
01792        case IM_VK_6:
01793        case IM_VK_7:
01794        case IM_VK_8:
01795        case IM_VK_9:
01796            hangul_lookup_commit_nth(s, key->keyCode - IM_VK_1);
01797            break;
01798        case IM_VK_ENTER:
01799            hangul_lookup_commit(s);
01800            break;
01801        case IM_VK_ESCAPE:
01802            hangul_lookup_done(s);
01803            break;
01804        case IM_VK_UP:
01805        case IM_VK_K:
01806            hangul_lookup_prev(s);
01807            break;
01808        case IM_VK_DOWN:
01809        case IM_VK_J:
01810            hangul_lookup_next(s);
01811            break;
01812        case IM_VK_LEFT:
01813        case IM_VK_H:
01814            hangul_lookup_prev_page(s);
01815            break;
01816        case IM_VK_RIGHT:
01817        case IM_VK_L:
01818        case IM_VK_SPACE:
01819            hangul_lookup_next_page(s);
01820            break;
01821        default:
01822            break;
01823        }
01824        return True;
01825     }
01826     
01827     if (hangul_is_candidate_key(key)) {
01828        hangul_lookup_start(s, key);
01829        return True;
01830     }
01831 
01832     /* on shift key we silently ignore it */
01833     if (key->keyCode == IM_VK_SHIFT)
01834        return False;
01835 
01836     /* ignore modifier on keys */
01837     if (key->modifier & (IM_CTRL_MASK | IM_ALT_MASK | IM_META_MASK))
01838        return False;
01839 
01840     if (hsession->composer != NULL)
01841        return hsession->composer(s, key);
01842 
01843     return False;
01844 }
01845 
01846 /* vim: set ts=8 sw=4 : */