[BUG] Shift+PageUp/PageDown falls back to plain PageUp/PageDown, breaking Konsole scrollback (regression in 2.1.269)
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet (closest are #70309 and #51393 — both about mouse-tracking-related scroll loss on older, pre-kitty-protocol versions, a different mechanism from this report)
- [x] This is a single bug report
- [x] I am using the latest version of Claude Code
What's Wrong?
Summary: Introduced in 2.1.269 (bisected; see "Is this a regression?" below), which expanded kitty keyboard protocol negotiation to more terminals including Konsole. Since then, Shift+PageUp/PageDown falls back to Claude Code's plain-PageUp/PageDown behavior (chat-input line navigation) instead of passing through to the terminal — and this fallback fires even when the combination is explicitly unbound via "shift+pageup": null in keybindings.json, not just when it's left unconfigured. In KDE Konsole this permanently breaks the terminal's native Shift+PageUp/PageDown scrollback shortcut while Claude Code is running, since Konsole correctly hands the keystroke to the app once the protocol is negotiated, and Claude Code's fallback then swallows it regardless of user configuration.
Observed behavior: with the cursor in Claude Code's chat input, Shift+PageUp/PageDown behaves like plain PageUp/PageDown — Claude Code's own line/cursor navigation (jump to line start, then previous line on repeats) fires instead of Konsole's scrollback. Exiting Claude Code restores normal Shift+PageUp/PageDown scrollback immediately.
Why this matters: by default, Claude Code has no keybinding at all for Shift+PageUp/PageDown (confirmed via the keybindings action table). Konsole does not expose Shift+PageUp/PageDown as a rebindable shortcut anywhere in Configure Shortcuts either — it's hardcoded in the terminal emulation widget — so there is no terminal-side workaround once Claude Code intercepts it, and no way for the user to give the terminal back the keystroke short of a keybindings.json workaround (see below).
Investigation
1. Raw PTY capture (xxd reading stdin, no Claude Code involved) — comparing legacy mode to kitty protocol forced on with printf '\e[>31u' (the same disambiguation request Claude Code issues):
| Mode | Plain PageUp | Shift+PageUp |
|---|---|---|
| Legacy (no kitty protocol) | ESC[5~ (1b 5b 35 7e) | nothing sent — Konsole intercepts it for its own scrollback |
| Kitty protocol enabled | ESC[5~, or ESC[5;1:3~ in full-disambiguation form | ESC[5;2~ and ESC[5;2:3~ — modifier field 2 = Shift, per spec |
Konsole behaves correctly here: once the protocol is negotiated, it stops intercepting the combo and forwards it with the modifier intact, trusting the application to read it.
2. Syscall-level capture inside Claude Code itself, via:
strace -f -e trace=read -s 200 -o claude-strace.log claude
Pressing plain PageUp then Shift+PageUp produced these read()s on Claude Code's own stdin fd:
read(8, "\33[5~", 262144) = 4 # plain PageUp
read(8, "\33[5;2~", 262144) = 6 # Shift+PageUp
The complete 6-byte sequence, modifier included, reaches Claude Code's process unmodified.
3. Binding test. Adding an explicit binding in ~/.claude/keybindings.json:
{ "context": "Global", "bindings": { "shift+pageup": "app:toggleTranscript" } }
makes Shift+PageUp correctly and reliably trigger app:toggleTranscript (confirmed: it opens the transcript view, and does not also trigger plain PageUp's line-navigation). This took effect immediately, without restarting Claude Code.
4. Explicit-unbind test. Setting
{ "context": "Global", "bindings": { "shift+pageup": null } }
in ~/.claude/keybindings.json, then restarting Claude Code, does not restore pass-through. With text spanning multiple lines in the chat input, Shift+PageUp with this explicit null override still behaves exactly like plain PageUp (cursor jumps to line start, then previous line on repeats).
Conclusion: Claude Code's input layer does correctly decode and distinguish the Shift modifier — test 3 rules out a parsing/decoding bug. The bug is in the fallback dispatch for Shift+PageUp/PageDown: it falls back to the plain-PageUp/PageDown handler not only when no binding is configured, but even when the user has explicitly unbound the combination with null. Per the keybindings documentation, null is supposed to remove a shortcut's binding; for this combination it does not — the plain-PageUp fallback still intercepts it either way, and only overriding it with a concrete action (test 3) escapes the fallback. That makes this a dispatch/fallback bug independent of whatever keybindings.json says, not something a user can currently work around with a null override alone.
This is adjacent to, but distinct from, the already-fixed 2.1.269 regressions (F1/F2/F4 in kitty-protocol terminals, Shift+punctuation in WezTerm, Alt+arrows in rxvt-unicode) — those were decoding bugs; this is a default-dispatch/fallback bug for a specific unbound key combination.
What Should Happen?
Setting "shift+pageup": null (and "shift+pagedown": null) in keybindings.json should unbind the combination and let it reach the terminal, per the documented behavior of null. Currently the plain-PageUp/PageDown fallback still intercepts it regardless of the null override, so the only working workaround is binding it to a concrete action (e.g. app:toggleTranscript) purely to prevent the fallback from firing — an unintended side channel, not an intentional way to "disable" a shortcut.
Steps to Reproduce
- Open KDE Konsole.
- Run
claude(inline/non-fullscreen mode, no special flags, default keybindings). - Produce enough output to have scrollback.
- With the cursor in the chat input field, press Shift+PageUp.
- Expected: Konsole scrolls its scrollback.
- Actual: nothing scrolls; the input field's cursor jumps as if plain PageUp were pressed (to line start, then previous line on repeats).
- Exit Claude Code (
/exit). - Press Shift+PageUp again — Konsole scrolls back normally.
Is this a regression?
Yes. Bisected directly using claude install <version> to switch the active build and retesting with default keybindings (no keybindings.json present) at each step:
| Version | Behavior |
|---|---|
| 2.1.240 | good |
| 2.1.252 | good |
| 2.1.261 | good |
| 2.1.266 | good |
| 2.1.268 | good (confirmed twice) |
| 2.1.269 (released 2026-09-11) | bad |
| 2.1.270 | bad |
The regression was introduced in 2.1.269, matching that version's changelog entry: "Improved keyboard support over SSH and in unrecognized terminals: terminals that answer the kitty keyboard query (such as foot and Alacritty 0.16+) now get Shift+Enter and Ctrl+Shift shortcuts" — Konsole answers this query, so this is almost certainly the change that put it into the affected path.
Claude Code Version
2.1.270
Platform
Anthropic API
Operating System
Linux (Arch)
Terminal/Shell
Konsole 26.08.1 (KDE), bash, TERM=xterm-256color
Additional Information
Related but distinct issues (mouse-tracking-caused scroll loss on older, pre-kitty-protocol versions — not this fallback-dispatch issue): #70309, #51393