Fix terminal bottom content obscured and enable touch-scroll in TUI apps - #39
Open
goxofy wants to merge 4 commits into
Open
Fix terminal bottom content obscured and enable touch-scroll in TUI apps#39goxofy wants to merge 4 commits into
goxofy wants to merge 4 commits into
Conversation
TUI apps (Claude Code, Codex, vim, htop) draw their bottom input row at the pty's last row. The WebView was sized by marginBottom so it spans only the visible area, but xterm computed rows from #terminal's 100vh CSS height, which WKWebView reports stale after a frame resize. The pty told the shell too many rows, so TUIs painted their input row behind the keyboard bar. Measure the real visible height with onLayout, push it into the WebView (debounced to avoid resize storms), pin #terminal's height to it, then fit and re-send the pty resize. Re-apply on terminalReady and prefer the pinned height in nativeFit/resize over the stale 100vh. Co-Authored-By: Claude <noreply@anthropic.com>
The previous touch handler called terminal.scrollLines(), which is a no-op on the alternate screen buffer that TUI apps run in, so swiping did nothing inside Claude Code / Codex. Synthesize a wheel event on the xterm root element instead: xterm routes it to the scrollback in the normal buffer, or to SGR mouse sequences / arrow keys in the alternate buffer, which TUIs understand. Enable stdin in the WebView and bridge xterm onData back to the pty via a new 'input' WebView message so the synthesized wheel bytes reach the shell. Keyboard input is unaffected (it goes through the RN IME). Co-Authored-By: Claude <noreply@anthropic.com>
When swiping up in a TUI app to return to the newest content, the native touch scroll of .xterm-viewport bubbled to the WebView page when the alternate buffer was at its top, scrolling the whole page instead of the terminal. Disable native touch-scrolling at the source with touch-action: none on the terminal elements (including .xterm-screen, the actual touch hit-target), so the synthetic WheelEvent remains the sole scroll driver. Works on both iOS WKWebView and Android WebView. Co-Authored-By: Claude <noreply@anthropic.com>
touch-action:none alone is not enough on iOS WKWebView: a passive touchmove still lets the page steal the gesture when the alt buffer is already at its top, so the whole terminal slides instead of the content. Make the scroll touchmove non-passive, call preventDefault (skipping only when text selection is active), disable WebView scrollEnabled, and pin .xterm-viewport overflow so the synthetic WheelEvent remains the only scroll driver. Co-Authored-By: Claude <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.
Summary
This PR fixes two mobile terminal issues that affect interactive CLI tools such as Claude Code and Codex:
1. Terminal bottom content obscured
TUI apps draw their input row at the last row of the pty. The WebView was already sized to the visible area by the parent
marginBottom, but xterm computed its row count from#terminal's100vhCSS height. Inside a WKWebView,100vh/window.innerHeightis stale after a frame resize, so xterm reported more rows than the visible area — the pty told the shell too many rows, and TUIs painted their input row behind the keyboard bar.Fix: measure the real visible height with React Native's
onLayout, push it into the WebView (debounced to avoid resize storms), pin#terminal's height to it, then re-fit and re-send the pty resize. The height is re-applied onterminalReadyandnativeFit/resizeprefer the pinned height over the stale100vh.2. Touch-swipe scrolling in TUI (alternate screen) apps
Claude Code / Codex run on xterm's alternate screen buffer, which has no scrollback — the old handler's
terminal.scrollLines()is a no-op there, so swiping did nothing.Fix: synthesize a
WheelEventon the xterm root element. xterm routes it correctly:?1000/?1006),Enabling
disableStdinand bridgingterminal.onDataback to the pty (via a newinputWebView message) lets the wheel bytes reach the shell. Regular keyboard input is unaffected — it goes through the RN IME and never hits xterm'sonData.A follow-up commit makes the scroll
touchmovenon-passive withpreventDefault(skipping during text selection) and disables WebView native scrolling, so an up-swipe back to the newest content scrolls the terminal instead of the whole page.Testing
Verified on iOS and Android physical devices:
All changes are confined to
app/tabs/sessions/terminal/Terminal.tsx.