textinput/ptihangulcore/src/hangulinputcontext.c
branchRCL_3
changeset 3 f5a1e66df979
equal deleted inserted replaced
0:eb1f2e154e89 3:f5a1e66df979
       
     1 /* libhangul
       
     2  * Copyright (c) 2005,2006 Choe Hwanjin
       
     3  * All rights reserved.
       
     4  * This library is free software; you can redistribute it and/or
       
     5  * modify it under the terms of the GNU Lesser General Public
       
     6  * License as published by the Free Software Foundation; either
       
     7  * version 2.1 of the License, or (at your option) any later version.
       
     8  *
       
     9  * This library is distributed in the hope that it will be useful,
       
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    12  * Lesser General Public License for more details.
       
    13  *
       
    14  * You should have received a copy of the GNU Lesser General Public
       
    15  * License along with this library; if not, write to the Free Software
       
    16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
       
    17  */
       
    18 
       
    19 #ifdef HAVE_CONFIG_H
       
    20 #include <config.h>
       
    21 #endif
       
    22 
       
    23 #include <stdlib.h>
       
    24 #include <string.h>
       
    25 #include <ctype.h>
       
    26 #include <inttypes.h>
       
    27 #include <limits.h>
       
    28 
       
    29 #include "hangul.h"
       
    30 #include "hangulinternals.h"
       
    31 
       
    32 #ifndef TRUE
       
    33 #define TRUE 1
       
    34 #endif
       
    35 
       
    36 #ifndef FALSE
       
    37 #define FALSE 0
       
    38 #endif
       
    39 
       
    40 #define HANGUL_KEYBOARD_TABLE_SIZE 0x80
       
    41 
       
    42 typedef void   (*HangulOnTranslate)  (HangulInputContext*,
       
    43 				      int,
       
    44 				      ucschar*,
       
    45 				      void*);
       
    46 typedef bool   (*HangulOnTransition) (HangulInputContext*,
       
    47 				      ucschar,
       
    48 				      const ucschar*,
       
    49 				      void*);
       
    50 
       
    51 typedef struct _HangulCombinationItem HangulCombinationItem;
       
    52 
       
    53 struct _HangulKeyboard {
       
    54     int type;
       
    55     ucschar* table;
       
    56 };
       
    57 
       
    58 struct _HangulCombinationItem {
       
    59     uint32_t key;
       
    60     ucschar code;
       
    61 };
       
    62 
       
    63 struct _HangulCombination {
       
    64     int size;
       
    65     HangulCombinationItem *table;
       
    66 };
       
    67 
       
    68 struct _HangulBuffer {
       
    69     ucschar choseong;
       
    70     ucschar jungseong;
       
    71     ucschar jongseong;
       
    72 
       
    73     ucschar stack[12];
       
    74     int     index;
       
    75 };
       
    76 
       
    77 struct _HangulInputContext {
       
    78     int type;
       
    79 
       
    80     const HangulKeyboard*    keyboard;
       
    81     const HangulCombination* combination;
       
    82 
       
    83     HangulBuffer buffer;
       
    84     int output_mode;
       
    85 
       
    86     ucschar preedit_string[64];
       
    87     ucschar commit_string[64];
       
    88     ucschar flushed_string[64];
       
    89 
       
    90     HangulOnTranslate   on_translate;
       
    91     void*               on_translate_data;
       
    92 
       
    93     HangulOnTransition  on_transition;
       
    94     void*               on_transition_data;
       
    95 
       
    96     HangulICFilter filter;
       
    97     void *filter_data;
       
    98 
       
    99     unsigned int use_jamo_mode_only : 1;
       
   100 };
       
   101 
       
   102 #include "hangulkeyboard.h"
       
   103 
       
   104 static const HangulKeyboard hangul_keyboard_2 = {
       
   105     HANGUL_KEYBOARD_TYPE_JAMO,
       
   106     (ucschar*)hangul_keyboard_table_2
       
   107 };
       
   108 
       
   109 static const HangulKeyboard hangul_keyboard_32 = {
       
   110     HANGUL_KEYBOARD_TYPE_JASO,
       
   111     (ucschar*)hangul_keyboard_table_32
       
   112 };
       
   113 
       
   114 static const HangulKeyboard hangul_keyboard_390 = {
       
   115     HANGUL_KEYBOARD_TYPE_JASO,
       
   116     (ucschar*)hangul_keyboard_table_390
       
   117 };
       
   118 
       
   119 static const HangulKeyboard hangul_keyboard_3final = {
       
   120     HANGUL_KEYBOARD_TYPE_JASO,
       
   121     (ucschar*)hangul_keyboard_table_3final
       
   122 };
       
   123 
       
   124 static const HangulKeyboard hangul_keyboard_3sun = {
       
   125     HANGUL_KEYBOARD_TYPE_JASO,
       
   126     (ucschar*)hangul_keyboard_table_3sun
       
   127 };
       
   128 
       
   129 static const HangulKeyboard hangul_keyboard_3yet = {
       
   130     HANGUL_KEYBOARD_TYPE_JASO,
       
   131     (ucschar*)hangul_keyboard_table_3yet
       
   132 };
       
   133 
       
   134 static const HangulCombination hangul_combination_default = {
       
   135     N_ELEMENTS(hangul_combination_table_default),
       
   136     (HangulCombinationItem*)hangul_combination_table_default
       
   137 };
       
   138 
       
   139 static const HangulCombination hangul_combination_full = {
       
   140     N_ELEMENTS(hangul_combination_table_full),
       
   141     (HangulCombinationItem*)hangul_combination_table_full
       
   142 };
       
   143 
       
   144 static void    hangul_buffer_push(HangulBuffer *buffer, ucschar ch);
       
   145 static ucschar hangul_buffer_pop (HangulBuffer *buffer);
       
   146 static ucschar hangul_buffer_peek(HangulBuffer *buffer);
       
   147 
       
   148 static void    hangul_buffer_clear(HangulBuffer *buffer);
       
   149 static int     hangul_buffer_get_string(HangulBuffer *buffer, ucschar*buf, int buflen);
       
   150 static int     hangul_buffer_get_jamo_string(HangulBuffer *buffer, ucschar *buf, int buflen);
       
   151 
       
   152 static void    hangul_ic_flush_internal(HangulInputContext *hic);
       
   153 
       
   154 HangulKeyboard*
       
   155 hangul_keyboard_new()
       
   156 {
       
   157     HangulKeyboard *keyboard = malloc(sizeof(HangulKeyboard));
       
   158     if (keyboard != NULL) {
       
   159 	keyboard->table = malloc(sizeof(ucschar) * HANGUL_KEYBOARD_TABLE_SIZE);
       
   160 	if (keyboard->table != NULL) {
       
   161 	    int i;
       
   162 	    for (i = 0; i < HANGUL_KEYBOARD_TABLE_SIZE; i++)
       
   163 		keyboard->table[i] = 0;
       
   164 
       
   165 	    return keyboard;
       
   166 	}
       
   167 	free(keyboard);
       
   168     }
       
   169 
       
   170     return NULL;
       
   171 }
       
   172 
       
   173 static ucschar
       
   174 hangul_keyboard_get_value(const HangulKeyboard *keyboard, int key)
       
   175 {
       
   176     if (keyboard != NULL) {
       
   177 	if (key >= 0 && key < HANGUL_KEYBOARD_TABLE_SIZE)
       
   178 	    return keyboard->table[key];
       
   179     }
       
   180 
       
   181     return 0;
       
   182 }
       
   183 
       
   184 void
       
   185 hangul_keyboard_set_value(HangulKeyboard *keyboard, int key, ucschar value)
       
   186 {
       
   187     if (keyboard != NULL) {
       
   188 	if (key >= 0 && key < N_ELEMENTS(keyboard->table))
       
   189 	    keyboard->table[key] = value;
       
   190     }
       
   191 }
       
   192 
       
   193 static int
       
   194 hangul_keyboard_get_type(const HangulKeyboard *keyboard)
       
   195 {
       
   196     int type = 0;
       
   197     if (keyboard != NULL) {
       
   198 	type = keyboard->type;
       
   199     }
       
   200     return type;
       
   201 }
       
   202 
       
   203 void
       
   204 hangul_keyboard_set_type(HangulKeyboard *keyboard, int type)
       
   205 {
       
   206     if (keyboard != NULL) {
       
   207 	keyboard->type = type;
       
   208     }
       
   209 }
       
   210 
       
   211 void
       
   212 hangul_keyboard_delete(HangulKeyboard *keyboard)
       
   213 {
       
   214     if (keyboard != NULL)
       
   215 	free(keyboard);
       
   216 }
       
   217 
       
   218 HangulCombination*
       
   219 hangul_combination_new()
       
   220 {
       
   221     HangulCombination *combination = malloc(sizeof(HangulCombination));
       
   222     if (combination != NULL) {
       
   223 	combination->size = 0;
       
   224 	combination->table = NULL;
       
   225 	return combination;
       
   226     }
       
   227 
       
   228     return NULL;
       
   229 }
       
   230 
       
   231 void
       
   232 hangul_combination_delete(HangulCombination *combination)
       
   233 {
       
   234     if (combination != NULL) {
       
   235 	if (combination->table != NULL)
       
   236 	    free(combination->table);
       
   237 	free(combination);
       
   238     }
       
   239 }
       
   240 
       
   241 static uint32_t
       
   242 hangul_combination_make_key(ucschar first, ucschar second)
       
   243 {
       
   244     return first << 16 | second;
       
   245 }
       
   246 
       
   247 bool
       
   248 hangul_combination_set_data(HangulCombination* combination, 
       
   249 			    ucschar* first, ucschar* second, ucschar* result,
       
   250 			    unsigned int n)
       
   251 {
       
   252     if (combination == NULL)
       
   253 	return false;
       
   254 
       
   255     if (n == 0 || n > ULONG_MAX / sizeof(HangulCombinationItem))
       
   256 	return false;
       
   257 
       
   258     combination->table = malloc(sizeof(HangulCombinationItem) * n);
       
   259     if (combination->table != NULL) {
       
   260 	int i;
       
   261 
       
   262 	combination->size = n;
       
   263 	for (i = 0; i < n; i++) {
       
   264 	    combination->table[i].key = hangul_combination_make_key(first[i], second[i]);
       
   265 	    combination->table[i].code = result[i];
       
   266 	}
       
   267 	return true;
       
   268     }
       
   269 
       
   270     return false;
       
   271 }
       
   272 
       
   273 static int 
       
   274 hangul_combination_cmp(const void* p1, const void* p2)
       
   275 {
       
   276     const HangulCombinationItem *item1 = p1;
       
   277     const HangulCombinationItem *item2 = p2;
       
   278     return item1->key - item2->key;
       
   279 }
       
   280 
       
   281 ucschar
       
   282 hangul_combination_combine(const HangulCombination* combination,
       
   283 			   ucschar first, ucschar second)
       
   284 {
       
   285     HangulCombinationItem *res;
       
   286     HangulCombinationItem key;
       
   287 
       
   288     if (combination == NULL)
       
   289 	return 0;
       
   290 
       
   291     key.key = hangul_combination_make_key(first, second);
       
   292     res = bsearch(&key, combination->table, combination->size,
       
   293 	          sizeof(combination->table[0]), hangul_combination_cmp);
       
   294     if (res != NULL)
       
   295 	return res->code;
       
   296 
       
   297     return 0;
       
   298 }
       
   299 
       
   300 static bool
       
   301 hangul_buffer_is_empty(HangulBuffer *buffer)
       
   302 {
       
   303     return buffer->choseong == 0 && buffer->jungseong == 0 &&
       
   304 	   buffer->jongseong == 0;
       
   305 }
       
   306 
       
   307 static bool
       
   308 hangul_buffer_has_choseong(HangulBuffer *buffer)
       
   309 {
       
   310     return buffer->choseong != 0;
       
   311 }
       
   312 
       
   313 static bool
       
   314 hangul_buffer_has_jungseong(HangulBuffer *buffer)
       
   315 {
       
   316     return buffer->jungseong != 0;
       
   317 }
       
   318 
       
   319 static bool
       
   320 hangul_buffer_has_jongseong(HangulBuffer *buffer)
       
   321 {
       
   322     return buffer->jongseong != 0;
       
   323 }
       
   324 
       
   325 static void
       
   326 hangul_buffer_push(HangulBuffer *buffer, ucschar ch)
       
   327 {
       
   328     if (hangul_is_choseong(ch)) {
       
   329 	buffer->choseong = ch;
       
   330     } else if (hangul_is_jungseong(ch)) {
       
   331 	buffer->jungseong = ch;
       
   332     } else if (hangul_is_jongseong(ch)) {
       
   333 	buffer->jongseong = ch;
       
   334     } else {
       
   335     }
       
   336 
       
   337     buffer->stack[++buffer->index] = ch;
       
   338 }
       
   339 
       
   340 static ucschar
       
   341 hangul_buffer_pop(HangulBuffer *buffer)
       
   342 {
       
   343     return buffer->stack[buffer->index--];
       
   344 }
       
   345 
       
   346 static ucschar
       
   347 hangul_buffer_peek(HangulBuffer *buffer)
       
   348 {
       
   349     if (buffer->index < 0)
       
   350 	return 0;
       
   351 
       
   352     return buffer->stack[buffer->index];
       
   353 }
       
   354 
       
   355 static void
       
   356 hangul_buffer_clear(HangulBuffer *buffer)
       
   357 {
       
   358     buffer->choseong = 0;
       
   359     buffer->jungseong = 0;
       
   360     buffer->jongseong = 0;
       
   361 
       
   362     buffer->index = -1;
       
   363     buffer->stack[0]  = 0;
       
   364     buffer->stack[1]  = 0;
       
   365     buffer->stack[2]  = 0;
       
   366     buffer->stack[3]  = 0;
       
   367     buffer->stack[4]  = 0;
       
   368     buffer->stack[5]  = 0;
       
   369     buffer->stack[6]  = 0;
       
   370     buffer->stack[7]  = 0;
       
   371     buffer->stack[8]  = 0;
       
   372     buffer->stack[9]  = 0;
       
   373     buffer->stack[10] = 0;
       
   374     buffer->stack[11] = 0;
       
   375 }
       
   376 
       
   377 static int
       
   378 hangul_buffer_get_jamo_string(HangulBuffer *buffer, ucschar *buf, int buflen)
       
   379 {
       
   380     int n = 0;
       
   381 
       
   382     if (buffer->choseong || buffer->jungseong || buffer->jongseong) {
       
   383 	if (buffer->choseong) {
       
   384 	    buf[n++] = buffer->choseong;
       
   385 	} else {
       
   386 	    buf[n++] = HANGUL_CHOSEONG_FILLER;
       
   387 	}
       
   388 	if (buffer->jungseong) {
       
   389 	    buf[n++] = buffer->jungseong;
       
   390 	} else {
       
   391 	    buf[n++] = HANGUL_JUNGSEONG_FILLER;
       
   392 	}
       
   393 	if (buffer->jongseong) {
       
   394 	    buf[n++] = buffer->jongseong;
       
   395 	}
       
   396     }
       
   397 
       
   398     buf[n] = 0;
       
   399 
       
   400     return n;
       
   401 }
       
   402 
       
   403 static int
       
   404 hangul_jaso_to_string(ucschar cho, ucschar jung, ucschar jong,
       
   405 		      ucschar *buf, int len)
       
   406 {
       
   407     ucschar ch = 0;
       
   408     int n = 0;
       
   409 
       
   410     if (cho) {
       
   411 	if (jung) {
       
   412 	    /* have cho, jung, jong or no jong */
       
   413 	    ch = hangul_jaso_to_syllable(cho, jung, jong);
       
   414 	    buf[n++] = ch;
       
   415 	} else {
       
   416 	    if (jong) {
       
   417 		/* have cho, jong */
       
   418 		ch = hangul_jaso_to_jamo(cho);
       
   419 		buf[n++] = ch;
       
   420 		ch = hangul_jaso_to_jamo(jong);
       
   421 		buf[n++] = ch;
       
   422 	    } else {
       
   423 		/* have cho */
       
   424 		ch = hangul_jaso_to_jamo(cho);
       
   425 		buf[n++] = ch;
       
   426 	    }
       
   427 	}
       
   428     } else {
       
   429 	if (jung) {
       
   430 	    if (jong) {
       
   431 		/* have jung, jong */
       
   432 		ch = hangul_jaso_to_jamo(jung);
       
   433 		buf[n++] = ch;
       
   434 		ch = hangul_jaso_to_jamo(jong);
       
   435 		buf[n++] = ch;
       
   436 	    } else {
       
   437 		/* have jung */
       
   438 		ch = hangul_jaso_to_jamo(jung);
       
   439 		buf[n++] = ch;
       
   440 	    }
       
   441 	} else {
       
   442 	    if (jong) { 
       
   443 		/* have jong */
       
   444 		ch = hangul_jaso_to_jamo(jong);
       
   445 		buf[n++] = ch;
       
   446 	    } else {
       
   447 		/* have nothing */
       
   448 		buf[n] = 0;
       
   449 	    }
       
   450 	}
       
   451     }
       
   452     buf[n] = 0;
       
   453 
       
   454     return n;
       
   455 }
       
   456 
       
   457 static int
       
   458 hangul_buffer_get_string(HangulBuffer *buffer, ucschar *buf, int buflen)
       
   459 {
       
   460     return hangul_jaso_to_string(buffer->choseong,
       
   461 				 buffer->jungseong,
       
   462 				 buffer->jongseong,
       
   463 				 buf, buflen);
       
   464 }
       
   465 
       
   466 static bool
       
   467 hangul_buffer_backspace(HangulBuffer *buffer)
       
   468 {
       
   469     if (buffer->index >= 0) {
       
   470 	ucschar ch = hangul_buffer_pop(buffer);
       
   471 	if (ch == 0)
       
   472 	    return false;
       
   473 
       
   474 	if (hangul_is_choseong(ch)) {
       
   475 	    ch = hangul_buffer_peek(buffer);
       
   476 	    buffer->choseong = hangul_is_choseong(ch) ? ch : 0;
       
   477 	    return true;
       
   478 	} else if (hangul_is_jungseong(ch)) {
       
   479 	    ch = hangul_buffer_peek(buffer);
       
   480 	    buffer->jungseong = hangul_is_jungseong(ch) ? ch : 0;
       
   481 	    return true;
       
   482 	} else if (hangul_is_jongseong(ch)) {
       
   483 	    ch = hangul_buffer_peek(buffer);
       
   484 	    buffer->jongseong = hangul_is_jongseong(ch) ? ch : 0;
       
   485 	    return true;
       
   486 	}
       
   487     }
       
   488     return false;
       
   489 }
       
   490 
       
   491 static 
       
   492 #ifndef __SYMBIAN32__
       
   493 inline 
       
   494 #endif
       
   495 bool
       
   496 hangul_ic_push(HangulInputContext *hic, ucschar c)
       
   497 {
       
   498     ucschar buf[64] = { 0, };
       
   499     if (hic->on_transition != NULL) {
       
   500 	ucschar cho, jung, jong;
       
   501 	if (hangul_is_choseong(c)) {
       
   502 	    cho  = c;
       
   503 	    jung = hic->buffer.jungseong;
       
   504 	    jong = hic->buffer.jongseong;
       
   505 	} else if (hangul_is_jungseong(c)) {
       
   506 	    cho  = hic->buffer.choseong;
       
   507 	    jung = c;
       
   508 	    jong = hic->buffer.jongseong;
       
   509 	} else if (hangul_is_jongseong(c)) {
       
   510 	    cho  = hic->buffer.choseong;
       
   511 	    jung = hic->buffer.jungseong;
       
   512 	    jong = c;
       
   513 	} else {
       
   514 	    hangul_ic_flush_internal(hic);
       
   515 	    return false;
       
   516 	}
       
   517 
       
   518 	hangul_jaso_to_string(cho, jung, jong, buf, N_ELEMENTS(buf));
       
   519 	if (!hic->on_transition(hic, c, buf, hic->on_transition_data)) {
       
   520 	    hangul_ic_flush_internal(hic);
       
   521 	    return false;
       
   522 	}
       
   523     } else {
       
   524 	if (!hangul_is_jaso(c)) {
       
   525 	    hangul_ic_flush_internal(hic);
       
   526 	    return false;
       
   527 	}
       
   528     }
       
   529 
       
   530     hangul_buffer_push(&hic->buffer, c);
       
   531     return true;
       
   532 }
       
   533 
       
   534 static 
       
   535 #ifndef __SYMBIAN32__
       
   536 inline 
       
   537 #endif
       
   538 ucschar
       
   539 hangul_ic_pop(HangulInputContext *hic)
       
   540 {
       
   541     return hangul_buffer_pop(&hic->buffer);
       
   542 }
       
   543 
       
   544 static 
       
   545 #ifndef __SYMBIAN32__
       
   546 inline 
       
   547 #endif
       
   548 ucschar
       
   549 hangul_ic_peek(HangulInputContext *hic)
       
   550 {
       
   551     return hangul_buffer_peek(&hic->buffer);
       
   552 }
       
   553 
       
   554 static 
       
   555 #ifndef __SYMBIAN32__
       
   556 inline 
       
   557 #endif
       
   558 void
       
   559 hangul_ic_save_preedit_string(HangulInputContext *hic)
       
   560 {
       
   561     if (hic->output_mode == HANGUL_OUTPUT_JAMO) {
       
   562 	hangul_buffer_get_jamo_string(&hic->buffer,
       
   563 				      hic->preedit_string,
       
   564 				      N_ELEMENTS(hic->preedit_string));
       
   565     } else {
       
   566 	hangul_buffer_get_string(&hic->buffer,
       
   567 				 hic->preedit_string,
       
   568 				 N_ELEMENTS(hic->preedit_string));
       
   569     }
       
   570 }
       
   571 
       
   572 static 
       
   573 #ifndef __SYMBIAN32__
       
   574 inline 
       
   575 #endif
       
   576 void
       
   577 hangul_ic_append_commit_string(HangulInputContext *hic, ucschar ch)
       
   578 {
       
   579     int i;
       
   580 
       
   581     for (i = 0; i < N_ELEMENTS(hic->commit_string); i++) {
       
   582 	if (hic->commit_string[i] == 0)
       
   583 	    break;
       
   584     }
       
   585 
       
   586     if (i + 1 < N_ELEMENTS(hic->commit_string)) {
       
   587 	hic->commit_string[i++] = ch;
       
   588 	hic->commit_string[i] = 0;
       
   589     }
       
   590 }
       
   591 
       
   592 static 
       
   593 #ifndef __SYMBIAN32__
       
   594 inline 
       
   595 #endif
       
   596 void
       
   597 hangul_ic_save_commit_string(HangulInputContext *hic)
       
   598 {
       
   599     ucschar *string = hic->commit_string;
       
   600     int len = N_ELEMENTS(hic->commit_string);
       
   601 
       
   602     while (len > 0) {
       
   603 	if (*string == 0)
       
   604 	    break;
       
   605 	len--;
       
   606 	string++;
       
   607     }
       
   608 
       
   609     if (hic->output_mode == HANGUL_OUTPUT_JAMO) {
       
   610 	hangul_buffer_get_jamo_string(&hic->buffer, string, len);
       
   611     } else {
       
   612 	hangul_buffer_get_string(&hic->buffer, string, len);
       
   613     }
       
   614 
       
   615     hangul_buffer_clear(&hic->buffer);
       
   616 }
       
   617 
       
   618 static bool
       
   619 hangul_ic_process_jamo(HangulInputContext *hic, ucschar ch)
       
   620 {
       
   621     ucschar jong;
       
   622     ucschar combined;
       
   623 
       
   624     if (!hangul_is_jaso(ch) && ch > 0) {
       
   625 	hangul_ic_save_commit_string(hic);
       
   626 	hangul_ic_append_commit_string(hic, ch);
       
   627 	return true;
       
   628     }
       
   629 
       
   630     if (hic->buffer.jongseong) {
       
   631 	if (hangul_is_choseong(ch)) {
       
   632 	    jong = hangul_choseong_to_jongseong(ch);
       
   633 	    combined = hangul_combination_combine(hic->combination,
       
   634 					      hic->buffer.jongseong, jong);
       
   635 	    if (hangul_is_jongseong(combined)) {
       
   636 		if (!hangul_ic_push(hic, combined)) {
       
   637 		    if (!hangul_ic_push(hic, ch)) {
       
   638 			return false;
       
   639 		    }
       
   640 		}
       
   641 	    } else {
       
   642 		hangul_ic_save_commit_string(hic);
       
   643 		if (!hangul_ic_push(hic, ch)) {
       
   644 		    return false;
       
   645 		}
       
   646 	    }
       
   647 	} else if (hangul_is_jungseong(ch)) {
       
   648 	    ucschar pop, peek;
       
   649 	    pop = hangul_ic_pop(hic);
       
   650 	    peek = hangul_ic_peek(hic);
       
   651 
       
   652 	    if (hangul_is_jungseong(peek)) {
       
   653 		hic->buffer.jongseong = 0;
       
   654 		hangul_ic_save_commit_string(hic);
       
   655 		hangul_ic_push(hic, hangul_jongseong_to_choseong(pop));
       
   656 		if (!hangul_ic_push(hic, ch)) {
       
   657 		    return false;
       
   658 		}
       
   659 	    } else {
       
   660 		ucschar choseong = 0, jongseong = 0; 
       
   661 		hangul_jongseong_dicompose(hic->buffer.jongseong,
       
   662 					   &jongseong, &choseong);
       
   663 		hic->buffer.jongseong = jongseong;
       
   664 		hangul_ic_save_commit_string(hic);
       
   665 		hangul_ic_push(hic, choseong);
       
   666 		if (!hangul_ic_push(hic, ch)) {
       
   667 		    return false;
       
   668 		}
       
   669 	    }
       
   670 	} else {
       
   671 	    goto flush;
       
   672 	}
       
   673     } else if (hic->buffer.jungseong) {
       
   674 	if (hangul_is_choseong(ch)) {
       
   675 	    if (hic->buffer.choseong) {
       
   676 		jong = hangul_choseong_to_jongseong(ch);
       
   677 		if (hangul_is_jongseong(jong)) {
       
   678 		    if (!hangul_ic_push(hic, jong)) {
       
   679 			if (!hangul_ic_push(hic, ch)) {
       
   680 			    return false;
       
   681 			}
       
   682 		    }
       
   683 		} else {
       
   684 		    hangul_ic_save_commit_string(hic);
       
   685 		    if (!hangul_ic_push(hic, ch)) {
       
   686 			return false;
       
   687 		    }
       
   688 		}
       
   689 	    } else {
       
   690 #if 1
       
   691         hangul_ic_save_commit_string(hic);
       
   692         if (!hangul_ic_push(hic, ch)) {
       
   693             return false;
       
   694         }
       
   695 #else
       
   696 		if (!hangul_ic_push(hic, ch)) {
       
   697 		    if (!hangul_ic_push(hic, ch)) {
       
   698 			return false;
       
   699 		    }
       
   700 		}
       
   701 #endif
       
   702 	    }
       
   703 	} else if (hangul_is_jungseong(ch)) {
       
   704 	    combined = hangul_combination_combine(hic->combination,
       
   705 						  hic->buffer.jungseong, ch);
       
   706 	    if (hangul_is_jungseong(combined)) {
       
   707 		if (!hangul_ic_push(hic, combined)) {
       
   708 		    return false;
       
   709 		}
       
   710 	    } else {
       
   711 		hangul_ic_save_commit_string(hic);
       
   712 		if (!hangul_ic_push(hic, ch)) {
       
   713 		    return false;
       
   714 		}
       
   715 	    }
       
   716 	} else {
       
   717 	    goto flush;
       
   718 	}
       
   719     } else if (hic->buffer.choseong) {
       
   720 	if (hangul_is_choseong(ch)) {
       
   721 	    combined = hangul_combination_combine(hic->combination,
       
   722 						  hic->buffer.choseong, ch);
       
   723 	    if (!hangul_ic_push(hic, combined)) {
       
   724 		if (!hangul_ic_push(hic, ch)) {
       
   725 		    return false;
       
   726 		}
       
   727 	    }
       
   728 	} else {
       
   729 	    if (!hangul_ic_push(hic, ch)) {
       
   730 		if (!hangul_ic_push(hic, ch)) {
       
   731 		    return false;
       
   732 		}
       
   733 	    }
       
   734 	}
       
   735     } else {
       
   736 	if (!hangul_ic_push(hic, ch)) {
       
   737 	    return false;
       
   738 	}
       
   739     }
       
   740 
       
   741     hangul_ic_save_preedit_string(hic);
       
   742     return true;
       
   743 
       
   744 flush:
       
   745     hangul_ic_flush_internal(hic);
       
   746     return false;
       
   747 }
       
   748 
       
   749 static bool
       
   750 hangul_ic_process_jaso(HangulInputContext *hic, ucschar ch)
       
   751 {
       
   752     if (hangul_is_choseong(ch)) {
       
   753 	if (hic->buffer.choseong == 0) {
       
   754 	    if (!hangul_ic_push(hic, ch)) {
       
   755 		if (!hangul_ic_push(hic, ch)) {
       
   756 		    return false;
       
   757 		}
       
   758 	    }
       
   759 	} else {
       
   760 	    ucschar choseong = 0;
       
   761 	    if (hangul_is_choseong(hangul_ic_peek(hic))) {
       
   762 		choseong = hangul_combination_combine(hic->combination,
       
   763 						  hic->buffer.choseong, ch);
       
   764 	    }
       
   765 	    if (choseong) {
       
   766 		if (!hangul_ic_push(hic, choseong)) {
       
   767 		    if (!hangul_ic_push(hic, choseong)) {
       
   768 			return false;
       
   769 		    }
       
   770 		}
       
   771 	    } else {
       
   772 		hangul_ic_save_commit_string(hic);
       
   773 		if (!hangul_ic_push(hic, ch)) {
       
   774 		    return false;
       
   775 		}
       
   776 	    }
       
   777 	}
       
   778     } else if (hangul_is_jungseong(ch)) {
       
   779 	if (hic->buffer.jungseong == 0) {
       
   780 	    if (!hangul_ic_push(hic, ch)) {
       
   781 		if (!hangul_ic_push(hic, ch)) {
       
   782 		    return false;
       
   783 		}
       
   784 	    }
       
   785 	} else {
       
   786 	    ucschar jungseong = 0;
       
   787 	    if (hangul_is_jungseong(hangul_ic_peek(hic))) {
       
   788 		jungseong = hangul_combination_combine(hic->combination,
       
   789 						 hic->buffer.jungseong, ch);
       
   790 	    }
       
   791 	    if (jungseong) {
       
   792 		if (!hangul_ic_push(hic, jungseong)) {
       
   793 		    if (!hangul_ic_push(hic, jungseong)) {
       
   794 			return false;
       
   795 		    }
       
   796 		}
       
   797 	    } else {
       
   798 		hangul_ic_save_commit_string(hic);
       
   799 		if (!hangul_ic_push(hic, ch)) {
       
   800 		    if (!hangul_ic_push(hic, ch)) {
       
   801 			return false;
       
   802 		    }
       
   803 		}
       
   804 	    }
       
   805 	}
       
   806     } else if (hangul_is_jongseong(ch)) {
       
   807 	if (hic->buffer.jongseong == 0) {
       
   808 	    if (!hangul_ic_push(hic, ch)) {
       
   809 		if (!hangul_ic_push(hic, ch)) {
       
   810 		    return false;
       
   811 		}
       
   812 	    }
       
   813 	} else {
       
   814 	    ucschar jongseong = 0;
       
   815 	    if (hangul_is_jongseong(hangul_ic_peek(hic))) {
       
   816 		jongseong = hangul_combination_combine(hic->combination,
       
   817 						   hic->buffer.jongseong, ch);
       
   818 	    }
       
   819 	    if (jongseong) {
       
   820 		if (!hangul_ic_push(hic, jongseong)) {
       
   821 		    if (!hangul_ic_push(hic, jongseong)) {
       
   822 			return false;
       
   823 		    }
       
   824 		}
       
   825 	    } else {
       
   826 		hangul_ic_save_commit_string(hic);
       
   827 		if (!hangul_ic_push(hic, ch)) {
       
   828 		    if (!hangul_ic_push(hic, ch)) {
       
   829 			return false;
       
   830 		    }
       
   831 		}
       
   832 	    }
       
   833 	}
       
   834     } else if (ch > 0) {
       
   835 	hangul_ic_save_commit_string(hic);
       
   836 	hangul_ic_append_commit_string(hic, ch);
       
   837     } else {
       
   838 	hangul_ic_save_commit_string(hic);
       
   839 	return false;
       
   840     }
       
   841 
       
   842     hangul_ic_save_preedit_string(hic);
       
   843     return true;
       
   844 }
       
   845 
       
   846 bool
       
   847 hangul_ic_process(HangulInputContext *hic, int ascii)
       
   848 {
       
   849     ucschar c;
       
   850 
       
   851     if (hic == NULL)
       
   852 	return false;
       
   853 
       
   854     hic->preedit_string[0] = 0;
       
   855     hic->commit_string[0] = 0;
       
   856 
       
   857     c = hangul_keyboard_get_value(hic->keyboard, ascii);
       
   858     if (hic->on_translate != NULL)
       
   859 	hic->on_translate(hic, ascii, &c, hic->on_translate_data);
       
   860 
       
   861     if (hangul_keyboard_get_type(hic->keyboard) == HANGUL_KEYBOARD_TYPE_JAMO)
       
   862 	return hangul_ic_process_jamo(hic, c);
       
   863     else
       
   864 	return hangul_ic_process_jaso(hic, c);
       
   865 }
       
   866 
       
   867 const ucschar*
       
   868 hangul_ic_get_preedit_string(HangulInputContext *hic)
       
   869 {
       
   870     if (hic == NULL)
       
   871 	return NULL;
       
   872 
       
   873     return hic->preedit_string;
       
   874 }
       
   875 
       
   876 const ucschar*
       
   877 hangul_ic_get_commit_string(HangulInputContext *hic)
       
   878 {
       
   879     if (hic == NULL)
       
   880 	return NULL;
       
   881 
       
   882     return hic->commit_string;
       
   883 }
       
   884 
       
   885 void
       
   886 hangul_ic_reset(HangulInputContext *hic)
       
   887 {
       
   888     if (hic == NULL)
       
   889 	return;
       
   890 
       
   891     hic->preedit_string[0] = 0;
       
   892     hic->commit_string[0] = 0;
       
   893     hic->flushed_string[0] = 0;
       
   894 
       
   895     hangul_buffer_clear(&hic->buffer);
       
   896 }
       
   897 
       
   898 /* append current preedit to the commit buffer.
       
   899  * this function does not clear previously made commit string. */
       
   900 static void
       
   901 hangul_ic_flush_internal(HangulInputContext *hic)
       
   902 {
       
   903     hic->preedit_string[0] = 0;
       
   904 
       
   905     hangul_ic_save_commit_string(hic);
       
   906     hangul_buffer_clear(&hic->buffer);
       
   907 }
       
   908 
       
   909 const ucschar*
       
   910 hangul_ic_flush(HangulInputContext *hic)
       
   911 {
       
   912     if (hic == NULL)
       
   913 	return NULL;
       
   914 
       
   915     // get the remaining string and clear the buffer
       
   916     hic->preedit_string[0] = 0;
       
   917     hic->commit_string[0] = 0;
       
   918     hic->flushed_string[0] = 0;
       
   919 
       
   920     if (hic->output_mode == HANGUL_OUTPUT_JAMO) {
       
   921 	hangul_buffer_get_jamo_string(&hic->buffer, hic->flushed_string,
       
   922 				 N_ELEMENTS(hic->flushed_string));
       
   923     } else {
       
   924 	hangul_buffer_get_string(&hic->buffer, hic->flushed_string,
       
   925 				 N_ELEMENTS(hic->flushed_string));
       
   926     }
       
   927 
       
   928     hangul_buffer_clear(&hic->buffer);
       
   929 
       
   930     return hic->flushed_string;
       
   931 }
       
   932 
       
   933 bool
       
   934 hangul_ic_backspace(HangulInputContext *hic)
       
   935 {
       
   936     int ret;
       
   937 
       
   938     if (hic == NULL)
       
   939 	return false;
       
   940 
       
   941     hic->preedit_string[0] = 0;
       
   942     hic->commit_string[0] = 0;
       
   943 
       
   944     ret = hangul_buffer_backspace(&hic->buffer);
       
   945     if (ret)
       
   946 	hangul_ic_save_preedit_string(hic);
       
   947     return ret;
       
   948 }
       
   949 
       
   950 int
       
   951 hangul_ic_dvorak_to_qwerty(int qwerty)
       
   952 {
       
   953     static const int table[] = {
       
   954 	'!',	/* ! */
       
   955 	'Q',	/* " */
       
   956 	'#',	/* # */
       
   957 	'$',	/* $ */
       
   958 	'%',	/* % */
       
   959 	'&',	/* & */
       
   960 	'q',	/* ' */
       
   961 	'(',	/* ( */
       
   962 	')',	/* ) */
       
   963 	'*',	/* * */
       
   964 	'}',	/* + */
       
   965 	'w',	/* , */
       
   966 	'\'',	/* - */
       
   967 	'e',	/* . */
       
   968 	'[',	/* / */
       
   969 	'0',	/* 0 */
       
   970 	'1',	/* 1 */
       
   971 	'2',	/* 2 */
       
   972 	'3',	/* 3 */
       
   973 	'4',	/* 4 */
       
   974 	'5',	/* 5 */
       
   975 	'6',	/* 6 */
       
   976 	'7',	/* 7 */
       
   977 	'8',	/* 8 */
       
   978 	'9',	/* 9 */
       
   979 	'Z',	/* : */
       
   980 	'z',	/* ; */
       
   981 	'W',	/* < */
       
   982 	']',	/* = */
       
   983 	'E',	/* > */
       
   984 	'{',	/* ? */
       
   985 	'@',	/* @ */
       
   986 	'A',	/* A */
       
   987 	'N',	/* B */
       
   988 	'I',	/* C */
       
   989 	'H',	/* D */
       
   990 	'D',	/* E */
       
   991 	'Y',	/* F */
       
   992 	'U',	/* G */
       
   993 	'J',	/* H */
       
   994 	'G',	/* I */
       
   995 	'C',	/* J */
       
   996 	'V',	/* K */
       
   997 	'P',	/* L */
       
   998 	'M',	/* M */
       
   999 	'L',	/* N */
       
  1000 	'S',	/* O */
       
  1001 	'R',	/* P */
       
  1002 	'X',	/* Q */
       
  1003 	'O',	/* R */
       
  1004 	':',	/* S */
       
  1005 	'K',	/* T */
       
  1006 	'F',	/* U */
       
  1007 	'>',	/* V */
       
  1008 	'<',	/* W */
       
  1009 	'B',	/* X */
       
  1010 	'T',	/* Y */
       
  1011 	'?',	/* Z */
       
  1012 	'-',	/* [ */
       
  1013 	'\\',	/* \ */
       
  1014 	'=',	/* ] */
       
  1015 	'^',	/* ^ */
       
  1016 	'"',	/* _ */
       
  1017 	'`',	/* ` */
       
  1018 	'a',	/* a */
       
  1019 	'n',	/* b */
       
  1020 	'i',	/* c */
       
  1021 	'h',	/* d */
       
  1022 	'd',	/* e */
       
  1023 	'y',	/* f */
       
  1024 	'u',	/* g */
       
  1025 	'j',	/* h */
       
  1026 	'g',	/* i */
       
  1027 	'c',	/* j */
       
  1028 	'v',	/* k */
       
  1029 	'p',	/* l */
       
  1030 	'm',	/* m */
       
  1031 	'l',	/* n */
       
  1032 	's',	/* o */
       
  1033 	'r',	/* p */
       
  1034 	'x',	/* q */
       
  1035 	'o',	/* r */
       
  1036 	';',	/* s */
       
  1037 	'k',	/* t */
       
  1038 	'f',	/* u */
       
  1039 	'.',	/* v */
       
  1040 	',',	/* w */
       
  1041 	'b',	/* x */
       
  1042 	't',	/* y */
       
  1043 	'/',	/* z */
       
  1044 	'_',	/* { */
       
  1045 	'|',	/* | */
       
  1046 	'+',	/* } */
       
  1047 	'~'	/* ~ */
       
  1048     };
       
  1049 
       
  1050     if (qwerty >= '!' && qwerty <= '~')
       
  1051 	return table[qwerty - '!'];
       
  1052 
       
  1053     return qwerty;
       
  1054 }
       
  1055 
       
  1056 bool
       
  1057 hangul_ic_is_empty(HangulInputContext *hic)
       
  1058 {
       
  1059     return hangul_buffer_is_empty(&hic->buffer);
       
  1060 }
       
  1061 
       
  1062 bool
       
  1063 hangul_ic_has_choseong(HangulInputContext *hic)
       
  1064 {
       
  1065     return hangul_buffer_has_choseong(&hic->buffer);
       
  1066 }
       
  1067 
       
  1068 bool
       
  1069 hangul_ic_has_jungseong(HangulInputContext *hic)
       
  1070 {
       
  1071     return hangul_buffer_has_jungseong(&hic->buffer);
       
  1072 }
       
  1073 
       
  1074 bool
       
  1075 hangul_ic_has_jongseong(HangulInputContext *hic)
       
  1076 {
       
  1077     return hangul_buffer_has_jongseong(&hic->buffer);
       
  1078 }
       
  1079 
       
  1080 void
       
  1081 hangul_ic_set_output_mode(HangulInputContext *hic, int mode)
       
  1082 {
       
  1083     if (hic == NULL)
       
  1084 	return;
       
  1085 
       
  1086     if (!hic->use_jamo_mode_only)
       
  1087 	hic->output_mode = mode;
       
  1088 }
       
  1089 
       
  1090 void
       
  1091 hangul_ic_connect_translate (HangulInputContext* hic,
       
  1092                              HangulOnTranslate callback,
       
  1093                              void* user_data)
       
  1094 {
       
  1095     if (hic != NULL) {
       
  1096 	hic->on_translate      = callback;
       
  1097 	hic->on_translate_data = user_data;
       
  1098     }
       
  1099 }
       
  1100 
       
  1101 void
       
  1102 hangul_ic_connect_transition(HangulInputContext* hic,
       
  1103                              HangulOnTransition callback,
       
  1104                              void* user_data)
       
  1105 {
       
  1106     if (hic != NULL) {
       
  1107 	hic->on_transition      = callback;
       
  1108 	hic->on_transition_data = user_data;
       
  1109     }
       
  1110 }
       
  1111 
       
  1112 void hangul_ic_connect_callback(HangulInputContext* hic, const char* event,
       
  1113 				void* callback, void* user_data)
       
  1114 {
       
  1115     if (hic == NULL || event == NULL)
       
  1116 	return;
       
  1117 
       
  1118     if (strcasecmp(event, "translate") == 0) {
       
  1119 	hic->on_translate      = (HangulOnTranslate)callback;
       
  1120 	hic->on_translate_data = user_data;
       
  1121     } else if (strcasecmp(event, "transition") == 0) {
       
  1122 	hic->on_transition      = (HangulOnTransition)callback;
       
  1123 	hic->on_transition_data = user_data;
       
  1124     }
       
  1125 }
       
  1126 
       
  1127 void hangul_ic_set_filter(HangulInputContext *hic,
       
  1128 			  HangulICFilter func, void *user_data)
       
  1129 {
       
  1130     return;
       
  1131 }
       
  1132 
       
  1133 void
       
  1134 hangul_ic_set_keyboard(HangulInputContext *hic, const HangulKeyboard* keyboard)
       
  1135 {
       
  1136     if (hic == NULL || keyboard == NULL)
       
  1137 	return;
       
  1138 
       
  1139     hic->keyboard = keyboard;
       
  1140 }
       
  1141 
       
  1142 void
       
  1143 hangul_ic_select_keyboard(HangulInputContext *hic, const char* id)
       
  1144 {
       
  1145     if (hic == NULL)
       
  1146 	return;
       
  1147 
       
  1148     if (id == NULL)
       
  1149 	id = "2";
       
  1150 
       
  1151     if (strcmp(id, "32") == 0) {
       
  1152 	hic->keyboard = &hangul_keyboard_32;
       
  1153 	hic->combination = &hangul_combination_default;
       
  1154 	hic->output_mode = HANGUL_OUTPUT_SYLLABLE;
       
  1155 	hic->use_jamo_mode_only = FALSE;
       
  1156     } else if (strcmp(id, "39") == 0) {
       
  1157 	hic->keyboard = &hangul_keyboard_390;
       
  1158 	hic->combination = &hangul_combination_default;
       
  1159 	hic->output_mode = HANGUL_OUTPUT_SYLLABLE;
       
  1160 	hic->use_jamo_mode_only = FALSE;
       
  1161     } else if (strcmp(id, "3f") == 0) {
       
  1162 	hic->keyboard = &hangul_keyboard_3final;
       
  1163 	hic->combination = &hangul_combination_default;
       
  1164 	hic->output_mode = HANGUL_OUTPUT_SYLLABLE;
       
  1165 	hic->use_jamo_mode_only = FALSE;
       
  1166     } else if (strcmp(id, "3s") == 0) {
       
  1167 	hic->keyboard = &hangul_keyboard_3sun;
       
  1168 	hic->combination = &hangul_combination_default;
       
  1169 	hic->output_mode = HANGUL_OUTPUT_SYLLABLE;
       
  1170 	hic->use_jamo_mode_only = FALSE;
       
  1171     } else if (strcmp(id, "3y") == 0) {
       
  1172 	hic->keyboard = &hangul_keyboard_3yet;
       
  1173 	hic->combination = &hangul_combination_full;
       
  1174 	hic->output_mode = HANGUL_OUTPUT_JAMO;
       
  1175 	hic->use_jamo_mode_only = TRUE;
       
  1176     } else {
       
  1177 	hic->keyboard = &hangul_keyboard_2;
       
  1178 	hic->combination = &hangul_combination_default;
       
  1179 	hic->output_mode = HANGUL_OUTPUT_SYLLABLE;
       
  1180 	hic->use_jamo_mode_only = FALSE;
       
  1181     }
       
  1182 }
       
  1183 
       
  1184 void
       
  1185 hangul_ic_set_combination(HangulInputContext *hic,
       
  1186 			  const HangulCombination* combination)
       
  1187 {
       
  1188     if (hic == NULL || combination == NULL)
       
  1189 	return;
       
  1190 
       
  1191     hic->combination = combination;
       
  1192 }
       
  1193 
       
  1194 HangulInputContext*
       
  1195 hangul_ic_new(const char* keyboard)
       
  1196 {
       
  1197     HangulInputContext *hic;
       
  1198     
       
  1199     int size=sizeof(HangulInputContext);
       
  1200 
       
  1201     hic = malloc(size);
       
  1202     if (hic == NULL)
       
  1203 	return NULL;
       
  1204 
       
  1205     hic->preedit_string[0] = 0;
       
  1206     hic->commit_string[0] = 0;
       
  1207     hic->flushed_string[0] = 0;
       
  1208 
       
  1209     hic->on_translate      = NULL;
       
  1210     hic->on_translate_data = NULL;
       
  1211 
       
  1212     hic->on_transition      = NULL;
       
  1213     hic->on_transition_data = NULL;
       
  1214 
       
  1215     hic->use_jamo_mode_only = FALSE;
       
  1216 
       
  1217     hangul_ic_set_output_mode(hic, HANGUL_OUTPUT_SYLLABLE);
       
  1218     hangul_ic_select_keyboard(hic, keyboard);
       
  1219 
       
  1220     hangul_buffer_clear(&hic->buffer);
       
  1221 
       
  1222     return hic;
       
  1223 }
       
  1224 
       
  1225 void
       
  1226 hangul_ic_delete(HangulInputContext *hic)
       
  1227 {
       
  1228     if (hic == NULL)
       
  1229 	return;
       
  1230 
       
  1231     free(hic);
       
  1232 }