Skip to content

fix(terminal): restore DEC private modes on focus-in to fix Windows Terminal mouse tracking#655

Merged
kommander merged 3 commits intomainfrom
fix/focus-restore-terminal-modes
Feb 10, 2026
Merged

fix(terminal): restore DEC private modes on focus-in to fix Windows Terminal mouse tracking#655
kommander merged 3 commits intomainfrom
fix/focus-restore-terminal-modes

Conversation

@Hona
Copy link
Member

@Hona Hona commented Feb 9, 2026

When Windows Terminal / ConPTY loses focus (alt-tab, minimize, tab switch), it silently strips DEC private mode escape codes even though the app's internal state still thinks they're enabled.

Now we listen to the focus signal and resend the escape codes.

…erminal mouse tracking

When Windows Terminal / ConPTY loses focus (alt-tab, minimize, tab switch),
it can silently strip DEC private mode escape codes like mouse tracking
(?1000/?1002/?1003/?1006), focus tracking (?1004), and bracketed paste
(?2004). This adds a restoreTerminalModes function that unconditionally
re-sends all currently-active mode sequences when the focus-in event
(ESC[I) is received, restoring mouse tracking and other terminal modes.
Copilot AI review requested due to automatic review settings February 9, 2026 09:36
@pkg-pr-new
Copy link

pkg-pr-new bot commented Feb 9, 2026

@opentui/core

npm i https://pkg.pr.new/anomalyco/opentui/@opentui/core@a90e7bc

@opentui/react

npm i https://pkg.pr.new/anomalyco/opentui/@opentui/react@a90e7bc

@opentui/solid

npm i https://pkg.pr.new/anomalyco/opentui/@opentui/solid@a90e7bc

@opentui/core-darwin-arm64

npm i https://pkg.pr.new/anomalyco/opentui/@opentui/core-darwin-arm64@a90e7bc

@opentui/core-darwin-x64

npm i https://pkg.pr.new/anomalyco/opentui/@opentui/core-darwin-x64@a90e7bc

@opentui/core-linux-arm64

npm i https://pkg.pr.new/anomalyco/opentui/@opentui/core-linux-arm64@a90e7bc

@opentui/core-linux-x64

npm i https://pkg.pr.new/anomalyco/opentui/@opentui/core-linux-x64@a90e7bc

@opentui/core-win32-arm64

npm i https://pkg.pr.new/anomalyco/opentui/@opentui/core-win32-arm64@a90e7bc

@opentui/core-win32-x64

npm i https://pkg.pr.new/anomalyco/opentui/@opentui/core-win32-x64@a90e7bc

commit: a90e7bc

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses a Windows Terminal / ConPTY behavior where DEC private modes (mouse tracking, bracketed paste, focus tracking, etc.) can be silently reset after focus changes by re-sending currently-active mode enable sequences when a focus-in (ESC[I) is received.

Changes:

  • Add a Zig restoreTerminalModes() that re-emits enable sequences for modes tracked as active.
  • Expose restoreTerminalModes through the Zig renderer, FFI exports, and the TypeScript bindings.
  • Invoke mode restoration on focus-in before emitting the "focus" event, and add tests + a manual demo.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
packages/core/src/zig/terminal.zig Adds restoreTerminalModes() that re-sends active terminal mode sequences.
packages/core/src/zig/renderer.zig Adds a renderer method to call terminal.restoreTerminalModes() and write the output.
packages/core/src/zig/lib.zig Exposes restoreTerminalModes as an exported FFI function.
packages/core/src/zig.ts Wires up the new FFI symbol + RenderLib interface + implementation method.
packages/core/src/renderer.ts Calls restoreTerminalModes on focus-in (ESC[I) before emitting "focus".
packages/core/src/examples/focus-restore-demo.ts Adds an interactive demo to validate focus restore behavior manually.
packages/core/src/examples/index.ts Registers the new demo in the example selector.
packages/core/src/tests/renderer.focus-restore.test.ts Adds unit tests validating the focus-in wiring and call ordering.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 533 to 536
// Re-push kitty keyboard protocol if active
if (self.state.kitty_keyboard) {
try tty.print(ansi.ANSI.csiUPush, .{self.opts.kitty_keyboard_flags});
}
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

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

restoreTerminalModes re-pushes the kitty keyboard protocol using self.opts.kitty_keyboard_flags, but the currently-active kitty flags may differ from opts. In particular, setKittyKeyboard(..., flags) only flips state.kitty_keyboard and does not persist the flags, and the public enableKittyKeyboard(flags) path in renderer.zig passes a flags argument without updating opts. On focus-in this can silently change the kitty keyboard flags after a restore. Consider storing the last-pushed kitty flags in terminal state (or updating opts.kitty_keyboard_flags whenever kitty is enabled) and using that stored value here.

Suggested change
// Re-push kitty keyboard protocol if active
if (self.state.kitty_keyboard) {
try tty.print(ansi.ANSI.csiUPush, .{self.opts.kitty_keyboard_flags});
}
// NOTE: We intentionally do not re-push kitty keyboard protocol here,
// because we cannot guarantee that self.opts.kitty_keyboard_flags
// reflects the currently active kitty keyboard flags. Restoring with
// incorrect flags would silently change behavior.

Copilot uses AI. Check for mistakes.
Hona added 2 commits February 10, 2026 08:09
…n-push on restore

Store the actually-pushed kitty keyboard flags in state.kitty_keyboard_flags
rather than relying on opts.kitty_keyboard_flags, which can diverge if
setKittyKeyboardFlags() is called after enable.

Use pop-then-push in restoreTerminalModes to prevent unbounded stack growth
per the kitty keyboard protocol spec (CSI > flags u pushes onto a stack).
@kommander kommander merged commit f91df10 into main Feb 10, 2026
16 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.

3 participants