engine: Ctrl+H converts the pending syllable; Backspace on an empty search stays put

Ctrl+H committed the syllable being composed and opened an empty search,
so converting 한 meant typing it twice; the pending syllable now seeds the
query. Backspace on an already empty search ended it and then reached the
application, deleting a character; it now only ends the search.
This commit is contained in:
2026-08-16 21:30:16 +09:00
parent 5e72a48c2c
commit 91b3e538f1
3 changed files with 48 additions and 24 deletions

View File

@@ -28,8 +28,8 @@ what is pending; `Esc` cancels it.
Hiragana mode composes a complete reading before offering Kanji candidates. Hiragana mode composes a complete reading before offering Kanji candidates.
Katakana mode does not perform Kanji conversion. Emoji and Hanja searches Katakana mode does not perform Kanji conversion. Emoji and Hanja searches
return to the previous mode after use; switching language during a search return to the previous mode after use; switching language during a search
commits the shown query. The Hanja dictionary lists one modern Hangul commits the shown query. `Ctrl+H` takes the syllable being composed as its
syllable at a time. query; the Hanja dictionary lists one modern Hangul syllable at a time.
## Preedit and candidates ## Preedit and candidates

View File

@@ -10,10 +10,12 @@ static Drawcmd lastdraw;
static Emit transjp(Im*, Rune); static Emit transjp(Im*, Rune);
static void backjp(Im*); static void backjp(Im*);
/* seed is what Ctrl+H found pending; raw the keys typed since; text both. */
typedef struct Search Search; typedef struct Search Search;
struct Search struct Search
{ {
int lang; int lang;
Str seed;
Str raw; Str raw;
Str text; Str text;
}; };
@@ -228,18 +230,6 @@ redraw(void)
channbsend(drawc, &dc); channbsend(drawc, &dc);
} }
static void
reset(void)
{
sclear(&im.pre);
sclear(&im.raw);
search.lang = 0;
sclear(&search.raw);
sclear(&search.text);
memset(&caret, 0, sizeof caret);
clearkouho();
}
/* Kanji candidates for a complete reading. */ /* Kanji candidates for a complete reading. */
static void static void
dictqjp(void) dictqjp(void)
@@ -526,9 +516,11 @@ hanjaquery(void)
Str key; Str key;
transstr(im.l, &search.raw, &key); transstr(im.l, &search.raw, &key);
search.text = key; search.text = search.seed;
sappend(&search.text, &key);
clearkouho(); clearkouho();
im.nkouho = dictlookup(getlang(LangHANJA), &key, im.kouho, Maxkouho); im.nkouho = dictlookup(getlang(LangHANJA), &search.text, im.kouho,
Maxkouho);
selectfirst(); selectfirst();
} }
@@ -551,11 +543,21 @@ static void
endsearch(void) endsearch(void)
{ {
search.lang = 0; search.lang = 0;
sclear(&search.seed);
sclear(&search.raw); sclear(&search.raw);
sclear(&search.text); sclear(&search.text);
clearkouho(); clearkouho();
} }
static void
reset(void)
{
sclear(&im.pre);
sclear(&im.raw);
endsearch();
memset(&caret, 0, sizeof caret);
}
static void static void
commitsearch(Str *com) commitsearch(Str *com)
{ {
@@ -563,13 +565,27 @@ commitsearch(Str *com)
endsearch(); endsearch();
} }
/* A search commits whatever is pending and takes over the keys. */ /*
* A search takes over the keys. Hanja converts the pending syllable, so
* it becomes the query; anything else pending is committed.
*/
static void static void
startsearch(int lang, Str *com) startsearch(int lang, Str *com)
{ {
commit(com); Str pending;
impre(&im, &pending);
if(lang == LangHANJA){
sclear(&im.pre);
sclear(&im.raw);
}else
commit(com);
commitsearch(com); commitsearch(com);
search.lang = lang; search.lang = lang;
if(lang == LangHANJA){
search.seed = pending;
searchquery();
}
} }
/* /*
@@ -635,11 +651,14 @@ searchkey(u32int ks, u32int mod, Str *com)
return 1; return 1;
} }
if(ks == Kback){ if(ks == Kback){
if(search.raw.n == 0){ if(search.raw.n != 0)
spopr(&search.raw);
else if(search.seed.n != 0)
spopr(&search.seed);
else{
endsearch(); endsearch();
return 0; return 1;
} }
spopr(&search.raw);
searchquery(); searchquery();
return 1; return 1;
} }

View File

@@ -1744,15 +1744,20 @@ engine_hanja_backspace(struct ct *t)
CT_CHECK(t, keystroke(Kback, 0, &com)); CT_CHECK(t, keystroke(Kback, 0, &com));
checkstr(t, "empty Hanja search", "", &search.text); checkstr(t, "empty Hanja search", "", &search.text);
CT_EQ_INT(t, LangHANJA, search.lang); CT_EQ_INT(t, LangHANJA, search.lang);
CT_CHECK(t, !keystroke(Kback, 0, &com)); CT_CHECK(t, keystroke(Kback, 0, &com));
CT_EQ_INT(t, 0, search.lang); CT_EQ_INT(t, 0, search.lang);
/* Ctrl+H converts the pending syllable: it seeds the query. */
if(!typekeys(t, "gks", &com)) if(!typekeys(t, "gks", &com))
goto cleanup; goto cleanup;
CT_CHECK(t, keystroke('h', Mctrl, &com)); CT_CHECK(t, keystroke('h', Mctrl, &com));
checkstr(t, "preedit committed before Hanja", "", &com); checkstr(t, "nothing committed before Hanja", "", &com);
checkstr(t, "pending syllable is the query", "", &search.text);
CT_EQ_INT(t, 2, im.nkouho);
CT_CHECK(t, keystroke(Kback, 0, &com));
checkstr(t, "seed backspaced", "", &search.text);
CT_EQ_INT(t, LangHANJA, search.lang); CT_EQ_INT(t, LangHANJA, search.lang);
CT_CHECK(t, !keystroke(Kback, 0, &com)); CT_CHECK(t, keystroke(Kback, 0, &com));
CT_EQ_INT(t, 0, search.lang); CT_EQ_INT(t, 0, search.lang);
CT_EQ_INT(t, LangKO, im.l->lang); CT_EQ_INT(t, LangKO, im.l->lang);
cleanup: cleanup: