Skip to content

v0.1.1: key-strip taps no longer dismiss the keyboard a TUI is driven with - #13

Merged
ThyFriendlyFox merged 2 commits into
mainfrom
fix/tui-keyboard-hold
Aug 6, 2026
Merged

v0.1.1: key-strip taps no longer dismiss the keyboard a TUI is driven with#13
ThyFriendlyFox merged 2 commits into
mainfrom
fix/tui-keyboard-hold

Conversation

@ThyFriendlyFox

Copy link
Copy Markdown
Collaborator

What & why

Two things, one release:

The fix. On a phone, tapping up/down/left/right/esc/tab on the terminal's key strip hid the keyboard — every arrow press cost a re-summon, making a TUI menu undrivable one keystroke at a time. Return did not hide it, and that asymmetry was the tell once traced: the keyboard's own keys live in another window, but strip taps land in the app, where KeyboardFloatingHost installs a global tap-to-dismiss recognizer that resigns on any tap outside a text input. The strip's buttons are buttons, not text inputs, so driving the program read as "tap outside" and dismissed.

Traced, not guessed: a temporary override on the prompt field logged the resign's callstack in the simulator, and it named the dismiss coordinator's gesture action directly.

While a program runs, the terminal container now registers its frame in KeyboardHoldRegions, and the dismiss recognizer skips taps that land inside a registered region. Taps outside the container — another lane, the gap — still dismiss, and the region unregisters when the program ends. An edge-preview terminal registers an off-screen rect no tap can land in.

A first attempt re-claimed the keyboard on keyboardDidHide; it is deliberately NOT in this diff — with the region in place, the only dismissals it could catch are the ones the user meant.

The release. This PR also cuts v0.1.1 per RELEASING.md: both apps bumped (iOS MARKETING_VERSION 0.1.1, Android versionName 0.1.1 / versionCode 2), changelog [Unreleased] moved to [0.1.1] - 2026-08-06 covering this fix and the graph-mount status freeze (#12, already on main). After merge: git tag v0.1.1 && git push origin v0.1.1 — the Release workflow builds and publishes with artifacts.

Gesture-law impact

Upheld, not amended: taps remain content, and the one global exception (tap-outside-dismisses) now excludes the region where taps ARE the content's input — a terminal being driven by its key strip.

Verified — function and feel

  • Simulator, both directions: less running, tap down on the strip → the prompt keeps its caret (before the fix this exact tap produced the logged resign); tap the margin outside the container → the caret drops (dismissal preserved).

  • iOS simulator build green after xcodegen generate; Android assembleDebug green with the version bump.

  • Builds clean (xcodegen generate re-run for the version bump)

  • Feel-tested on a real device — owner: arrows through a create-vite menu should leave the keyboard planted; a tap off the container edge should still dismiss

  • Screenshot exercised in-session (caret held / caret dropped; the fix is the absence of a disappearance)

  • Docs updated: CHANGELOG.md carries 0.1.1; behavior change is the fix itself

  • No diagnostics or demo scaffolding left in the merge (the callstack logger was removed before commit)

🤖 Generated with Claude Code

ThyFriendlyFox and others added 2 commits August 5, 2026 20:58
On a phone, tapping up/down/left/right/esc/tab on the terminal's key strip hid
the keyboard — every arrow press cost a re-summon, which makes a TUI menu
undrivable one keystroke at a time. Return did NOT hide it, and that asymmetry
was the tell once the resign was traced: the keyboard's own keys live in
another window, but strip taps land in the app, where `KeyboardFloatingHost`
installs a global tap-to-dismiss recognizer that resigns on any tap outside a
text input. The strip's buttons are buttons, not text inputs, so driving the
program read as "tap outside" and dismissed.

Traced, not guessed: a temporary override on the prompt field logged the
resign's callstack on the simulator, and it named the dismiss coordinator's
gesture action directly.

Fix: while a program is running, the terminal container registers its frame in
`KeyboardHoldRegions`, and the dismiss recognizer skips taps that land inside
a registered region. Everything else about dismissal stands — taps outside the
container (another lane, the gap) still resign, which is the half of the rule
worth keeping, and the region unregisters when the program ends. An
edge-preview terminal registers an off-screen rect no tap can land in.

A first attempt re-claimed the keyboard on `keyboardDidHide` while a program
owned the screen. It is not in this diff, and the reason is recorded: with the
region in place, the only dismissals it could still catch are the ones the
user MEANT — it would have turned "tap off the edge to dismiss" into a fight
the user loses. Removed in favor of not causing the hide at all.

Verified on the simulator, both directions: `less` running, tap `down` on the
strip — the prompt keeps its caret (before the fix this produced the logged
resign); tap the margin outside the container — the caret drops. Build clean.

The gesture law is upheld, not amended: taps remain content, and the one
global exception (tap-outside-dismisses) now excludes the region where taps
ARE the content's input.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Both apps move to 0.1.1 (Android versionCode 2), per RELEASING.md: the
changelog's two entries are the graph-mount status freeze (merged in #12) and
the key-strip keyboard dismissal (this branch). Tagging v0.1.1 on main after
merge publishes the release.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ThyFriendlyFox
ThyFriendlyFox merged commit 5b8d64c into main Aug 6, 2026
2 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