Skip to content

fix: retire kitty ctrl+v interception (XWayland breaks router tmux detection)#2

Merged
NagyVikt merged 2 commits into
mainfrom
fix/retire-kitty-ctrlv-map-xwayland
Jun 10, 2026
Merged

fix: retire kitty ctrl+v interception (XWayland breaks router tmux detection)#2
NagyVikt merged 2 commits into
mainfrom
fix/retire-kitty-ctrlv-map-xwayland

Conversation

@NagyVikt

Copy link
Copy Markdown
Collaborator

Why

PR #1 widened the daemon dedup window to 2.5s and fixed the router's socket resolution — but double-pastes persisted. Root cause found today: the kitty→XWayland switch breaks the router's entire detection premise. kitten @ ls reports is_focused=false for every OS window and empty foreground_processes, so focused_window_is_tmux() can never return true. Every Ctrl+V in kitty took the slow fallthrough (background launch spawn, seconds late under load), and the late second fire landed outside any reasonable dedup window — the journal shows identical 162-byte text pastes 4s apart (pane %23 at 15:14:50 and 15:14:54).

What

  • config/keybindings.canonical: kitty ctrl+vUNBOUND — kitty must NOT intercept Ctrl+V. tmux's bind -n C-v becomes the single handler: ~5ms via flashpaste-trigger, and the pane id comes from the pressing client (also killing the wrong-pane hazard of the router's target-less tmux display-message). Non-tmux kitty windows: the raw 0x16 reaches Claude Code, which reads the clipboard itself via the wl-paste shim; plain shells use kitty-native ctrl+shift+v.
  • bin/flashpaste-keybindings-check.sh: new UNBOUND keyword — asserts a key must not be bound on a surface (checker previously only supported positive substring rules).
  • bin/kitty-paste-router.sh: retired-status header + tracing to the shared clipboard-pipeline log (it was the only paste path that wrote no logs — which is why this regression was invisible).
  • tests/keybindings-check.test.sh: covers UNBOUND pass/violation, keeps positive-rule and literal-+ coverage via fixture canonicals.

Test plan

  • bash tests/keybindings-check.test.sh — 6/6 pass
  • bash tests/kitty-focused-is-tmux.test.sh, tests/wl-paste-guard.test.sh — pass
  • bash bin/flashpaste-keybindings-check.sh against live configs — consistent
  • Live: ctrl+v map removed from kitty.conf + kitten @ load-config reload; tmux-bind path verified single-paste end-to-end (sentinel via kitten @ send-key → one daemon request, one paste, 38 bytes)
  • Real-keypress Ctrl+V verification by user (synthetic XTEST keys don't reach kitty's keymap)

🤖 Generated with Claude Code

…etection

Under XWayland kitty, `kitten @ ls` reports is_focused=false for every OS
window and empty foreground_processes, so kitty-paste-router.sh's
focused_window_is_tmux() can never succeed. Every Ctrl+V took the slow
fallthrough (background launch, seconds late under load) and the late
second fire landed outside the daemon's 2.5s dedup window — journal shows
identical 162-byte text pastes 4s apart (pane %23, 15:14:50 + 15:14:54).

Fix: kitty must not bind ctrl+v at all. tmux's own `bind -n C-v` is the
single handler (~5ms, pane id from the pressing client — also kills the
wrong-pane hazard of the router's target-less `tmux display-message`).
Non-tmux kitty windows: raw 0x16 reaches Claude Code, which reads the
clipboard itself via the wl-paste shim; plain shells use ctrl+shift+v.

- keybindings.canonical: kitty ctrl+v -> UNBOUND (new keyword)
- flashpaste-keybindings-check.sh: support UNBOUND (binding must not exist)
- kitty-paste-router.sh: retired-status header + clip-pipeline-log tracing
  (it was the only paste path with zero logging)
- tests/keybindings-check.test.sh: cover UNBOUND pass/violation + keep
  positive-rule and literal-+ coverage via fixture canonicals

@NagyVikt NagyVikt left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI review (independent fresh-context agent): APPROVE — 0 CRITICAL, 0 HIGH, 0 MEDIUM, 3 LOW.

  • UNBOUND keyword logic verified: surface-dispatch → UNBOUND check → continue flow is correct; literal + escaping covered by tests.
  • clog tracing guard matches the established pipeline pattern; no set -u traps; no injection surface (quoted args to a printf >> logger).
  • Tests 6/6 pass; bash -n clean; manual shellcheck analysis of new lines against the CI gate (-S warning -e SC1090,SC2034,SC2155) finds no new warnings.

LOW (non-blocking): missing-conf file silently satisfies UNBOUND (pre-existing gap shared with positive rules); pre-existing hardcoded paste_image.sh default path; no fixture for UNBOUND-with-absent-conf. Full artifact: .claude/reviews/pr-2-review.md.

shellcheck -S warning (CI gate) parses $key_re[[:space:]] as an array
expansion and errors. Introduced with the checker in PR #1; this was the
shellcheck regression that turned main's Lint job red. Braces quiet it
with no behavior change (tests 6/6, live check consistent).
@NagyVikt NagyVikt merged commit 0bdcd37 into main Jun 10, 2026
5 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant