Kitty keyboard protocol + macOS editing keybinds over the web terminal#79
Open
dkzlv wants to merge 8 commits into
Open
Kitty keyboard protocol + macOS editing keybinds over the web terminal#79dkzlv wants to merge 8 commits into
dkzlv wants to merge 8 commits into
Conversation
The Cmd+K command palette search input lacked autocomplete-suppression attributes, so the browser could show its native autocomplete/history dropdown over the palette. Add autocomplete/autocorrect/autocapitalize=off and spellcheck=false, matching the sibling overlays (Palette, Font, Remotes).
The Paste button fired from onPointerDown with e.preventDefault(), which suppresses the synthesized click. iOS Safari (WebKit) only authorises navigator.clipboard.readText() inside a genuine click/touch gesture, so the read rejected silently and pasting was a no-op. Route the Paste button through a real click via a new clickToActivate flag (other buttons keep their snappy pointerdown behaviour), and refocus the surface afterwards to keep the on-screen keyboard up.
Add a shared scrollbarStyle(theme) helper and apply it to every scrollable overlay/list: the Cmd+K switcher, theme/font pickers, remotes list, the generic OverlayPanel body, and the off-screen terminal rail. Uses CSS scrollbar-width/scrollbar-color so the scrollbar matches the active palette instead of the chunky native one.
The browser terminal only captured paste as text via the hidden textarea's input(insertFromPaste) event, and Ctrl+V's preventDefault suppressed the paste event entirely — so pasted images were silently dropped and TUIs like Claude Code read an empty clipboard on ^V. Intercept Ctrl+V to defer ^V, add a paste listener that forwards any clipboard image via sendClipboard(mime, bytes) to the compositor clipboard, then send ^V so the app reads a populated selection (transport messages are ordered). A fallback timer preserves ^V quoted-insert when no image/paste is present; Cmd+V / Ctrl+Shift+V text paths are unchanged.
The hidden capture textarea is kept empty, but iOS only auto-repeats Backspace while the field still has content to delete, so a held Backspace deleted a single character and stopped. Seed the textarea with an NBSP filler buffer on iOS so iOS's own key-repeat streams a deleteContentBackward per repeat; forward one DEL each and top the buffer back up on idle (or before it runs dry mid-hold). Filler is stripped from the typed-text and Ctrl/Alt modifier paths so it never reaches the shell.
The BLIT_EXPORT_SOCK row widened the Purpose column without realigning the rest of the table, tripping prettier --check in CI.
…erminal Modifier+key combos (Shift+Enter, Cmd+Backspace, Ctrl+Enter, ...) now reach TUIs like Claude Code instead of collapsing to their unmodified key, and macOS "natural text editing" chords work at a bare shell prompt. Kitty keyboard protocol (CSI-u), end-to-end: - alacritty-driver: enable kitty_keyboard; capture the CSI ? u query reply (Event::PtyWrite, previously dropped) and drain it back to the PTY; surface negotiated flags from TermMode in the frame snapshot. - remote: carry kitty_flags as a trailing S2C_UPDATE byte (old clients ignore it), force a frame on flag-only changes, parse defensively. - server: drain pty writes after driver.process(); reorder query replies so the CSI ? u answer isn't beaten by DA1. - browser: expose Terminal.kitty_flags() to JS. - js/core: new kitty.ts CSI-u encoder; keyboard.ts delegates to it when flags != 0 and stays byte-identical to the legacy path when flags == 0. macOS natural text editing keybinds (browser-side, gated on kitty == 0): - macEditingKeybind() maps Cmd/Option editing chords to the legacy control bytes readline/ZLE already bind (Cmd+Backspace -> Ctrl+U, Cmd+arrows -> Ctrl+A/E, Opt+Backspace -> Meta-DEL, Opt+arrows -> Meta-b/f), so they work at a plain shell without shell config, while a kitty-aware app still receives the real combo as CSI-u. Also: add pkgs.git to the dev shell and a virtual:blit-wasm module declaration for the website's typecheck.
Coverage
|
|
🔗 Preview: https://blit-k73dskpc4-indent.vercel.app |
Contributor
Hmmm? |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Two related fixes so keyboard input over blit's web terminal behaves like a native terminal.
1. Kitty keyboard protocol (CSI-u), end-to-end
Modifier+key combos (Shift+Enter, Cmd+Backspace, Ctrl+Enter, …) previously collapsed to their unmodified key because a PTY is a raw byte stream and the legacy xterm encoding has no sequence for them. This implements the modern kitty keyboard protocol, which encodes every key as
CSI <codepoint>;<modifier-bitmask> uand only activates for apps that negotiate it — so combos now reach TUIs like Claude Code without regressing other apps.kitty_keyboard; capture theCSI ? ucapability-query reply (Event::PtyWrite, which we were dropping) and drain it back to the PTY; surface negotiated flags fromTermModein the frame snapshot.kitty_flagsas a trailingS2C_UPDATEbyte (old clients ignore it), force a frame on flag-only changes, parse defensively by payload length.driver.process(); reorder query replies so theCSI ? uanswer isn't beaten by DA1 (which would read as "no kitty").Terminal.kitty_flags()to JS.kitty.tsCSI-u encoder;keyboard.tsdelegates to it when flags != 0 and stays byte-identical to the legacy path when flags == 0.2. macOS "natural text editing" keybinds
At a bare shell prompt the kitty protocol is inactive (by design), so Cmd/Option editing chords did nothing. Mirroring Ghostty's default macOS keybinds,
macEditingKeybind()translates them to the legacy control bytes readline/ZLE already bind — so they work at a plain shell with no shell config, while a kitty-aware app still receives the real combo as CSI-u:Ctrl+UCtrl+A/Ctrl+EMeta-DELMeta-b/Meta-fGated on macOS and on
kittyFlags === 0.Testing
Local CI green:
./bin/lint— cargo fmt, prettier, clippy (-D warnings) all clean./bin/tests— Rust workspace tests pass; JS typecheck; core 388 / react 11 / solid 11 vitest; Python + Bun fd-channelNotes
quality-of-life-fixeshad a pre-existingprettier --checkfailure ondocs/server.md(unrelated table drift); fixed directly on that branch and this is rebased on top.pkgs.gitin the dev shell and avirtual:blit-wasmmodule declaration for the website typecheck.