diff options
author | Choe Hwanjin <choe.hwanjin@gmail.com> | 2016-02-23 18:39:29 +0900 |
---|---|---|
committer | Choe Hwanjin <choe.hwanjin@gmail.com> | 2016-02-23 18:46:12 +0900 |
commit | 1b438ae53333c7186544ecd79add5ea175a63d8d (patch) | |
tree | 7eee5d88bdecfc27fea221eb33658d14ac98b761 | |
parent | 3cc99981949155e27e6e0db8a26a4c48a79d5e4f (diff) | |
download | libhangul-1b438ae53333c7186544ecd79add5ea175a63d8d.tar.gz |
hangul ic: HANGUL_IC_OPTION_COMBI_ON_DOUBLE_STROKE 옵션 추가
두벌식에서 자음을 연속 입력해서 된소리로 조합해주는 기능을 설정으로
조정할 수 있게 한다. (예를 들어 ㄱ+ㄱ을 ㄲ으로 변환해 주는 기능)
이에 따라서 관련 유닛 테스트 코드를 변경하고 이 옵션을 테스트할
코드를 추가한다.
기본값은 MS IME 호환을 위해서 false로 설정한다.
세벌식의 경우에는 이 기능이 자판의 기본적인 동작 방식이므로 이
옵션으로 조정되지 않는다.
두벌식 옛한글 자판의 경우에는 현대 한글 자모의 경우만 조합이 제한되고
옛한글 자모들은 그대로 조합된다.
구현에 필요한 hangul_is_jamo_conjoinable 함수도 추가.
-rw-r--r-- | hangul/hangul.h | 2 | ||||
-rw-r--r-- | hangul/hangulctype.c | 12 | ||||
-rw-r--r-- | hangul/hangulinputcontext.c | 55 | ||||
-rw-r--r-- | test/test.c | 158 |
4 files changed, 163 insertions, 64 deletions
diff --git a/hangul/hangul.h b/hangul/hangul.h index 539096b..b55ee57 100644 --- a/hangul/hangul.h +++ b/hangul/hangul.h @@ -46,6 +46,7 @@ bool hangul_is_jongseong(ucschar c); bool hangul_is_choseong_conjoinable(ucschar c); bool hangul_is_jungseong_conjoinable(ucschar c); bool hangul_is_jongseong_conjoinable(ucschar c); +bool hangul_is_jamo_conjoinable(ucschar c); bool hangul_is_syllable(ucschar c); bool hangul_is_jamo(ucschar c); bool hangul_is_cjamo(ucschar c); @@ -88,6 +89,7 @@ enum { enum { HANGUL_IC_OPTION_AUTO_REORDER, + HANGUL_IC_OPTION_COMBI_ON_DOUBLE_STROKE, }; /* keyboard */ diff --git a/hangul/hangulctype.c b/hangul/hangulctype.c index 31dd206..e29d79b 100644 --- a/hangul/hangulctype.c +++ b/hangul/hangulctype.c @@ -146,6 +146,18 @@ hangul_is_jongseong_conjoinable(ucschar c) /** * @ingroup hangulctype + * @brief 자모가 조합 가능한지 확인 + */ +bool +hangul_is_jamo_conjoinable(ucschar c) +{ + return hangul_is_choseong_conjoinable(c) || + hangul_is_jungseong_conjoinable(c) || + hangul_is_jongseong_conjoinable(c); +} + +/** + * @ingroup hangulctype * @brief 한글 음절 인지 확 * @param c UCS4 코드 값 * @return @a c가 한글 음절 코드이면 true, 그 외에는 false diff --git a/hangul/hangulinputcontext.c b/hangul/hangulinputcontext.c index f4addda..0585d71 100644 --- a/hangul/hangulinputcontext.c +++ b/hangul/hangulinputcontext.c @@ -235,6 +235,7 @@ struct _HangulInputContext { unsigned int use_jamo_mode_only : 1; unsigned int option_auto_reorder : 1; + unsigned int option_combi_on_double_stroke : 1; }; #include "hangulkeyboard.h" @@ -851,6 +852,27 @@ hangul_ic_choseong_to_jongseong(HangulInputContext* hic, ucschar cho) return 0; } +static ucschar +hangul_ic_combine(HangulInputContext* hic, ucschar first, ucschar second) +{ + if (!hic->option_combi_on_double_stroke) { + if (hangul_keyboard_get_type(hic->keyboard) == HANGUL_KEYBOARD_TYPE_JAMO) { + /* 옛한글은 아래 규칙을 적용하지 않아야 입력가능한 글자가 있으므로 + * 적용하지 않는다. */ + if (first == second && + hangul_is_jamo_conjoinable(first)) { + return 0; + } + } + } + + ucschar combined = 0; + combined = hangul_combination_combine(hic->keyboard->combination, + first, second); + + return combined; +} + static bool hangul_ic_process_jamo(HangulInputContext *hic, ucschar ch) { @@ -866,8 +888,7 @@ hangul_ic_process_jamo(HangulInputContext *hic, ucschar ch) if (hic->buffer.jongseong) { if (hangul_is_choseong(ch)) { jong = hangul_ic_choseong_to_jongseong(hic, ch); - combined = hangul_combination_combine(hic->keyboard->combination, - hic->buffer.jongseong, jong); + combined = hangul_ic_combine(hic, hic->buffer.jongseong, jong); if (hangul_is_jongseong(combined)) { if (!hangul_ic_push(hic, combined)) { if (!hangul_ic_push(hic, ch)) { @@ -944,8 +965,7 @@ hangul_ic_process_jamo(HangulInputContext *hic, ucschar ch) } } } else if (hangul_is_jungseong(ch)) { - combined = hangul_combination_combine(hic->keyboard->combination, - hic->buffer.jungseong, ch); + combined = hangul_ic_combine(hic, hic->buffer.jungseong, ch); if (hangul_is_jungseong(combined)) { if (!hangul_ic_push(hic, combined)) { return false; @@ -961,8 +981,7 @@ hangul_ic_process_jamo(HangulInputContext *hic, ucschar ch) } } else if (hic->buffer.choseong) { if (hangul_is_choseong(ch)) { - combined = hangul_combination_combine(hic->keyboard->combination, - hic->buffer.choseong, ch); + combined = hangul_ic_combine(hic, hic->buffer.choseong, ch); /* 초성을 입력한 combine 함수에서 종성이 나오게 된다면 * 이전 초성도 종성으로 바꿔 주는 편이 나머지 처리에 편리하다. * 이 기능은 MS IME 호환기능으로 ㄳ을 입력하는데 사용한다. */ @@ -1027,8 +1046,7 @@ hangul_ic_process_jaso(HangulInputContext *hic, ucschar ch) } else { ucschar choseong = 0; if (hangul_is_choseong(hangul_ic_peek(hic))) { - choseong = hangul_combination_combine(hic->keyboard->combination, - hic->buffer.choseong, ch); + choseong = hangul_ic_combine(hic, hic->buffer.choseong, ch); } if (choseong) { if (!hangul_ic_push(hic, choseong)) { @@ -1068,8 +1086,7 @@ hangul_ic_process_jaso(HangulInputContext *hic, ucschar ch) } else { ucschar jungseong = 0; if (hangul_is_jungseong(hangul_ic_peek(hic))) { - jungseong = hangul_combination_combine(hic->keyboard->combination, - hic->buffer.jungseong, ch); + jungseong = hangul_ic_combine(hic, hic->buffer.jungseong, ch); } if (jungseong) { if (!hangul_ic_push(hic, jungseong)) { @@ -1096,8 +1113,7 @@ hangul_ic_process_jaso(HangulInputContext *hic, ucschar ch) } else { ucschar jongseong = 0; if (hangul_is_jongseong(hangul_ic_peek(hic))) { - jongseong = hangul_combination_combine(hic->keyboard->combination, - hic->buffer.jongseong, ch); + jongseong = hangul_ic_combine(hic, hic->buffer.jongseong, ch); } if (jongseong) { if (!hangul_ic_push(hic, jongseong)) { @@ -1154,8 +1170,7 @@ hangul_ic_process_romaja(HangulInputContext *hic, int ascii, ucschar ch) jong = ch; else jong = hangul_ic_choseong_to_jongseong(hic, ch); - combined = hangul_combination_combine(hic->keyboard->combination, - hic->buffer.jongseong, jong); + combined = hangul_ic_combine(hic, hic->buffer.jongseong, jong); if (hangul_is_jongseong(combined)) { if (!hangul_ic_push(hic, combined)) { if (!hangul_ic_push(hic, ch)) { @@ -1229,8 +1244,7 @@ hangul_ic_process_romaja(HangulInputContext *hic, int ascii, ucschar ch) } } } else if (hangul_is_jungseong(ch)) { - combined = hangul_combination_combine(hic->keyboard->combination, - hic->buffer.jungseong, ch); + combined = hangul_ic_combine(hic, hic->buffer.jungseong, ch); if (hangul_is_jungseong(combined)) { if (!hangul_ic_push(hic, combined)) { return false; @@ -1253,8 +1267,7 @@ hangul_ic_process_romaja(HangulInputContext *hic, int ascii, ucschar ch) } } else if (hic->buffer.choseong) { if (hangul_is_choseong(ch)) { - combined = hangul_combination_combine(hic->keyboard->combination, - hic->buffer.choseong, ch); + combined = hangul_ic_combine(hic, hic->buffer.choseong, ch); if (combined == 0) { hic->buffer.jungseong = 0x1173; hangul_ic_flush_internal(hic); @@ -1574,6 +1587,8 @@ hangul_ic_get_option(HangulInputContext* hic, int option) switch (option) { case HANGUL_IC_OPTION_AUTO_REORDER: return hic->option_auto_reorder; + case HANGUL_IC_OPTION_COMBI_ON_DOUBLE_STROKE: + return hic->option_combi_on_double_stroke; } return false; @@ -1586,6 +1601,9 @@ hangul_ic_set_option(HangulInputContext* hic, int option, bool value) case HANGUL_IC_OPTION_AUTO_REORDER: hic->option_auto_reorder = value; break; + case HANGUL_IC_OPTION_COMBI_ON_DOUBLE_STROKE: + hic->option_combi_on_double_stroke = value; + break; } } @@ -1746,6 +1764,7 @@ hangul_ic_new(const char* keyboard) hic->use_jamo_mode_only = FALSE; hic->option_auto_reorder = false; + hic->option_combi_on_double_stroke = false; hangul_ic_set_output_mode(hic, HANGUL_OUTPUT_SYLLABLE); hangul_ic_select_keyboard(hic, keyboard); diff --git a/test/test.c b/test/test.c index 982e58b..def4e0a 100644 --- a/test/test.c +++ b/test/test.c @@ -7,6 +7,39 @@ #define countof(x) ((sizeof(x)) / (sizeof(x[0]))) +static HangulInputContext* global_ic = NULL; + +/* ic option을 바꾸면서 테스트하는걸 손쉽게 하기 위해서 + * static ic를 하나 두고 이것으로 테스트를 진행하게 코드를 + * 바꾼다. */ +static HangulInputContext* +get_ic(const char* keyboard) +{ + if (global_ic == NULL) { + global_ic = hangul_ic_new("2"); + } + + hangul_ic_select_keyboard(global_ic, keyboard); + hangul_ic_reset(global_ic); + + return global_ic; +} + +static void +set_ic_option(int option, bool value) +{ + HangulInputContext* ic = get_ic("2"); + hangul_ic_set_option(ic, option, value); +} + +static bool +get_ic_option(int option) +{ + HangulInputContext* ic = get_ic("2"); + bool value = hangul_ic_get_option(ic, option); + return value; +} + static bool check_preedit_with_ic(HangulInputContext* ic, const char* input, const wchar_t* output) { @@ -33,12 +66,10 @@ check_preedit(const char* keyboard, const char* input, const wchar_t* output) HangulInputContext* ic; int res; - ic = hangul_ic_new(keyboard); + ic = get_ic(keyboard); res = check_preedit_with_ic(ic, input, output);; - hangul_ic_delete(ic); - return res; } @@ -68,12 +99,10 @@ check_commit(const char* keyboard, const char* input, const wchar_t* output) HangulInputContext* ic; int res; - ic = hangul_ic_new(keyboard); + ic = get_ic(keyboard); res = check_commit_with_ic(ic, input, output); - hangul_ic_delete(ic); - return res; } @@ -82,9 +111,6 @@ START_TEST(test_hangul_ic_process_2) /* ㄱㅏㅉ */ fail_unless(check_commit("2", "rkW", L"가")); fail_unless(check_preedit("2", "rkW", L"ㅉ")); - /* ㅂㅓㅅㅅㅡ */ - fail_unless(check_commit("2", "qjttm", L"벗")); - fail_unless(check_preedit("2", "qjttm", L"스")); /* ㅂㅓㅆㅡ */ fail_unless(check_commit("2", "qjTm", L"버")); fail_unless(check_preedit("2", "qjTm", L"쓰")); @@ -100,7 +126,6 @@ START_TEST(test_hangul_ic_process_2) /* backspace */ fail_unless(check_preedit("2", "rkT\b", L"가")); - fail_unless(check_preedit("2", "rktt\b", L"갓")); fail_unless(check_preedit("2", "rt\bk", L"가")); fail_unless(check_preedit("2", "akfr\b", L"말")); fail_unless(check_preedit("2", "dnp\b", L"우")); @@ -132,25 +157,42 @@ START_TEST(test_hangul_ic_process_2y) fail_unless(check_preedit("2y", "fo", L"래")); /* ㅎ. ㄴ */ fail_unless(check_preedit("2y", "gKs", L"\x1112\x119e\x11ab")); - /* ㅂㅂㅇㅏㅁㅅㅅ */ + /* ㅃㅇㅏㅁㅆ */ + fail_unless(check_preedit("2y", "QdhaT", L"\x112c\x1169\x11de")); + /* ㅃㅇㅏㅁㅅㅅㅛ */ + fail_unless(check_commit("2y", "Qdhatty", L"\x112c\x1169\x11dd")); + fail_unless(check_preedit("2y", "Qdhatty", L"쇼")); + /* ㅃㅇㅏㅁㅆㅛ */ + fail_unless(check_commit("2y", "QdhaTy", L"\x112c\x1169\x11b7")); + fail_unless(check_preedit("2y", "QdhaTy", L"쑈")); + /* 옛이응 처리 */ + /* ㄱㅏㆁㆁ */ + fail_unless(check_preedit("2y", "rkDD", L"\x1100\x1161\x11ee")); + /* ㄱㅏㆁㆁㅏ */ + fail_unless(check_commit("2y", "rkDDk", L"\x1100\x1161\x11f0")); + fail_unless(check_preedit("2y", "rkDDk", L"\x114c\x1161")); + + + bool val = get_ic_option(HANGUL_IC_OPTION_COMBI_ON_DOUBLE_STROKE); + set_ic_option(HANGUL_IC_OPTION_COMBI_ON_DOUBLE_STROKE, true); + + /* ㅂㅂㅇㅏㅁㅅㅅ */ fail_unless(check_preedit("2y", "qqdhatt", L"\x112c\x1169\x11de")); - /* ㅂㅂㅇㅏㅁㅅㅅㅛ */ + /* ㅂㅂㅇㅏㅁㅅㅅㅛ */ fail_unless(check_commit("2y", "qqdhatty", L"\x112c\x1169\x11dd")); fail_unless(check_preedit("2y", "qqdhatty", L"쇼")); - /* ㅂㅂㅇㅏㅁㅆㅛ */ + /* ㅂㅂㅇㅏㅁㅆㅛ */ fail_unless(check_commit("2y", "qqdhaTy", L"\x112c\x1169\x11b7")); fail_unless(check_preedit("2y", "qqdhaTy", L"쑈")); - /* 옛이응 처리 */ + /* ㅇㅇㅏㅇㅇㅏ */ fail_unless(check_commit("2y", "ddkdd", L"\x1147\x1161\x11bc")); fail_unless(check_preedit("2y", "ddkdd", L"ㅇ")); - /* ㄱㅏㆁㆁ */ - fail_unless(check_preedit("2y", "rkDD", L"\x1100\x1161\x11ee")); - /* ㄱㅏㆁㆁㅏ */ - fail_unless(check_commit("2y", "rkDDk", L"\x1100\x1161\x11f0")); - fail_unless(check_preedit("2y", "rkDDk", L"\x114c\x1161")); + /* ㅏㅏㅏㅏ */ fail_unless(check_preedit("2y", "kkkk", L"\x115f\x11a2")); + + set_ic_option(HANGUL_IC_OPTION_COMBI_ON_DOUBLE_STROKE, val); } END_TEST @@ -293,39 +335,60 @@ END_TEST START_TEST(test_hangul_ic_auto_reorder) { - HangulInputContext* ic = hangul_ic_new("2"); + bool val = get_ic_option(HANGUL_IC_OPTION_AUTO_REORDER); - hangul_ic_set_option(ic, HANGUL_IC_OPTION_AUTO_REORDER, true); - hangul_ic_reset(ic); - fail_unless(check_preedit_with_ic(ic, "rk", L"가")); - hangul_ic_reset(ic); - fail_unless(check_preedit_with_ic(ic, "kr", L"가")); + set_ic_option(HANGUL_IC_OPTION_AUTO_REORDER, true); + fail_unless(check_preedit("2", "rk", L"가")); + fail_unless(check_preedit("2", "kr", L"가")); - hangul_ic_set_option(ic, HANGUL_IC_OPTION_AUTO_REORDER, false); - hangul_ic_reset(ic); - fail_unless(check_preedit_with_ic(ic, "rk", L"가")); - hangul_ic_reset(ic); - fail_unless(check_commit_with_ic(ic, "kr", L"ㅏ")); - hangul_ic_reset(ic); - fail_unless(check_preedit_with_ic(ic, "kr", L"ㄱ")); + set_ic_option(HANGUL_IC_OPTION_AUTO_REORDER, false); + fail_unless(check_preedit("2", "rk", L"가")); + fail_unless(check_commit("2", "kr", L"ㅏ")); + fail_unless(check_preedit("2", "kr", L"ㄱ")); - hangul_ic_select_keyboard(ic, "3f"); + set_ic_option(HANGUL_IC_OPTION_AUTO_REORDER, true); + fail_unless(check_preedit("3f", "kf", L"가")); + fail_unless(check_preedit("3f", "fk", L"가")); - hangul_ic_set_option(ic, HANGUL_IC_OPTION_AUTO_REORDER, true); - hangul_ic_reset(ic); - fail_unless(check_preedit_with_ic(ic, "kf", L"가")); - hangul_ic_reset(ic); - fail_unless(check_preedit_with_ic(ic, "fk", L"가")); + set_ic_option(HANGUL_IC_OPTION_AUTO_REORDER, false); + fail_unless(check_preedit("3f", "kf", L"가")); + fail_unless(check_commit("3f", "fk", L"ㅏ")); + fail_unless(check_preedit("3f", "fk", L"ㄱ")); - hangul_ic_set_option(ic, HANGUL_IC_OPTION_AUTO_REORDER, false); - hangul_ic_reset(ic); - fail_unless(check_preedit_with_ic(ic, "kf", L"가")); - hangul_ic_reset(ic); - fail_unless(check_commit_with_ic(ic, "fk", L"ㅏ")); - hangul_ic_reset(ic); - fail_unless(check_preedit_with_ic(ic, "fk", L"ㄱ")); + set_ic_option(HANGUL_IC_OPTION_AUTO_REORDER, val); +} +END_TEST - hangul_ic_delete(ic); +START_TEST(test_hangul_ic_combi_on_double_stroke) +{ + bool val = get_ic_option(HANGUL_IC_OPTION_COMBI_ON_DOUBLE_STROKE); + + set_ic_option(HANGUL_IC_OPTION_COMBI_ON_DOUBLE_STROKE, true); + fail_unless(check_preedit("2", "rrkrr", L"깎")); + fail_unless(check_preedit("2", "rrkrrk", L"가")); + + /* ㅂㅓㅅㅅ */ + fail_unless(check_preedit("2", "qjtt", L"벘")); + fail_unless(check_commit("2", "qjttm", L"벗")); + fail_unless(check_preedit("2", "qjttm", L"스")); + + fail_unless(check_preedit("2", "rktt", L"갔")); + fail_unless(check_preedit("2", "rktt\b", L"갓")); + + set_ic_option(HANGUL_IC_OPTION_COMBI_ON_DOUBLE_STROKE, false); + fail_unless(check_commit("2", "rr", L"ㄱ")); + fail_unless(check_preedit("2", "rr", L"ㄱ")); + fail_unless(check_preedit("2", "rrk", L"가")); + fail_unless(check_preedit("2", "rrkr", L"각")); + fail_unless(check_commit("2", "rrkrr", L"각")); + fail_unless(check_preedit("2", "rrkrr", L"ㄱ")); + fail_unless(check_preedit("2", "rrkrrk", L"가")); + + /* ㅂㅓㅅㅅ */ + fail_unless(check_commit("2", "qjtt", L"벗")); + fail_unless(check_preedit("2", "qjtt", L"ㅅ")); + + set_ic_option(HANGUL_IC_OPTION_COMBI_ON_DOUBLE_STROKE, val); } END_TEST @@ -491,6 +554,7 @@ Suite* libhangul_suite() tcase_add_test(hangul, test_hangul_ic_process_3f); tcase_add_test(hangul, test_hangul_ic_process_romaja); tcase_add_test(hangul, test_hangul_ic_auto_reorder); + tcase_add_test(hangul, test_hangul_ic_combi_on_double_stroke); tcase_add_test(hangul, test_syllable_iterator); tcase_add_test(hangul, test_hangul_keyboard); tcase_add_test(hangul, test_hangul_jamo_to_cjamo); @@ -511,5 +575,7 @@ int main() number_failed = srunner_ntests_failed(sr); srunner_free(sr); + hangul_ic_delete(global_ic); + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } |