engine: a page key on an untouched list turns the page

movekouho() answers every one of Up, Down, PageUp and PageDown the same
way when nothing is chosen yet -- `if(im.sel < 0) im.sel = 0;` -- and
delta is thrown away.  For Up and Down that is right: the list is drawn
with no cursor, so the first move takes the first candidate.  For
PageDown it is not, because there is no page state to move; pagefirst()
derives the page from im.sel alone, so selecting candidate 1 leaves the
page exactly where it was.

dictqjp() leaves sel at -1 on every keystroke, so a Japanese list is
always untouched when it first appears.  Type かく, look at its thirty
candidates, and press PageDown for the next nine:

	                     before          after
	かく, PageDown        sel 0, page 0   sel 9, page 9
	かく, PageDown twice  sel 9, page 9   sel 18, page 18
	かく, PageUp          sel 0, page 0   unchanged
	かく, Down            sel 0, page 0   unchanged

Nothing on screen answers the first press but the highlight appearing on
row 1, and the page turns only on the second.  fcitx5 pages on the first,
because its candidate list carries a page of its own and
toPageable()->next() does not touch the cursor
(ref-fcitx5-hangul/src/engine.cpp:326-336).  strans has one number where
fcitx5 has two, which is the right trade for nine rows and 128
candidates -- but then the number has to move by a page when a page key
asks for one.

`delta == Maxdisp` rather than `delta > 0` is deliberate: Down must still
land on candidate 1, and writing it the loose way fails both this table
and engine/japanese-candidates at engine_test.c:1198, where the language
switch takes 漢字 and would take 幹事 instead.  PageUp from an untouched
list still clamps to 0; there is no page above the first.

searchkey shares movekouho, and is unaffected: emojiquery and hanjaquery
both end in selectfirst(), so a search list is never untouched while it
has candidates.
This commit is contained in:
2026-08-18 09:14:39 +09:00
parent bfcd9f6786
commit c9c01fdeb9
2 changed files with 6 additions and 1 deletions

View File

@@ -91,11 +91,12 @@ movedelta(u32int ks)
return 0;
}
/* Nothing chosen yet: Down takes the first candidate, PageDown pages. */
static void
movekouho(int delta)
{
if(im.sel < 0)
im.sel = 0;
im.sel = delta == Maxdisp ? Maxdisp : 0;
else
im.sel += delta;
if(im.sel < 0)

View File

@@ -871,6 +871,10 @@ engine_candidate_page_movement(struct ct *t)
{ 32, 22, Kpgdown, 31 },
{ 32, 31, Kpgup, 22 },
{ 32, 31, Kpgdown, 31 },
{ 32, -1, Kdown, 0 },
{ 32, -1, Kup, 0 },
{ 32, -1, Kpgdown, 9 },
{ 32, -1, Kpgup, 0 },
};
int first, i, n;
Str com;