korean: ㄳ from two consonants, 가 from a vowel typed first; index jamo by scanning

libhangul, and so fcitx5-hangul, joins two lone consonants into the
compound jong they make (rt → ㄳ, split again by a vowel: rtk → ㄱ사),
and by default reorders a vowel typed before its consonant (kr → 가);
strans committed the first jamo and started over.  Backspace on a lone
ㄳ leaves ㄱ, as on a syllable.

The three jamo index tables and their -1 macros were the cho, jung, and
jong arrays inverted by hand, bounded by a Jrange the callers had to
respect; a linear scan of the arrays says the same in ten lines.
This commit is contained in:
2026-08-17 01:22:52 +09:00
parent f0498868eb
commit 1285476b41
2 changed files with 40 additions and 46 deletions

67
ko.c
View File

@@ -4,8 +4,6 @@
enum enum
{ {
Sbase = 0xAC00, Sbase = 0xAC00,
Jbase = 0x3131,
Jrange = 51,
Ncho = 19, Ncho = 19,
Njung = 21, Njung = 21,
Njong = 28, Njong = 28,
@@ -35,41 +33,21 @@ static Rune jong[] = {
L'', L'', L'', L'', L'', L'',
}; };
static int choidx[Jrange] = { /* A jamo's index in cho, jung, or jong, or -1; jong[0] is no jong. */
[L''-Jbase] = 1, [L''-Jbase] = 2, [L''-Jbase] = 3, static int
[L''-Jbase] = 4, [L''-Jbase] = 5, [L''-Jbase] = 6, idx(Rune *t, int n, Rune r)
[L''-Jbase] = 7, [L''-Jbase] = 8, [L''-Jbase] = 9, {
[L''-Jbase] = 10, [L''-Jbase] = 11, [L''-Jbase] = 12, int i;
[L''-Jbase] = 13, [L''-Jbase] = 14, [L''-Jbase] = 15,
[L''-Jbase] = 16, [L''-Jbase] = 17, [L''-Jbase] = 18,
[L''-Jbase] = 19,
};
static int jungidx[Jrange] = { for(i = 0; i < n; i++)
[L''-Jbase] = 1, [L''-Jbase] = 2, [L''-Jbase] = 3, if(t[i] == r)
[L''-Jbase] = 4, [L''-Jbase] = 5, [L''-Jbase] = 6, return i;
[L''-Jbase] = 7, [L''-Jbase] = 8, [L''-Jbase] = 9, return -1;
[L''-Jbase] = 10, [L''-Jbase] = 11, [L''-Jbase] = 12, }
[L''-Jbase] = 13, [L''-Jbase] = 14, [L''-Jbase] = 15,
[L''-Jbase] = 16, [L''-Jbase] = 17, [L''-Jbase] = 18,
[L''-Jbase] = 19, [L''-Jbase] = 20, [L''-Jbase] = 21,
};
static int jongidx[Jrange] = { #define Choidx(r) idx(cho, Ncho, r)
[L''-Jbase] = 2, [L''-Jbase] = 3, [L''-Jbase] = 4, #define Jungidx(r) idx(jung, Njung, r)
[L''-Jbase] = 5, [L''-Jbase] = 6, [L''-Jbase] = 7, #define Jongidx(r) idx(jong, Njong, r)
[L''-Jbase] = 8, [L''-Jbase] = 9, [L''-Jbase] = 10,
[L''-Jbase] = 11, [L''-Jbase] = 12, [L''-Jbase] = 13,
[L''-Jbase] = 14, [L''-Jbase] = 15, [L''-Jbase] = 16,
[L''-Jbase] = 17, [L''-Jbase] = 18, [L''-Jbase] = 19,
[L''-Jbase] = 20, [L''-Jbase] = 21, [L''-Jbase] = 22,
[L''-Jbase] = 23, [L''-Jbase] = 24, [L''-Jbase] = 25,
[L''-Jbase] = 26, [L''-Jbase] = 27, [L''-Jbase] = 28,
};
#define Choidx(r) (choidx[(r) - Jbase] - 1)
#define Jungidx(r) (jungidx[(r) - Jbase] - 1)
#define Jongidx(r) (jongidx[(r) - Jbase] - 1)
static Rune jamomap[128] = { static Rune jamomap[128] = {
['r'] = L'', ['R'] = L'', ['r'] = L'', ['R'] = L'',
@@ -221,12 +199,23 @@ transko(Im *im, Rune c)
sputr(&e.next, compose(ci, ji, 0)); sputr(&e.next, compose(ci, ji, 0));
return e; return e;
} }
if(Jungidx(last) >= 0 && ji >= 0){ /* A vowel typed first is reordered under its consonant. */
if(Jungidx(last) >= 0 && Choidx(jm) >= 0){
sputr(&e.next, compose(Choidx(jm), Jungidx(last), 0));
return e;
}
/* Two vowels or two consonants may be one jamo, ㅘ or ㄳ. */
comb = combine(cvow, nelem(cvow), last, jm); comb = combine(cvow, nelem(cvow), last, jm);
if(comb == 0)
comb = combine(cjong, nelem(cjong), last, jm);
if(comb){ if(comb){
sputr(&e.next, comb); sputr(&e.next, comb);
return e; return e;
} }
if(ji >= 0 && splitpair(cjong, nelem(cjong), last, &stay, &next)){
sputr(&e.s, stay);
sputr(&e.next, compose(Choidx(next), ji, 0));
return e;
} }
e.s = im->pre; e.s = im->pre;
sputr(&e.next, jm); sputr(&e.next, jm);
@@ -294,14 +283,12 @@ backko(Im *im)
last = slastr(&im->pre); last = slastr(&im->pre);
if(!issyl(last)){ if(!issyl(last)){
if(splitpair(cvow, nelem(cvow), last, &stay, &next)){
spopr(&im->pre); spopr(&im->pre);
if(splitpair(cvow, nelem(cvow), last, &stay, &next) ||
splitpair(cjong, nelem(cjong), last, &stay, &next))
sputr(&im->pre, stay); sputr(&im->pre, stay);
return; return;
} }
spopr(&im->pre);
return;
}
decompose(last, &c, &j, &jo); decompose(last, &c, &j, &jo);
spopr(&im->pre); spopr(&im->pre);
if(jo > 0 && splitpair(cjong, nelem(cjong), jong[jo], &stay, &next)){ if(jo > 0 && splitpair(cjong, nelem(cjong), jong[jo], &stay, &next)){

View File

@@ -25,6 +25,12 @@ korean_sequences(struct ct *t)
{ "rr", "ㄱㄱ" }, { "rr", "ㄱㄱ" },
{ "Rk", "" }, { "Rk", "" },
{ "rk1", "가1" }, { "rk1", "가1" },
{ "rt", "" },
{ "rtk", "ㄱ사" },
{ "rtt", "ㄳㅅ" },
{ "kr", "" },
{ "hkr", "" },
{ "kk", "ㅏㅏ" },
}; };
Str out; Str out;
int i; int i;
@@ -81,6 +87,7 @@ korean_backspace(struct ct *t)
{ {
static const struct { char *before, *after; } cases[] = { static const struct { char *before, *after; } cases[] = {
{ "", "" }, { "", "" },
{ "", "" },
{ "", "" }, { "", "" },
{ "", "" }, { "", "" }, { "", "" }, { "", "" }, { "", "" }, { "", "" },
{ "", "" }, { "", "" }, { "", "" }, { "", "" }, { "", "" }, { "", "" },