2 * Copyright (C) 2004 - 2009 Choe Hwanjin
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.
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.
14 * You should have received a copy of the GNU Lesser General Public
15 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
29 #include "hangul-gettext.h"
31 #include "hangulinternals.h"
34 * @defgroup hangulic 한글 입력 기능 구현
36 * @section hangulicusage Hangul Input Context의 사용법
37 * 이 섹션에서는 한글 입력 기능을 구현하는 핵심 기능에 대해 설명한다.
39 * 먼저 preedit string과 commit string 이 두 용어에 대해서 설명하겠다.
40 * 이 두가지 용어는 Unix 계열의 입력기 framework에서 널리 쓰이는 표현이다.
42 * preedit string은 아직 조합중으로 어플리케이션에 완전히 입력되지 않은
43 * 스트링을 가리킨다. 일반적으로 한글 입력기에서는 역상으로 보이고
44 * 일본 중국어 입력기에서는 underline이 붙어 나타난다. 아직 완성이 되지
45 * 않은 스트링이므로 어플리케이션에 전달이 되지 않고 사라질 수도 있다.
47 * commit string은 조합이 완료되어 어플리케이션에 전달되는 스트링이다.
48 * 이 스트링은 실제 어플리케이션의 텍스트로 인식이 되므로 이 이후에는
49 * 더이상 입력기가 관리할 수 있는 데이터가 아니다.
51 * 한글 입력과정은 다음과 같은 과정을 거치게 된다.
52 * 입력된 영문 키를 그에 해당하는 한글 자모로 변환한후 한글 자모를 모아
53 * 하나의 음절을 만든다. 여기까지 이루어지는 과정을 preedit string 형태로
54 * 사용자에게 계속 보이게 하는 것이 필요하다.
55 * 그리고는 한글 음절이 완성되고나면 그 글자를 어플리케이션에 commit
56 * string 형태로 보내여 입력을 완료하는 것이다. 다음 키를 받게 되면
59 * libhangul에서 한글 조합 기능은 @ref HangulInputContext 를 이용해서 구현하게
60 * 되는데 기본 적인 방법은 @ref HangulInputContext 에 사용자로부터의 입력을
61 * 순서대로 전달하면서 그 상태가 바뀜에 따라서 preedit 나 commit 스트링을
64 * 입력 코드들은 GUI 코드와 밀접하게 붙어 있어서 키 이벤트를 받아서
65 * 처리하도록 구현하는 것이 보통이다. 그런데 유닉스에는 많은 입력 프레임웍들이
66 * 난립하고 있는 상황이어서 매 입력 프레임웍마다 한글 조합 루틴을 작성해서
67 * 넣는 것은 비효율적이다. 간단한 API를 구현하여 여러 프레임웍에서 바로
68 * 사용할 수 있도록 구현하는 편이 사용성이 높아지게 된다.
70 * 그래서 libhangul에서는 키 이벤트를 따로 재정의하지 않고 ASCII 코드를
71 * 직접 사용하는 방향으로 재정의된 데이터가 많지 않도록 하였다.
72 * 실제 사용 방법은 말로 설명하는 것보다 샘플 코드를 사용하는 편이
73 * 이해가 빠를 것이다. 그래서 대략적인 진행 과정을 샘플 코드로
76 * 아래 예제는 실제로는 존재하지 않는 GUI 라이브러리 코드를 사용하였다.
77 * 실제 GUI 코드를 사용하면 코드가 너무 길어져서 설명이 어렵고 코드가
78 * 길어지면 핵심을 놓치기 쉽기 때문에 가공의 함수를 사용하였다.
79 * 또한 텍스트의 encoding conversion 관련된 부분도 생략하였다.
80 * 여기서 사용한 가공의 GUI 코드는 TWin으로 시작하게 하였다.
84 HangulInputContext* hic = hangul_ic_new("2");
87 // 아래는 키 입력만 처리하는 이벤트 루프이다.
88 // 실제 GUI코드는 이렇게 단순하진 않지만
89 // 편의상 키 입력만 처리하는 코드로 작성하였다.
91 TWinKeyEvent event = TWinGetKeyEvent(); // 키이벤트를 받는 이런 함수가
95 if (event.isBackspace()) {
96 // backspace를 ascii로 변환하기가 좀 꺼림직해서
97 // libhangul에서는 backspace 처리를 위한
99 res = hangul_ic_backspace(hic);
101 // 키 입력을 해당하는 ascii 코드로 변환한다.
102 // libhangul에서는 이 ascii 코드가 키 이벤트
104 int ascii = event.getAscii();
106 // 키 입력을 받았으면 이것을 hic에 먼저 보낸다.
107 // 그래야 hic가 이 키를 사용할 것인지 아닌지를 판단할 수 있다.
108 // 함수가 true를 리턴하면 이 키를 사용했다는 의미이므로
109 // GUI 코드가 이 키 입력을 프로세싱하지 않도록 해야 한다.
110 // 그렇지 않으면 한 키입력이 두번 프로세싱된다.
111 res = hangul_ic_process(hic, ascii);
114 // hic는 한번 키입력을 받고 나면 내부 상태 변화가 일어나고
115 // 완성된 글자를 어플리케이션에 보내야 하는 상황이 있을 수 있다.
116 // 이것을 HangulInputContext에서는 commit 스트링이 있는지로
117 // 판단한다. commit 스트링을 받아봐서 스트링이 있다면
118 // 그 스트링으로 입력이 완료된 걸로 본다.
119 const ucschar commit;
120 commit = hangul_ic_get_commit_string(hic);
121 if (commit[0] != 0) { // 스트링의 길이를 재서 commit 스트링이 있는지
123 TWinInputUnicodeChars(commit);
126 // 키입력 후에는 preedit string도 역시 변화하게 되는데
127 // 입력기 프레임웍에서는 이 스트링을 화면에 보여주어야
128 // 조합중인 글자가 화면에 표시가 되는 것이다.
129 const ucschar preedit;
130 preedit = hangul_ic_get_preedit_string(hic);
131 // 이 경우에는 스트링의 길이에 관계없이 항상 업데이트를
132 // 해야 한다. 왜냐하면 이전에 조합중이던 글자가 있다가
133 // 조합이 완료되면서 조합중인 상태의 글자가 없어질 수도 있기 때문에
134 // 스트링의 길이에 관계없이 현재 상태의 스트링을 preedit
135 // 스트링으로 보여주면 되는 것이다.
136 TWinUpdatePreeditString(preedit);
138 // 위 두작업이 끝난후에는 키 이벤트를 계속 프로세싱해야 하는지
140 // hic가 키 이벤트를 사용하지 않았다면 기본 GUI 코드에 계속해서
141 // 키 이벤트 프로세싱을 진행하도록 해야 한다.
143 TWinForwardKeyEventToUI(ascii);
145 ascii = GetKeyEvent();
148 hangul_ic_delete(hic);
154 * @file hangulinputcontext.c
159 * @typedef HangulInputContext
160 * @brief 한글 입력 상태를 관리하기 위한 오브젝트
162 * libhangul에서 제공하는 한글 조합 루틴에서 상태 정보를 저장하는 opaque
163 * 데이타 오브젝트이다. 이 오브젝트에 키입력 정보를 순차적으로 보내주면서
164 * preedit 스트링이나, commit 스트링을 받아서 처리하면 한글 입력 기능을
166 * 내부의 데이터 멤버는 공개되어 있지 않다. 각각의 멤버는 accessor 함수로만
178 #define HANGUL_KEYBOARD_TABLE_SIZE 0x80
180 typedef void (*HangulOnTranslate) (HangulInputContext*,
184 typedef bool (*HangulOnTransition) (HangulInputContext*,
189 typedef struct _HangulCombinationItem HangulCombinationItem;
191 struct _HangulKeyboard {
195 const ucschar* table;
196 const HangulCombination* combination;
199 struct _HangulCombinationItem {
204 struct _HangulCombination {
206 HangulCombinationItem *table;
209 struct _HangulBuffer {
218 struct _HangulInputContext {
221 const HangulKeyboard* keyboard;
226 ucschar preedit_string[64];
227 ucschar commit_string[64];
228 ucschar flushed_string[64];
230 HangulOnTranslate on_translate;
231 void* on_translate_data;
233 HangulOnTransition on_transition;
234 void* on_transition_data;
236 unsigned int use_jamo_mode_only : 1;
239 #include "hangulkeyboard.h"
241 static const HangulCombination hangul_combination_default = {
242 N_ELEMENTS(hangul_combination_table_default),
243 (HangulCombinationItem*)hangul_combination_table_default
246 static const HangulCombination hangul_combination_romaja = {
247 N_ELEMENTS(hangul_combination_table_romaja),
248 (HangulCombinationItem*)hangul_combination_table_romaja
251 static const HangulCombination hangul_combination_full = {
252 N_ELEMENTS(hangul_combination_table_full),
253 (HangulCombinationItem*)hangul_combination_table_full
256 static const HangulCombination hangul_combination_ahn = {
257 N_ELEMENTS(hangul_combination_table_ahn),
258 (HangulCombinationItem*)hangul_combination_table_ahn
261 static const HangulKeyboard hangul_keyboard_2 = {
262 HANGUL_KEYBOARD_TYPE_JAMO,
265 (ucschar*)hangul_keyboard_table_2,
266 &hangul_combination_default
269 static const HangulKeyboard hangul_keyboard_2y = {
270 HANGUL_KEYBOARD_TYPE_JAMO,
272 N_("Dubeolsik Yetgeul"),
273 (ucschar*)hangul_keyboard_table_2y,
274 &hangul_combination_full
277 static const HangulKeyboard hangul_keyboard_32 = {
278 HANGUL_KEYBOARD_TYPE_JASO,
280 N_("Sebeolsik Dubeol Layout"),
281 (ucschar*)hangul_keyboard_table_32,
282 &hangul_combination_default
285 static const HangulKeyboard hangul_keyboard_390 = {
286 HANGUL_KEYBOARD_TYPE_JASO,
289 (ucschar*)hangul_keyboard_table_390,
290 &hangul_combination_default
293 static const HangulKeyboard hangul_keyboard_3final = {
294 HANGUL_KEYBOARD_TYPE_JASO,
296 N_("Sebeolsik Final"),
297 (ucschar*)hangul_keyboard_table_3final,
298 &hangul_combination_default
301 static const HangulKeyboard hangul_keyboard_3sun = {
302 HANGUL_KEYBOARD_TYPE_JASO,
304 N_("Sebeolsik Noshift"),
305 (ucschar*)hangul_keyboard_table_3sun,
306 &hangul_combination_default
309 static const HangulKeyboard hangul_keyboard_3yet = {
310 HANGUL_KEYBOARD_TYPE_JASO,
312 N_("Sebeolsik Yetgeul"),
313 (ucschar*)hangul_keyboard_table_3yet,
314 &hangul_combination_full
317 static const HangulKeyboard hangul_keyboard_romaja = {
318 HANGUL_KEYBOARD_TYPE_ROMAJA,
321 (ucschar*)hangul_keyboard_table_romaja,
322 &hangul_combination_romaja
325 static const HangulKeyboard hangul_keyboard_ahn = {
326 HANGUL_KEYBOARD_TYPE_JASO,
329 (ucschar*)hangul_keyboard_table_ahn,
330 &hangul_combination_ahn
333 static const HangulKeyboard* hangul_keyboards[] = {
336 &hangul_keyboard_390,
337 &hangul_keyboard_3final,
338 &hangul_keyboard_3sun,
339 &hangul_keyboard_3yet,
341 &hangul_keyboard_romaja,
342 &hangul_keyboard_ahn,
346 static void hangul_buffer_push(HangulBuffer *buffer, ucschar ch);
347 static ucschar hangul_buffer_pop (HangulBuffer *buffer);
348 static ucschar hangul_buffer_peek(HangulBuffer *buffer);
350 static void hangul_buffer_clear(HangulBuffer *buffer);
351 static int hangul_buffer_get_string(HangulBuffer *buffer, ucschar*buf, int buflen);
352 static int hangul_buffer_get_jamo_string(HangulBuffer *buffer, ucschar *buf, int buflen);
354 static void hangul_ic_flush_internal(HangulInputContext *hic);
357 hangul_keyboard_new()
359 HangulKeyboard *keyboard = malloc(sizeof(HangulKeyboard));
360 if (keyboard != NULL) {
361 ucschar* table = malloc(sizeof(ucschar) * HANGUL_KEYBOARD_TABLE_SIZE);
364 for (i = 0; i < HANGUL_KEYBOARD_TABLE_SIZE; i++)
367 keyboard->table = table;
377 hangul_keyboard_get_value(const HangulKeyboard *keyboard, int key)
379 if (keyboard != NULL) {
380 if (key >= 0 && key < HANGUL_KEYBOARD_TABLE_SIZE)
381 return keyboard->table[key];
388 hangul_keyboard_set_value(HangulKeyboard *keyboard, int key, ucschar value)
390 if (keyboard != NULL) {
391 if (key >= 0 && key < HANGUL_KEYBOARD_TABLE_SIZE) {
392 ucschar* table = (ucschar*)keyboard->table;
399 hangul_keyboard_get_type(const HangulKeyboard *keyboard)
402 if (keyboard != NULL) {
403 type = keyboard->type;
409 hangul_keyboard_set_type(HangulKeyboard *keyboard, int type)
411 if (keyboard != NULL) {
412 keyboard->type = type;
417 hangul_keyboard_delete(HangulKeyboard *keyboard)
419 if (keyboard != NULL)
424 hangul_combination_new()
426 HangulCombination *combination = malloc(sizeof(HangulCombination));
427 if (combination != NULL) {
428 combination->size = 0;
429 combination->table = NULL;
437 hangul_combination_delete(HangulCombination *combination)
439 if (combination != NULL) {
440 if (combination->table != NULL)
441 free(combination->table);
447 hangul_combination_make_key(ucschar first, ucschar second)
449 return first << 16 | second;
453 hangul_combination_set_data(HangulCombination* combination,
454 ucschar* first, ucschar* second, ucschar* result,
457 if (combination == NULL)
460 if (n == 0 || n > ULONG_MAX / sizeof(HangulCombinationItem))
463 combination->table = malloc(sizeof(HangulCombinationItem) * n);
464 if (combination->table != NULL) {
467 combination->size = n;
468 for (i = 0; i < n; i++) {
469 combination->table[i].key = hangul_combination_make_key(first[i], second[i]);
470 combination->table[i].code = result[i];
479 hangul_combination_cmp(const void* p1, const void* p2)
481 const HangulCombinationItem *item1 = p1;
482 const HangulCombinationItem *item2 = p2;
484 /* key는 unsigned int이므로 단순히 빼서 리턴하면 안된다.
485 * 두 수의 차가 큰 경우 int로 변환하면서 음수가 될 수 있다. */
486 if (item1->key < item2->key)
488 else if (item1->key > item2->key)
495 hangul_combination_combine(const HangulCombination* combination,
496 ucschar first, ucschar second)
498 HangulCombinationItem *res;
499 HangulCombinationItem key;
501 if (combination == NULL)
504 key.key = hangul_combination_make_key(first, second);
505 res = bsearch(&key, combination->table, combination->size,
506 sizeof(combination->table[0]), hangul_combination_cmp);
514 hangul_buffer_is_empty(HangulBuffer *buffer)
516 return buffer->choseong == 0 && buffer->jungseong == 0 &&
517 buffer->jongseong == 0;
521 hangul_buffer_has_choseong(HangulBuffer *buffer)
523 return buffer->choseong != 0;
527 hangul_buffer_has_jungseong(HangulBuffer *buffer)
529 return buffer->jungseong != 0;
533 hangul_buffer_has_jongseong(HangulBuffer *buffer)
535 return buffer->jongseong != 0;
539 hangul_buffer_push(HangulBuffer *buffer, ucschar ch)
541 if (hangul_is_choseong(ch)) {
542 buffer->choseong = ch;
543 } else if (hangul_is_jungseong(ch)) {
544 buffer->jungseong = ch;
545 } else if (hangul_is_jongseong(ch)) {
546 buffer->jongseong = ch;
550 buffer->stack[++buffer->index] = ch;
554 hangul_buffer_pop(HangulBuffer *buffer)
556 return buffer->stack[buffer->index--];
560 hangul_buffer_peek(HangulBuffer *buffer)
562 if (buffer->index < 0)
565 return buffer->stack[buffer->index];
569 hangul_buffer_clear(HangulBuffer *buffer)
571 buffer->choseong = 0;
572 buffer->jungseong = 0;
573 buffer->jongseong = 0;
576 buffer->stack[0] = 0;
577 buffer->stack[1] = 0;
578 buffer->stack[2] = 0;
579 buffer->stack[3] = 0;
580 buffer->stack[4] = 0;
581 buffer->stack[5] = 0;
582 buffer->stack[6] = 0;
583 buffer->stack[7] = 0;
584 buffer->stack[8] = 0;
585 buffer->stack[9] = 0;
586 buffer->stack[10] = 0;
587 buffer->stack[11] = 0;
591 hangul_buffer_get_jamo_string(HangulBuffer *buffer, ucschar *buf, int buflen)
595 if (buffer->choseong || buffer->jungseong || buffer->jongseong) {
596 if (buffer->choseong) {
597 buf[n++] = buffer->choseong;
599 buf[n++] = HANGUL_CHOSEONG_FILLER;
601 if (buffer->jungseong) {
602 buf[n++] = buffer->jungseong;
604 buf[n++] = HANGUL_JUNGSEONG_FILLER;
606 if (buffer->jongseong) {
607 buf[n++] = buffer->jongseong;
617 hangul_jaso_to_string(ucschar cho, ucschar jung, ucschar jong,
618 ucschar *buf, int len)
625 /* have cho, jung, jong or no jong */
626 ch = hangul_jamo_to_syllable(cho, jung, jong);
630 /* 한글 음절로 표현 불가능한 경우 */
640 buf[n++] = HANGUL_JUNGSEONG_FILLER;
644 ch = hangul_jamo_to_cjamo(cho);
645 if (hangul_is_cjamo(ch)) {
649 buf[n++] = HANGUL_JUNGSEONG_FILLER;
656 /* have jung, jong */
657 buf[n++] = HANGUL_CHOSEONG_FILLER;
662 ch = hangul_jamo_to_cjamo(jung);
663 if (hangul_is_cjamo(ch)) {
666 buf[n++] = HANGUL_CHOSEONG_FILLER;
673 ch = hangul_jamo_to_cjamo(jong);
674 if (hangul_is_cjamo(ch)) {
677 buf[n++] = HANGUL_CHOSEONG_FILLER;
678 buf[n++] = HANGUL_JUNGSEONG_FILLER;
693 hangul_buffer_get_string(HangulBuffer *buffer, ucschar *buf, int buflen)
695 return hangul_jaso_to_string(buffer->choseong,
702 hangul_buffer_backspace(HangulBuffer *buffer)
704 if (buffer->index >= 0) {
705 ucschar ch = hangul_buffer_pop(buffer);
709 if (buffer->index >= 0) {
710 if (hangul_is_choseong(ch)) {
711 ch = hangul_buffer_peek(buffer);
712 buffer->choseong = hangul_is_choseong(ch) ? ch : 0;
714 } else if (hangul_is_jungseong(ch)) {
715 ch = hangul_buffer_peek(buffer);
716 buffer->jungseong = hangul_is_jungseong(ch) ? ch : 0;
718 } else if (hangul_is_jongseong(ch)) {
719 ch = hangul_buffer_peek(buffer);
720 buffer->jongseong = hangul_is_jongseong(ch) ? ch : 0;
724 buffer->choseong = 0;
725 buffer->jungseong = 0;
726 buffer->jongseong = 0;
734 hangul_ic_push(HangulInputContext *hic, ucschar c)
736 ucschar buf[64] = { 0, };
737 if (hic->on_transition != NULL) {
738 ucschar cho, jung, jong;
739 if (hangul_is_choseong(c)) {
741 jung = hic->buffer.jungseong;
742 jong = hic->buffer.jongseong;
743 } else if (hangul_is_jungseong(c)) {
744 cho = hic->buffer.choseong;
746 jong = hic->buffer.jongseong;
747 } else if (hangul_is_jongseong(c)) {
748 cho = hic->buffer.choseong;
749 jung = hic->buffer.jungseong;
752 hangul_ic_flush_internal(hic);
756 hangul_jaso_to_string(cho, jung, jong, buf, N_ELEMENTS(buf));
757 if (!hic->on_transition(hic, c, buf, hic->on_transition_data)) {
758 hangul_ic_flush_internal(hic);
762 if (!hangul_is_jamo(c)) {
763 hangul_ic_flush_internal(hic);
768 hangul_buffer_push(&hic->buffer, c);
772 static inline ucschar
773 hangul_ic_pop(HangulInputContext *hic)
775 return hangul_buffer_pop(&hic->buffer);
778 static inline ucschar
779 hangul_ic_peek(HangulInputContext *hic)
781 return hangul_buffer_peek(&hic->buffer);
785 hangul_ic_save_preedit_string(HangulInputContext *hic)
787 if (hic->output_mode == HANGUL_OUTPUT_JAMO) {
788 hangul_buffer_get_jamo_string(&hic->buffer,
790 N_ELEMENTS(hic->preedit_string));
792 hangul_buffer_get_string(&hic->buffer,
794 N_ELEMENTS(hic->preedit_string));
799 hangul_ic_append_commit_string(HangulInputContext *hic, ucschar ch)
803 for (i = 0; i < N_ELEMENTS(hic->commit_string); i++) {
804 if (hic->commit_string[i] == 0)
808 if (i + 1 < N_ELEMENTS(hic->commit_string)) {
809 hic->commit_string[i++] = ch;
810 hic->commit_string[i] = 0;
815 hangul_ic_save_commit_string(HangulInputContext *hic)
817 ucschar *string = hic->commit_string;
818 int len = N_ELEMENTS(hic->commit_string);
827 if (hic->output_mode == HANGUL_OUTPUT_JAMO) {
828 hangul_buffer_get_jamo_string(&hic->buffer, string, len);
830 hangul_buffer_get_string(&hic->buffer, string, len);
833 hangul_buffer_clear(&hic->buffer);
837 hangul_ic_choseong_to_jongseong(HangulInputContext* hic, ucschar cho)
839 ucschar jong = hangul_choseong_to_jongseong(cho);
840 if (hangul_is_jongseong_conjoinable(jong)) {
843 /* 옛글 조합 규칙을 사용하는 자판의 경우에는 종성이 conjoinable
845 if (hic->keyboard->combination == &hangul_combination_full) {
854 hangul_ic_process_jamo(HangulInputContext *hic, ucschar ch)
859 if (!hangul_is_jamo(ch) && ch > 0) {
860 hangul_ic_save_commit_string(hic);
861 hangul_ic_append_commit_string(hic, ch);
865 if (hic->buffer.jongseong) {
866 if (hangul_is_choseong(ch)) {
867 jong = hangul_ic_choseong_to_jongseong(hic, ch);
868 combined = hangul_combination_combine(hic->keyboard->combination,
869 hic->buffer.jongseong, jong);
870 if (hangul_is_jongseong(combined)) {
871 if (!hangul_ic_push(hic, combined)) {
872 if (!hangul_ic_push(hic, ch)) {
877 hangul_ic_save_commit_string(hic);
878 if (!hangul_ic_push(hic, ch)) {
882 } else if (hangul_is_jungseong(ch)) {
884 pop = hangul_ic_pop(hic);
885 peek = hangul_ic_peek(hic);
887 if (hangul_is_jongseong(peek)) {
888 ucschar choseong = hangul_jongseong_get_diff(peek,
889 hic->buffer.jongseong);
891 hangul_ic_save_commit_string(hic);
892 if (!hangul_ic_push(hic, ch)) {
896 hic->buffer.jongseong = peek;
897 hangul_ic_save_commit_string(hic);
898 hangul_ic_push(hic, choseong);
899 if (!hangul_ic_push(hic, ch)) {
904 hic->buffer.jongseong = 0;
905 hangul_ic_save_commit_string(hic);
906 hangul_ic_push(hic, hangul_jongseong_to_choseong(pop));
907 if (!hangul_ic_push(hic, ch)) {
914 } else if (hic->buffer.jungseong) {
915 if (hangul_is_choseong(ch)) {
916 if (hic->buffer.choseong) {
917 jong = hangul_ic_choseong_to_jongseong(hic, ch);
918 if (hangul_is_jongseong(jong)) {
919 if (!hangul_ic_push(hic, jong)) {
920 if (!hangul_ic_push(hic, ch)) {
925 hangul_ic_save_commit_string(hic);
926 if (!hangul_ic_push(hic, ch)) {
931 if (!hangul_ic_push(hic, ch)) {
932 if (!hangul_ic_push(hic, ch)) {
937 } else if (hangul_is_jungseong(ch)) {
938 combined = hangul_combination_combine(hic->keyboard->combination,
939 hic->buffer.jungseong, ch);
940 if (hangul_is_jungseong(combined)) {
941 if (!hangul_ic_push(hic, combined)) {
945 hangul_ic_save_commit_string(hic);
946 if (!hangul_ic_push(hic, ch)) {
953 } else if (hic->buffer.choseong) {
954 if (hangul_is_choseong(ch)) {
955 combined = hangul_combination_combine(hic->keyboard->combination,
956 hic->buffer.choseong, ch);
957 if (!hangul_ic_push(hic, combined)) {
958 if (!hangul_ic_push(hic, ch)) {
963 if (!hangul_ic_push(hic, ch)) {
964 if (!hangul_ic_push(hic, ch)) {
970 if (!hangul_ic_push(hic, ch)) {
975 hangul_ic_save_preedit_string(hic);
979 hangul_ic_flush_internal(hic);
984 hangul_ic_process_jaso(HangulInputContext *hic, ucschar ch)
986 if (hangul_is_choseong(ch)) {
987 if (hic->buffer.choseong == 0) {
988 if (!hangul_ic_push(hic, ch)) {
989 if (!hangul_ic_push(hic, ch)) {
994 ucschar choseong = 0;
995 if (hangul_is_choseong(hangul_ic_peek(hic))) {
996 choseong = hangul_combination_combine(hic->keyboard->combination,
997 hic->buffer.choseong, ch);
1000 if (!hangul_ic_push(hic, choseong)) {
1001 if (!hangul_ic_push(hic, choseong)) {
1006 hangul_ic_save_commit_string(hic);
1007 if (!hangul_ic_push(hic, ch)) {
1012 } else if (hangul_is_jungseong(ch)) {
1013 if (hic->buffer.jungseong == 0) {
1014 if (!hangul_ic_push(hic, ch)) {
1015 if (!hangul_ic_push(hic, ch)) {
1020 ucschar jungseong = 0;
1021 if (hangul_is_jungseong(hangul_ic_peek(hic))) {
1022 jungseong = hangul_combination_combine(hic->keyboard->combination,
1023 hic->buffer.jungseong, ch);
1026 if (!hangul_ic_push(hic, jungseong)) {
1027 if (!hangul_ic_push(hic, jungseong)) {
1032 hangul_ic_save_commit_string(hic);
1033 if (!hangul_ic_push(hic, ch)) {
1034 if (!hangul_ic_push(hic, ch)) {
1040 } else if (hangul_is_jongseong(ch)) {
1041 if (hic->buffer.jongseong == 0) {
1042 if (!hangul_ic_push(hic, ch)) {
1043 if (!hangul_ic_push(hic, ch)) {
1048 ucschar jongseong = 0;
1049 if (hangul_is_jongseong(hangul_ic_peek(hic))) {
1050 jongseong = hangul_combination_combine(hic->keyboard->combination,
1051 hic->buffer.jongseong, ch);
1054 if (!hangul_ic_push(hic, jongseong)) {
1055 if (!hangul_ic_push(hic, jongseong)) {
1060 hangul_ic_save_commit_string(hic);
1061 if (!hangul_ic_push(hic, ch)) {
1062 if (!hangul_ic_push(hic, ch)) {
1068 } else if (ch > 0) {
1069 hangul_ic_save_commit_string(hic);
1070 hangul_ic_append_commit_string(hic, ch);
1072 hangul_ic_save_commit_string(hic);
1076 hangul_ic_save_preedit_string(hic);
1081 hangul_ic_process_romaja(HangulInputContext *hic, int ascii, ucschar ch)
1086 if (!hangul_is_jamo(ch) && ch > 0) {
1087 hangul_ic_save_commit_string(hic);
1088 hangul_ic_append_commit_string(hic, ch);
1092 if (isupper(ascii)) {
1093 hangul_ic_save_commit_string(hic);
1096 if (hic->buffer.jongseong) {
1097 if (ascii == 'x' || ascii == 'X') {
1099 hangul_ic_save_commit_string(hic);
1100 if (!hangul_ic_push(hic, ch)) {
1103 } else if (hangul_is_choseong(ch) || hangul_is_jongseong(ch)) {
1104 if (hangul_is_jongseong(ch))
1107 jong = hangul_ic_choseong_to_jongseong(hic, ch);
1108 combined = hangul_combination_combine(hic->keyboard->combination,
1109 hic->buffer.jongseong, jong);
1110 if (hangul_is_jongseong(combined)) {
1111 if (!hangul_ic_push(hic, combined)) {
1112 if (!hangul_ic_push(hic, ch)) {
1117 hangul_ic_save_commit_string(hic);
1118 if (!hangul_ic_push(hic, ch)) {
1122 } else if (hangul_is_jungseong(ch)) {
1123 if (hic->buffer.jongseong == 0x11bc) {
1124 hangul_ic_save_commit_string(hic);
1125 hic->buffer.choseong = 0x110b;
1126 hangul_ic_push(hic, ch);
1129 pop = hangul_ic_pop(hic);
1130 peek = hangul_ic_peek(hic);
1132 if (hangul_is_jungseong(peek)) {
1133 if (pop == 0x11aa) {
1134 hic->buffer.jongseong = 0x11a8;
1137 hic->buffer.jongseong = 0;
1139 hangul_ic_save_commit_string(hic);
1140 hangul_ic_push(hic, hangul_jongseong_to_choseong(pop));
1141 if (!hangul_ic_push(hic, ch)) {
1145 ucschar choseong = 0, jongseong = 0;
1146 hangul_jongseong_decompose(hic->buffer.jongseong,
1147 &jongseong, &choseong);
1148 hic->buffer.jongseong = jongseong;
1149 hangul_ic_save_commit_string(hic);
1150 hangul_ic_push(hic, choseong);
1151 if (!hangul_ic_push(hic, ch)) {
1159 } else if (hic->buffer.jungseong) {
1160 if (hangul_is_choseong(ch)) {
1161 if (hic->buffer.choseong) {
1162 jong = hangul_ic_choseong_to_jongseong(hic, ch);
1163 if (hangul_is_jongseong(jong)) {
1164 if (!hangul_ic_push(hic, jong)) {
1165 if (!hangul_ic_push(hic, ch)) {
1170 hangul_ic_save_commit_string(hic);
1171 if (!hangul_ic_push(hic, ch)) {
1176 if (!hangul_ic_push(hic, ch)) {
1177 if (!hangul_ic_push(hic, ch)) {
1182 } else if (hangul_is_jungseong(ch)) {
1183 combined = hangul_combination_combine(hic->keyboard->combination,
1184 hic->buffer.jungseong, ch);
1185 if (hangul_is_jungseong(combined)) {
1186 if (!hangul_ic_push(hic, combined)) {
1190 hangul_ic_save_commit_string(hic);
1191 hic->buffer.choseong = 0x110b;
1192 if (!hangul_ic_push(hic, ch)) {
1196 } else if (hangul_is_jongseong(ch)) {
1197 if (!hangul_ic_push(hic, ch)) {
1198 if (!hangul_ic_push(hic, ch)) {
1205 } else if (hic->buffer.choseong) {
1206 if (hangul_is_choseong(ch)) {
1207 combined = hangul_combination_combine(hic->keyboard->combination,
1208 hic->buffer.choseong, ch);
1209 if (combined == 0) {
1210 hic->buffer.jungseong = 0x1173;
1211 hangul_ic_flush_internal(hic);
1212 if (!hangul_ic_push(hic, ch)) {
1216 if (!hangul_ic_push(hic, combined)) {
1217 if (!hangul_ic_push(hic, ch)) {
1222 } else if (hangul_is_jongseong(ch)) {
1223 hic->buffer.jungseong = 0x1173;
1224 hangul_ic_save_commit_string(hic);
1225 if (ascii == 'x' || ascii == 'X')
1227 if (!hangul_ic_push(hic, ch)) {
1231 if (!hangul_ic_push(hic, ch)) {
1232 if (!hangul_ic_push(hic, ch)) {
1238 if (ascii == 'x' || ascii == 'X') {
1242 if (!hangul_ic_push(hic, ch)) {
1245 if (hic->buffer.choseong == 0 && hic->buffer.jungseong != 0)
1246 hic->buffer.choseong = 0x110b;
1250 hangul_ic_save_preedit_string(hic);
1254 hangul_ic_flush_internal(hic);
1260 * @brief 키 입력을 처리하여 실제로 한글 조합을 하는 함수
1261 * @param hic @ref HangulInputContext 오브젝트
1262 * @param ascii 키 이벤트
1263 * @return @ref HangulInputContext 가 이 키를 사용했으면 true,
1266 * ascii 값으로 주어진 키 이벤트를 받아서 내부의 한글 조합 상태를
1267 * 변화시키고, preedit, commit 스트링을 저장한다.
1269 * libhangul의 키 이벤트 프로세스는 ASCII 코드 값을 기준으로 처리한다.
1270 * 이 키 값은 US Qwerty 자판 배열에서의 키 값에 해당한다.
1271 * 따라서 유럽어 자판을 사용하는 경우에는 해당 키의 ASCII 코드를 직접
1272 * 전달하면 안되고, 그 키가 US Qwerty 자판이었을 경우에 발생할 수 있는
1273 * ASCII 코드 값을 주어야 한다.
1274 * 또한 ASCII 코드 이므로 Shift 상태는 대문자로 전달이 된다.
1275 * Capslock이 눌린 경우에는 대소문자를 뒤바꾸어 보내주지 않으면
1276 * 마치 Shift가 눌린 것 처럼 동작할 수 있으므로 주의한다.
1277 * preedit, commit 스트링은 hangul_ic_get_preedit_string(),
1278 * hangul_ic_get_commit_string() 함수를 이용하여 구할 수 있다.
1280 * 이 함수의 사용법에 대한 설명은 @ref hangulicusage 부분을 참조한다.
1282 * @remarks 이 함수는 @ref HangulInputContext 의 상태를 변화 시킨다.
1285 hangul_ic_process(HangulInputContext *hic, int ascii)
1292 hic->preedit_string[0] = 0;
1293 hic->commit_string[0] = 0;
1295 c = hangul_keyboard_get_value(hic->keyboard, ascii);
1296 if (hic->on_translate != NULL)
1297 hic->on_translate(hic, ascii, &c, hic->on_translate_data);
1299 if (hangul_keyboard_get_type(hic->keyboard) == HANGUL_KEYBOARD_TYPE_JAMO)
1300 return hangul_ic_process_jamo(hic, c);
1301 else if (hangul_keyboard_get_type(hic->keyboard) == HANGUL_KEYBOARD_TYPE_JASO)
1302 return hangul_ic_process_jaso(hic, c);
1304 return hangul_ic_process_romaja(hic, ascii, c);
1309 * @brief 현재 상태의 preedit string을 구하는 함수
1310 * @param hic preedit string을 구하고자하는 입력 상태 object
1311 * @return UCS4 preedit 스트링, 이 스트링은 @a hic 내부의 데이터이므로
1312 * 수정하거나 free해서는 안된다.
1314 * 이 함수는 @a hic 내부의 현재 상태의 preedit string을 리턴한다.
1315 * 따라서 hic가 다른 키 이벤트를 처리하고 나면 그 내용이 바뀔 수 있다.
1317 * @remarks 이 함수는 @ref HangulInputContext 의 상태를 변화 시키지 않는다.
1320 hangul_ic_get_preedit_string(HangulInputContext *hic)
1325 return hic->preedit_string;
1330 * @brief 현재 상태의 commit string을 구하는 함수
1331 * @param hic commit string을 구하고자하는 입력 상태 object
1332 * @return UCS4 commit 스트링, 이 스트링은 @a hic 내부의 데이터이므로
1333 * 수정하거나 free해서는 안된다.
1335 * 이 함수는 @a hic 내부의 현재 상태의 commit string을 리턴한다.
1336 * 따라서 hic가 다른 키 이벤트를 처리하고 나면 그 내용이 바뀔 수 있다.
1338 * @remarks 이 함수는 @ref HangulInputContext 의 상태를 변화 시키지 않는다.
1341 hangul_ic_get_commit_string(HangulInputContext *hic)
1346 return hic->commit_string;
1351 * @brief @ref HangulInputContext 를 초기상태로 되돌리는 함수
1352 * @param hic @ref HangulInputContext 를 가리키는 포인터
1354 * 이 함수는 @a hic가 가리키는 @ref HangulInputContext 의 상태를
1355 * 처음 상태로 되돌린다. preedit 스트링, commit 스트링, flush 스트링이
1356 * 없어지고, 입력되었던 키에 대한 기록이 없어진다.
1357 * 영어 상태로 바뀌는 것이 아니다.
1359 * 비교: hangul_ic_flush()
1361 * @remarks 이 함수는 @ref HangulInputContext 의 상태를 변화 시킨다.
1364 hangul_ic_reset(HangulInputContext *hic)
1369 hic->preedit_string[0] = 0;
1370 hic->commit_string[0] = 0;
1371 hic->flushed_string[0] = 0;
1373 hangul_buffer_clear(&hic->buffer);
1376 /* append current preedit to the commit buffer.
1377 * this function does not clear previously made commit string. */
1379 hangul_ic_flush_internal(HangulInputContext *hic)
1381 hic->preedit_string[0] = 0;
1383 hangul_ic_save_commit_string(hic);
1384 hangul_buffer_clear(&hic->buffer);
1389 * @brief @ref HangulInputContext 의 입력 상태를 완료하는 함수
1390 * @param hic @ref HangulInputContext 를 가리키는 포인터
1391 * @return 조합 완료된 스트링, 스트링의 길이가 0이면 조합 완료된 스트링이
1394 * 이 함수는 @a hic가 가리키는 @ref HangulInputContext 의 입력 상태를 완료한다.
1395 * 조합중이던 스트링을 완성하여 리턴한다. 그리고 입력 상태가 초기 상태로
1396 * 되돌아 간다. 조합중이던 글자를 강제로 commit하고 싶을때 사용하는 함수다.
1397 * 보통의 경우 입력 framework에서 focus가 나갈때 이 함수를 불러서 마지막
1398 * 상태를 완료해야 조합중이던 글자를 잃어버리지 않게 된다.
1400 * 비교: hangul_ic_reset()
1402 * @remarks 이 함수는 @ref HangulInputContext 의 상태를 변화 시킨다.
1405 hangul_ic_flush(HangulInputContext *hic)
1410 // get the remaining string and clear the buffer
1411 hic->preedit_string[0] = 0;
1412 hic->commit_string[0] = 0;
1413 hic->flushed_string[0] = 0;
1415 if (hic->output_mode == HANGUL_OUTPUT_JAMO) {
1416 hangul_buffer_get_jamo_string(&hic->buffer, hic->flushed_string,
1417 N_ELEMENTS(hic->flushed_string));
1419 hangul_buffer_get_string(&hic->buffer, hic->flushed_string,
1420 N_ELEMENTS(hic->flushed_string));
1423 hangul_buffer_clear(&hic->buffer);
1425 return hic->flushed_string;
1430 * @brief @ref HangulInputContext 가 backspace 키를 처리하도록 하는 함수
1431 * @param hic @ref HangulInputContext 를 가리키는 포인터
1432 * @return @a hic가 키를 사용했으면 true, 사용하지 않았으면 false
1434 * 이 함수는 @a hic가 가리키는 @ref HangulInputContext 의 조합중이던 글자를
1435 * 뒤에서부터 하나 지우는 기능을 한다. backspace 키를 눌렀을 때 발생하는
1436 * 동작을 한다. 따라서 이 함수를 부르고 나면 preedit string이 바뀌므로
1439 * @remarks 이 함수는 @ref HangulInputContext 의 상태를 변화 시킨다.
1442 hangul_ic_backspace(HangulInputContext *hic)
1449 hic->preedit_string[0] = 0;
1450 hic->commit_string[0] = 0;
1452 ret = hangul_buffer_backspace(&hic->buffer);
1454 hangul_ic_save_preedit_string(hic);
1460 * @brief @ref HangulInputContext 가 조합중인 글자를 가지고 있는지 확인하는 함수
1461 * @param hic @ref HangulInputContext 를 가리키는 포인터
1463 * @ref HangulInputContext 가 조합중인 글자가 있으면 true를 리턴한다.
1465 * @remarks 이 함수는 @ref HangulInputContext 의 상태를 변화 시키지 않는다.
1468 hangul_ic_is_empty(HangulInputContext *hic)
1470 return hangul_buffer_is_empty(&hic->buffer);
1475 * @brief @ref HangulInputContext 가 조합중인 초성을 가지고 있는지 확인하는 함수
1476 * @param hic @ref HangulInputContext 를 가리키는 포인터
1478 * @ref HangulInputContext 가 조합중인 글자가 초성이 있으면 true를 리턴한다.
1480 * @remarks 이 함수는 @ref HangulInputContext 의 상태를 변화 시키지 않는다.
1483 hangul_ic_has_choseong(HangulInputContext *hic)
1485 return hangul_buffer_has_choseong(&hic->buffer);
1490 * @brief @ref HangulInputContext 가 조합중인 중성을 가지고 있는지 확인하는 함수
1491 * @param hic @ref HangulInputContext 를 가리키는 포인터
1493 * @ref HangulInputContext 가 조합중인 글자가 중성이 있으면 true를 리턴한다.
1495 * @remarks 이 함수는 @ref HangulInputContext 의 상태를 변화 시키지 않는다.
1498 hangul_ic_has_jungseong(HangulInputContext *hic)
1500 return hangul_buffer_has_jungseong(&hic->buffer);
1505 * @brief @ref HangulInputContext 가 조합중인 종성을 가지고 있는지 확인하는 함수
1506 * @param hic @ref HangulInputContext 를 가리키는 포인터
1508 * @ref HangulInputContext 가 조합중인 글자가 종성이 있으면 true를 리턴한다.
1510 * @remarks 이 함수는 @ref HangulInputContext 의 상태를 변화 시키지 않는다.
1513 hangul_ic_has_jongseong(HangulInputContext *hic)
1515 return hangul_buffer_has_jongseong(&hic->buffer);
1519 hangul_ic_set_output_mode(HangulInputContext *hic, int mode)
1524 if (!hic->use_jamo_mode_only)
1525 hic->output_mode = mode;
1529 hangul_ic_connect_translate (HangulInputContext* hic,
1530 HangulOnTranslate callback,
1534 hic->on_translate = callback;
1535 hic->on_translate_data = user_data;
1540 hangul_ic_connect_transition(HangulInputContext* hic,
1541 HangulOnTransition callback,
1545 hic->on_transition = callback;
1546 hic->on_transition_data = user_data;
1550 void hangul_ic_connect_callback(HangulInputContext* hic, const char* event,
1551 void* callback, void* user_data)
1553 if (hic == NULL || event == NULL)
1556 if (strcasecmp(event, "translate") == 0) {
1557 hic->on_translate = (HangulOnTranslate)callback;
1558 hic->on_translate_data = user_data;
1559 } else if (strcasecmp(event, "transition") == 0) {
1560 hic->on_transition = (HangulOnTransition)callback;
1561 hic->on_transition_data = user_data;
1566 hangul_ic_set_keyboard(HangulInputContext *hic, const HangulKeyboard* keyboard)
1568 if (hic == NULL || keyboard == NULL)
1571 hic->keyboard = keyboard;
1574 static const HangulKeyboard*
1575 hangul_ic_get_keyboard_by_id(const char* id)
1580 /* hangul_keyboards 테이블은 id 순으로 정렬되어 있지 않으므로
1581 * binary search를 할수 없고 linear search를 한다. */
1582 n = hangul_ic_get_n_keyboards();
1583 for (i = 0; i < n; ++i) {
1584 const HangulKeyboard* keyboard = hangul_keyboards[i];
1585 if (strcmp(id, keyboard->id) == 0) {
1595 * @brief @ref HangulInputContext 의 자판 배열을 바꾸는 함수
1596 * @param hic @ref HangulInputContext 오브젝트
1597 * @param id 선택하고자 하는 자판, 아래와 같은 값을 선택할 수 있다.
1598 * @li "2" @ref layout_2 자판
1599 * @li "2y" @ref layout_2y 자판
1600 * @li "3f" @ref layout_3f 자판
1601 * @li "39" @ref layout_390 자판
1602 * @li "3s" @ref layout_3s 자판
1603 * @li "3y" @ref layout_3y 자판
1604 * @li "32" @ref layout_32 자판
1605 * @li "ro" @ref layout_ro 자판
1607 * libhangul이 지원하는 자판에 대한 정보는 @ref hangulkeyboards 페이지를
1611 * 이 함수는 @ref HangulInputContext 의 자판을 @a id로 지정된 것으로 변경한다.
1613 * @remarks 이 함수는 @ref HangulInputContext 의 내부 조합 상태에는 영향을
1614 * 미치지 않는다. 따라서 입력 중간에 자판을 변경하더라도 조합 상태는 유지된다.
1617 hangul_ic_select_keyboard(HangulInputContext *hic, const char* id)
1619 const HangulKeyboard* keyboard;
1627 keyboard = hangul_ic_get_keyboard_by_id(id);
1628 if (keyboard != NULL) {
1629 hic->keyboard = keyboard;
1631 hic->keyboard = &hangul_keyboard_2;
1636 hangul_ic_set_combination(HangulInputContext *hic,
1637 const HangulCombination* combination)
1643 * @brief @ref HangulInputContext 오브젝트를 생성한다.
1644 * @param keyboard 사용하고자 하는 키보드, 사용 가능한 값에 대해서는
1645 * hangul_ic_select_keyboard() 함수 설명을 참조한다.
1646 * @return 새로 생성된 @ref HangulInputContext 에 대한 포인터
1648 * 이 함수는 한글 조합 기능을 제공하는 @ref HangulInputContext 오브젝트를
1649 * 생성한다. 생성할때 지정한 자판은 나중에 hangul_ic_select_keyboard() 함수로
1651 * 더이상 사용하지 않을 때에는 hangul_ic_delete() 함수로 삭제해야 한다.
1654 hangul_ic_new(const char* keyboard)
1656 HangulInputContext *hic;
1658 hic = malloc(sizeof(HangulInputContext));
1662 hic->preedit_string[0] = 0;
1663 hic->commit_string[0] = 0;
1664 hic->flushed_string[0] = 0;
1666 hic->on_translate = NULL;
1667 hic->on_translate_data = NULL;
1669 hic->on_transition = NULL;
1670 hic->on_transition_data = NULL;
1672 hic->use_jamo_mode_only = FALSE;
1674 hangul_ic_set_output_mode(hic, HANGUL_OUTPUT_SYLLABLE);
1675 hangul_ic_select_keyboard(hic, keyboard);
1677 hangul_buffer_clear(&hic->buffer);
1684 * @brief @ref HangulInputContext 를 삭제하는 함수
1685 * @param hic @ref HangulInputContext 오브젝트
1687 * @a hic가 가리키는 @ref HangulInputContext 오브젝트의 메모리를 해제한다.
1688 * hangul_ic_new() 함수로 생성된 모든 @ref HangulInputContext 오브젝트는
1689 * 이 함수로 메모리해제를 해야 한다.
1690 * 메모리 해제 과정에서 상태 변화는 일어나지 않으므로 마지막 입력된
1691 * 조합중이던 내용은 사라지게 된다.
1694 hangul_ic_delete(HangulInputContext *hic)
1703 hangul_ic_get_n_keyboards()
1705 return N_ELEMENTS(hangul_keyboards);
1709 hangul_ic_get_keyboard_id(unsigned index_)
1711 if (index_ < N_ELEMENTS(hangul_keyboards)) {
1712 return hangul_keyboards[index_]->id;
1719 hangul_ic_get_keyboard_name(unsigned index_)
1722 static bool isGettextInitialized = false;
1723 if (!isGettextInitialized) {
1724 isGettextInitialized = true;
1725 bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
1726 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
1730 if (index_ < N_ELEMENTS(hangul_keyboards)) {
1731 return _(hangul_keyboards[index_]->name);
1739 * @brief 주어진 hic가 transliteration method인지 판별
1740 * @param hic 상태를 알고자 하는 HangulInputContext 포인터
1741 * @return hic가 transliteration method인 경우 true를 리턴, 아니면 false
1743 * 이 함수는 @a hic 가 transliteration method인지 판별하는 함수다.
1744 * 이 함수가 false를 리턴할 경우에는 process 함수에 keycode를 넘기기 전에
1745 * 키보드 자판 배열에 독립적인 값으로 변환한 후 넘겨야 한다.
1746 * 그렇지 않으면 유럽어 자판과 한국어 자판을 같이 쓸때 한글 입력이 제대로
1750 hangul_ic_is_transliteration(HangulInputContext *hic)
1757 type = hangul_keyboard_get_type(hic->keyboard);
1758 if (type == HANGUL_KEYBOARD_TYPE_ROMAJA)