Visitar URL original
tui: NumPad End/Home ignored under kitty keyboard protocol (Windows Terminal reports KP_END 57424) · Issue #55533 · anomalyco/opencode · GitHub
Skip to content

tui: NumPad End/Home ignored under kitty keyboard protocol (Windows Terminal reports KP_END 57424) #55533

Closed

Description

@shawnoster

Description

NumPad End (NumLock off) does nothing in the TUI, while the regular End key works. Same for the other NumPad navigation keys.

With the kitty keyboard protocol enabled, Windows Terminal reports NumPad End as KP_END (CSI 57424 u) rather than End. OpenCode doesn't treat it as End, so the default end bindings never fire. Outside OpenCode both keys send ^[[F, so the terminal is fine.

Expected: NumPad navigation keys behave like their regular equivalents (kpend → end, kphome → home, and so on), the same way opentui#1047 handled NumPad digits and Enter in the textarea.

Workaround: adding the kp* names to cli.json works (after restarting the TUI), so the key names are already parsed and accepted. They just aren't in the defaults:

"keybinds": {
  "input.line.home": "ctrl+a,home,kphome",
  "input.line.end": "ctrl+e,end,kpend"
}

Earlier reports of the same root cause were auto-closed in V1: #20461, #7698.

Plugins

None related (one local personal plugin)

OpenCode version

2.0.29

Steps to reproduce

  1. In Windows Terminal (WSL), with NumLock off, run printf '\e[>1u'; cat -v; printf '\e[<u'
  2. Press End, then NumPad End. Output: ^[[F^[[57424u
  3. Open OpenCode with default keybinds, scroll up in a session, and press End: it jumps to the last message. Press NumPad End: nothing happens.

Screenshot and/or share link

N/A

Operating System

Windows 11 + WSL2, Ubuntu 26 (Linux 6.18.54.1-microsoft-standard-WSL2)

Terminal

Windows Terminal

Activity

  1. opencode-agent commented on Oct 14, 2026

    @opencode-agent
    Contributor

    Thanks for the detailed report. I reproduced this on 2.0.29 and it still happens on the latest dev (13afea6a).

    What I did, using a simulated model:

    1. Started a session with a few long answers and pressed Home to scroll to the top.
    2. Sent the regular End sequence (ESC [ F). The view jumped to the last message, as expected.
    3. Pressed Home again, then sent NumPad End the way Windows Terminal sends it under the kitty protocol (ESC [ 57424 u). Nothing happened: the view stayed at the top with "Jump to latest ↓" showing.

    The key is recognised as kpend, but none of the default keybinds include the kp* names, which matches what you found. The recording and screenshots below show this, and the script below reproduces it. Until it's addressed, adding the kp* names to your cli.json keybinds, as you described, is the workaround.

    recording.mp4

    Screenshot

    Screenshot

    Reproduction script (drive.ts)
    // Repro for anomalyco/opencode#55533: NumPad End (kitty CSI 57424u -> "kpend") is ignored,
    // while regular End (CSI F) triggers session.last.
    import { Effect } from "effect"
    import { Llm, OpenCodeDriver } from "opencode-drive"
    
    const long = (n: number) =>
      Array.from({ length: 40 }, (_, i) => `Answer ${n}, line ${i + 1}`).join("\n\n")
    
    export default OpenCodeDriver.use(
      {
        ...(process.env.OC_DEV ? { opencode: { dev: process.env.OC_DEV } } : {}),
        tui: { recording: true, keypressOverlay: true },
      },
      ({ ui, llm }) =>
        Effect.gen(function* () {
          for (const n of [1, 2, 3]) {
            yield* llm.queue(Llm.text(long(n)))
            yield* ui.submit(`Question ${n}`)
            yield* ui.waitFor(`Answer ${n}, line 40`)
          }
          yield* Effect.sleep(500)
    
          // Scroll up to the first message
          yield* ui.press("home")
          yield* Effect.sleep(700)
          yield* ui.screenshot("1-after-home")
    
          // Regular End (CSI F): jumps to the last message
          yield* ui.press("\x1b[F")
          yield* Effect.sleep(700)
          yield* ui.screenshot("2-after-end")
    
          // Back to the top
          yield* ui.press("home")
          yield* Effect.sleep(700)
          yield* ui.screenshot("3-after-home-again")
    
          // NumPad End as sent by Windows Terminal under kitty protocol: CSI 57424 u
          yield* ui.press("\x1b[57424u")
          yield* Effect.sleep(1000)
          yield* ui.screenshot("4-after-numpad-end")
        }),
    )

    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.

  2. argszero commented on Oct 14, 2026

    @argszero
    Contributor

    I'd like to work on this.

    The diagnosis matches the code: the kp* key names are already parsed by the keymap layer, but none of the default bindings in packages/tui/src/config/keybind.ts list them, so a NumPad navigation key resolves to a name that no binding mentions and the press is dropped.

    I'll add the NumPad equivalents next to the keys they mirror in the defaults (kphome, kpend, kpleft, kpright, kpup, kpdown, kppageup, kppagedown, kpinsert, kpdelete), and cover it with a test that asserts a NumPad key resolves to the same action as its regular counterpart, rather than relying on the workaround in cli.json.

    I'll open a PR against dev and link this issue.

  3. added a commit that references this issue on Oct 19, 2026
    447a768
  4. argszero commented on Oct 22, 2026

    @argszero
    Contributor

    The fix for this is in PR #57114 (ecbb8d2d97), rebased onto current dev.

    Measured there: with the two defaults in packages/tui/src/config/keybind.ts reverted to none, typing aa, Shift+Enter, bb, then CSI 57423 u + x and CSI 57424 u + y gives aa\nbbxy — both keypad keys dropped, which is the reported behaviour. With the change it gives xaa\nbby and the transcript scroll position is unchanged. The test that pins it is keypad Home and End move the prompt cursor in packages/tui/test/session-prompt-keypad-home-end.test.tsx; it drives the real session route, not just the binding table.

    I had originally opened that PR against #57113 and have corrected its closing keyword to this issue, since #57113 is the duplicate.

  5. argszero commented on Oct 27, 2026

    @argszero
    Contributor

    The fix is now #59770, on the same commit (4c1cfb9335); #57114 was closed and re-opened so the change appears as a fresh pull request rather than an eight-day-old one. Nothing in the patch changed.

    Recap of what it does: session.first, session.last, session.page.up and session.page.down in packages/tui/src/config/keybind.ts now list the keypad key beside the plain key it mirrors (kphome, kpend, kppageup, kppagedown), so NumPad Home and End navigate the transcript exactly as plain Home and End do. The red-before-green measurement and the codepoint evidence are in the PR body.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions