Skip to content

fix(agent-isolation): close the macOS touch overlay when it loses the keyboard - #1325

Merged
potiuk merged 1 commit into
apache:mainfrom
potiuk:fix/overlay-keyboard-focus
Sep 21, 2026
Merged

potiuk merged 1 commit into
apache:mainfrom
potiuk:fix/overlay-keyboard-focus

Conversation

@potiuk

@potiuk potiuk commented Sep 21, 2026

Copy link
Copy Markdown
Member

Summary

  • The macOS touch overlay could be left on screen with no way to dismiss it
    from the keyboard. take_focus takes the keyboard once, on the way up, and
    the window is -topmost — so anything that takes focus afterwards (a
    notification, another app activating, clicking back to the terminal) left the
    overlay painted over the screen with Esc going elsewhere. Reported by a user
    who had to kill the process to clear it.
  • Bind <Deactivate> so the window closes when another application takes the
    keyboard, rather than lingering in a state where it is visible but not
    listening.
  • Deliberately not re-grabbing focus: that would make Esc always work, but
    the module's contract is that it does not trap the screen — the key still has
    to be touched for the command to go through.

Why <Deactivate> and not <FocusOut>

Tk's focus events track the keyboard moving between widgets inside one
application
, and nothing moves between widgets here. <FocusOut> reads
correct and does nothing when a different application takes over. I tried it
first and measured it doing nothing before switching.

Type of change

  • Python package (tools/*/ with pyproject.toml)

Test plan

  • prek run --all-files passes
  • uv run pytest tools/agent-isolation/tests/test_gpg_touch_overlay.py — green
    (1 skip: no interpreter on this machine can import gi)
  • New regression test test_the_aqua_window_closes_when_it_loses_the_keyboard
    fails without the fix (AssertionError: ... it binds only ['<Button-1>', '<Escape>']) and passes with it
  • Manually verified on macOS 15 / uv CPython 3.13.5 / Tk 8.6, the interpreter
    _tk_python actually selects:
scenario before after
Esc with overlay focused dismissed dismissed
Esc after another app activates overlay survives n/a — already gone
another app activates overlay stays on screen dismissed
left idle 8s stays stays (no spurious dismissal)

Notes for review

  • The GTK sibling (gpg-touch-overlay-window.py) calls present() once and has
    no equivalent focus-loss handling, so it likely shares this flaw. I did not
    touch it: I have no Linux/GTK environment here and did not want to ship an
    unverified change to that path. Worth a follow-up by someone who can test it.
  • FOCUS_GRACE_MS = 750 is empirical — long enough to cover activation churn on
    this machine, short enough to still catch a real focus loss. Happy to adjust.

… keyboard

take_focus takes the keyboard once, on the way up, and the window is
-topmost. Anything that takes it afterwards — a notification, another
application activating, the terminal being clicked — left the overlay
painted over the screen with Esc going somewhere else and nothing but a
kill to get rid of it.

Bind <Deactivate> so the window closes instead. Not <FocusOut>: Tk's
focus events track the keyboard moving between widgets inside one
application, and nothing moves between widgets here, so it never fires
when another application takes over. The binding is deferred past a
short grace period because activation itself churns focus — bound
immediately, the window closes on its own way up.

Re-grabbing the keyboard would make Esc always work too, but this window
deliberately does not trap the screen: the key still has to be touched
for the command to go through.

Generated-by: Claude Opus 5
@potiuk potiuk added family:tools tools/* capability:fix Implement code change to resolve an issue labels Sep 21, 2026
@potiuk
potiuk merged commit 6b0b9db into apache:main Sep 21, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

capability:fix Implement code change to resolve an issue family:tools tools/*

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant