Skip to content

fix(app): restore first responder after native tab close#26

Merged
simota merged 1 commit into
mainfrom
fix/tab-close-first-responder
Jul 17, 2026
Merged

fix(app): restore first responder after native tab close#26
simota merged 1 commit into
mainfrom
fix/tab-close-first-responder

Conversation

@simota

@simota simota commented Jul 17, 2026

Copy link
Copy Markdown
Owner

Summary

新規タブを追加して閉じた後、生存タブでキーボード入力が効かなくなる不具合(再発)の修正。

  • 真因: AppKitのネイティブタブteardownが生存ウィンドウをkeyにしつつfirstResponderをwinitのcontent NSViewから外すため、keyDown:が届かず WindowEvent::KeyboardInput が沈黙する。
  • 既存のdeferred RestoreFocus 修正は focus_window()(makeKeyAndOrderFront:)のみで、対象が既にkeyの場合firstResponderを再割当てしない=この故障モードにはno-opだった。
  • 対応: macos_window::focus_content_view() を追加し makeFirstResponder: を直接送出。RestoreFocus ハンドラと Focused(true) の両経路で firstResponder復元 + set_ime_allowed off/on(stale marked textの破棄)を実施。非macOS経路は不変。

Test plan

  • cargo build --workspace / cargo clippy --workspace クリーン
  • cargo test -p noa-app: 966 passed
  • 実機smoke(要目視): ⌘T→⌘W→前タブで即打鍵が効くこと。exit で閉じる経路も同様。NOA_IME_TRACE=1 で打鍵時に [ime-trace] Key: が出ることを確認。

Closing a native macOS tab left the surviving tab unable to receive
keyboard input: AppKit's tab teardown makes the survivor key but moves
first responder off winit's content NSView, so keyDown: never reaches
WinitView and WindowEvent::KeyboardInput goes silent.

The previous deferred-RestoreFocus fix only called focus_window()
(makeKeyAndOrderFront:), which does not reassign first responder when
the target window is already key — a no-op for this failure mode.

Add macos_window::focus_content_view, which resolves the AppKit
NSView from the raw window handle and sends makeFirstResponder: to
its window. Call it (plus a set_ime_allowed off/on toggle to discard
stale marked text) from both the RestoreFocus handler and the
Focused(true) path, so recovery does not depend on where the deferred
event lands relative to AppKit's teardown. Non-macOS paths unchanged.
@simota
simota merged commit 13d4824 into main Jul 17, 2026
1 check passed
@simota
simota deleted the fix/tab-close-first-responder branch July 17, 2026 11:23
simota added a commit that referenced this pull request Jul 17, 2026
…estore (#27)

Two regressions from the native-tab-close focus fix (#26):

Search opening uninvited: closing a tab with cmd+w destroys the view
before the Cmd-release flagsChanged reaches winit, so the app's stored
modifiers stay stuck holding SUPER and the next plain keypress on the
surviving tab resolves as a chord (plain f -> cmd+f -> Search/Find).
Reset stored modifiers on Focused(false) and in the RestoreFocus
handler; winit re-sends ModifiersChanged on the next real modifier
press, so nothing is lost. Regression test locks the resolution
semantics the reset relies on.

Intermittent crash on the same gesture: the belt-and-suspenders block
added to Focused(true) ran makeFirstResponder: plus an IME off/on
toggle synchronously inside the winit handler on every focus gain,
including mid-teardown ones — a re-entrancy/teardown race. Remove it;
focus restore after tab close lives solely on the deferred
RestoreFocus path, which keeps the first-responder + IME re-arm.
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