You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
tui: keypad PageUp/PageDown/Home/End ignored by the error screen, error details, /btw and mini footers #58946
NumPad PageUp / PageDown / Home / End do nothing in several TUI views, while the regular keys work. Scaffolding sections that hardcode a comparison against event.name compare against pageup, pagedown, home, end, but under the kitty keyboard protocol a keypad press reports its own key name.
Measured on dev (a41d09bc78) by driving the real input path (app.renderer.stdin → KeyHandler → useKeyboard):
key sent
name the handler receives
keypad End (CSI 57424 u)
kpend
keypad Home (CSI 57423 u)
kphome
keypad PageUp (CSI 57421 u)
kppageup
keypad PageDown (CSI 57422 u)
kppagedown
keypad Up / Down / Left / Right
kpup / kpdown / kpleft / kpright
regular End / CSI 5 ~ PageUp
end / pageup
So a guard like if (event.name === "end") fires 1 time for the regular key and 0 times for the keypad key.
Affected comparisons (all reached through useKeyboard, i.e. raw events):
packages/tui/src/component/error-component.tsx:94-97 — the error screen; PageUp/PageDown/Home/End cannot scroll the stack trace.
packages/tui/src/component/dialog-error-details.tsx:74-77 — the error details dialog.
packages/tui/src/feature-plugins/prompt/btw.tsx:120-123 — the /btw answer panel.
The keypad Up/Down/Left/Right comparisons in the same handlers miss for the same reason.
Why the cli.json workaround does not cover this
#55533 documents that adding kp* names to cli.json restores the affected bindings. These six sites never consult the keymap: each subscribes to renderer.keyInput via useKeyboard and compares the raw event name, so no binding and no alias table is involved. The keypad keys stay dead there even with cli.json configured.
@opentui/core already knows the equivalence (defaultKeyAliases maps kpend → end, kppageup → pageup, …), but it applies it to binding lookups only, not to the events a raw handler receives.
Expected behaviour
Keypad navigation keys behave like their regular equivalents in these views, so a keyboard with NumLock off can scroll the error screen, the error details dialog, /btw and the mini footers.
Related
#55533 is the binding-side counterpart and stays open; this covers the raw-handler sites it cannot reach.
Thanks for the detailed report! I could reproduce this in the /btw answer panel.
Steps: I opened a session, asked a /btw question whose simulated answer was 80 lines long, then sent the kitty keypad sequences CSI 57424 u (End), CSI 57422 u (PageDown) and CSI 57423 u (Home). None of them scrolled the panel, while the regular End and Home keys did. It happens on 2.1.4 and on the latest dev (a41d09bc78). The recording and screenshots below show it, and the script below reproduces it.
I only ran the /btw panel. The error screen, the error details dialog and the mini footers use the same event.name checks in the code, so they are very likely affected the same way. Your PR #58947 targets exactly this, and #55533 remains the separate issue for keypad keys in keybindings.
recording.mp4
Reproduction script (drive.ts)
// Repro for #58946: keypad End/Home (kitty CSI-u) do nothing in the /btw answer panel,// while the regular End/Home keys scroll it.import{Effect,Stream}from"effect"import{Llm,OpenCodeDriver}from"opencode-drive"constlines=Array.from({length: 80},(_,i)=>`answer line ${i+1}`)constanswer=lines.join("\n\n")constKP_END="\x1b[57424u"constKP_HOME="\x1b[57423u"constKP_PAGE_DOWN="\x1b[57422u"exportdefaultOpenCodeDriver.use({
...(process.env.OC_DEV ? {opencode: {dev: process.env.OC_DEV}} : {}),tui: {recording: true,keypressOverlay: true},},({ ui, llm })=>Effect.gen(function*(){yield*llm.serve((request)=>Stream.make(JSON.stringify(request).includes("what are the lines") ? Llm.text(answer) : Llm.text("Hello.")),)yield*ui.submit("hi")yield*Effect.sleep(4000)yield*ui.submit("/btw what are the lines?")yield*Effect.sleep(6000)yield*Effect.sleep(800)yield*ui.screenshot("1-btw-open")// Keypad End: should jump to the bottomyield*ui.press(KP_END)yield*Effect.sleep(800)constkpEnd=yield*ui.matches("answer line 80")yield*ui.screenshot("2-after-keypad-end")// Keypad PageDown: should scroll down a pageyield*ui.press(KP_PAGE_DOWN)yield*Effect.sleep(800)constkpPgDn=!(yield*ui.matches("answer line 12"))yield*ui.screenshot("3-after-keypad-pagedown")// Regular End: jumps to the bottomyield*ui.press("end")yield*Effect.sleep(800)constend=yield*ui.matches("answer line 80")yield*ui.screenshot("4-after-regular-end")// Keypad Home: should jump back to topyield*ui.press(KP_HOME)yield*Effect.sleep(800)constkpHome=!(yield*ui.matches("answer line 80"))yield*ui.screenshot("5-after-keypad-home")// Regular Homeyield*ui.press("home")yield*Effect.sleep(800)consthome=!(yield*ui.matches("answer line 80"))yield*ui.screenshot("6-after-regular-home")yield*Effect.log(JSON.stringify({keypadEndReachedBottom: kpEnd,keypadPageDownScrolled: kpPgDn,regularEndReachedBottom: end,keypadHomeReachedTop: kpHome,regularHomeReachedTop: home}),)}),)
Run it with opencode-drive: opencode-drive run ./drive.ts. It drives opencode from your PATH; set OC_DEV to the path of an OpenCode checkout to run that from source instead.
Activity
opencode-agent commentedon Oct 25, 2026
Thanks for the detailed report! I could reproduce this in the
/btwanswer panel.Steps: I opened a session, asked a
/btwquestion whose simulated answer was 80 lines long, then sent the kitty keypad sequencesCSI 57424 u(End),CSI 57422 u(PageDown) andCSI 57423 u(Home). None of them scrolled the panel, while the regular End and Home keys did. It happens on 2.1.4 and on the latestdev(a41d09bc78). The recording and screenshots below show it, and the script below reproduces it.I only ran the
/btwpanel. The error screen, the error details dialog and the mini footers use the sameevent.namechecks in the code, so they are very likely affected the same way. Your PR #58947 targets exactly this, and #55533 remains the separate issue for keypad keys in keybindings.recording.mp4
Reproduction script (drive.ts)
Run it with opencode-drive:
opencode-drive run ./drive.ts. It drivesopencodefrom yourPATH; setOC_DEVto the path of an OpenCode checkout to run that from source instead.