Repository navigation
fix(canvas): keep a hovered terminal's keyboard after the pointer leaves (sloppy focus) - #1162
Merged
Merged
Conversation
…ves (sloppy focus) With the default focus-follows-pointer, a hover dwell gave a terminal the keyboard and mouseleave took it straight back: the xterm was blurred and the node dropped its active flag and presence focus. Typing into a terminal while the mouse rested on the canvas (or on the sidebar, or on the way to another card) silently went nowhere. Now the dwell only TAKES the keyboard. The terminal keeps it until another node takes it (its own dwell, a click) or the user clicks elsewhere — X11's "sloppy focus". Release follows DOM focus through the same useClickToFocus hook click-to-focus already uses (#757), which now runs in both modes. Only the hover guard still follows the pointer in this mode (leaving re-arms it, so a pass-over scroll keeps panning the canvas), so the hook's setArmed is gated by focusDrivesGuard. A dwell onto a node whose ⌘M view covers its xterm cannot take the keyboard itself, so it blurs the previous terminal's xterm (dwellBlursForeignTerminal) instead of leaving it receiving keystrokes while another node reads as active. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Merged
nexusatemporal
pushed a commit
to nexusatemporal/nodeterm
that referenced
this pull request
Oct 10, 2026
Version bump 0.4.2 → 0.4.3 — 20 PRs / 80 commits since v0.4.2. - **eneskirca#1159 — the one to ship for.** Hold-to-talk could leave a live microphone that typed into the selected terminal one line every 0–2 minutes for ~10 minutes, sometimes the user's meeting speech. Reported from 0.3.16 and present across many versions. Root cause: `startRecording` stored the capture in `captureRef` only AFTER `await capture.start()` resolved, so an overlay that closed inside that window (a <400 ms Cmd+Alt tap, any Cmd+Opt+<key>, a window blur) left the unmount cleanup with nothing to cancel. - **eneskirca#1118** run node: `.vscode/launch.json` "Run Without Debugging" on the canvas, with Flutter hot reload / hot restart / reload-on-save. - **eneskirca#1154** resize from every edge under Liquid Glass + window-management fixes; **eneskirca#1162** sloppy focus keeps a hovered terminal's keyboard after the pointer leaves. - **eneskirca#1137** Live links: Figma-style create dialog; **eneskirca#1160** Billing & invoices → Stripe customer portal. - **eneskirca#1157** agent confirms offer "don't ask again for agents in <project>"; **eneskirca#1107** ask before writing agent config, skills replace AGENTS.md blocks; **eneskirca#1125** chat-view prompts typed, not pasted; **eneskirca#1111** bounded concurrency + progress for bulk restarts; **eneskirca#836** arrange by lineage and inside a group; **eneskirca#1142** strikethrough in the shared GPU renderer; **eneskirca#1155** readable Agents/Accounts settings. - **eneskirca#701** zustand 4 → 5 major; **eneskirca#1121/eneskirca#1122/eneskirca#1126** share/palette/relay fixes. docs/release-notes/v0.4.3.md is the Highlights block. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
Problem
With the default Terminal focus follows pointer (ON), hovering a terminal for the pan-hover delay gave it the keyboard — and moving the pointer off it took the keyboard straight back (
onBodyLeaveblurred the xterm and dropped the node's active flag + presence focus). Typing into a terminal while the mouse rested on the canvas, the sidebar, or on its way to another card silently went nowhere.Change — sloppy focus
The hover dwell now only takes the keyboard. The terminal keeps it until:
How:
onBodyLeaveno longer blurs/releases in either mode; in focus-follows-pointer mode it only re-arms the hover guard (pointerLeaveRearmsGuard), so a pass-over scroll still pans the canvas until the next dwell.useClickToFocushook (feature request: option to disable X Window focus-follows-pointer (Mac-style click to select what UI element has the input focus) #757), which now runs in both modes (theenabledparam is gone). ItssetArmedis a no-op in focus-follows-pointer mode (focusDrivesGuard) — the guard stays a pointer contract there, so a ⌘K / sidebar release can't strand an armed guard under a resting pointer, and a header-drag reclaim can't drop it while the pointer is elsewhere.dwellBlursForeignTerminal) instead of leaving that pane receiving keystrokes while another node reads as active. Stickies/editors/fields keep their caret, as before.CLAUDE.mdand the module docs updated.Click to focus (setting OFF) is unchanged.
Surfaces
ModalTerminalhas no hover guard).Tests
terminalFocusMode.test.ts):pointerLeaveRearmsGuard,focusDrivesGuard,dwellBlursForeignTerminal, plus wiring checks thatonBodyLeavecontains no blur /setActive(id, false)/releaseFocus.useClickToFocus.test.tsx): a terminal the pointer has left keeps the keyboard and stays active; another terminal's xterm taking focus releases it.onBodyLeave, or ungatingsetArmed, turns the suite red.npm run typecheck/ full renderer suites on this box: only pre-existing env failures from a stale sharednode_modules(ssh2missing, monaco 0.52 vs ^0.57) — identical on cleanmain.Mac verification owed
🤖 Generated with Claude Code