summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChoe Hwanjin <choe.hwanjin@gmail.com>2016-02-23 18:39:29 +0900
committerChoe Hwanjin <choe.hwanjin@gmail.com>2016-02-23 18:46:12 +0900
commit1b438ae53333c7186544ecd79add5ea175a63d8d (patch)
tree7eee5d88bdecfc27fea221eb33658d14ac98b761
parent3cc99981949155e27e6e0db8a26a4c48a79d5e4f (diff)
downloadlibhangul-1b438ae53333c7186544ecd79add5ea175a63d8d.tar.gz
hangul ic: HANGUL_IC_OPTION_COMBI_ON_DOUBLE_STROKE 옵션 추가
두벌식에서 자음을 연속 입력해서 된소리로 조합해주는 기능을 설정으로 조정할 수 있게 한다. (예를 들어 ㄱ+ㄱ을 ㄲ으로 변환해 주는 기능) 이에 따라서 관련 유닛 테스트 코드를 변경하고 이 옵션을 테스트할 코드를 추가한다. 기본값은 MS IME 호환을 위해서 false로 설정한다. 세벌식의 경우에는 이 기능이 자판의 기본적인 동작 방식이므로 이 옵션으로 조정되지 않는다. 두벌식 옛한글 자판의 경우에는 현대 한글 자모의 경우만 조합이 제한되고 옛한글 자모들은 그대로 조합된다. 구현에 필요한 hangul_is_jamo_conjoinable 함수도 추가.
-rw-r--r--hangul/hangul.h2
-rw-r--r--hangul/hangulctype.c12
-rw-r--r--hangul/hangulinputcontext.c55
-rw-r--r--test/test.c158
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;
}