Summary
Tapping the Select button in the mobile control tray flashes the selection panel open and immediately closes it. Selection mode is unreachable on touch devices.
Repro
- Open TermiWeb on a touch device (observed on Android Brave).
- Tap the Select button in the mobile control tray.
- Selection panel briefly appears, then snaps back to the live terminal view. Selection mode never stays on.
Suspected cause
The Select button's activation handler is registered via bindControlButtonActivation (src/client/main.ts:657) on pointerup. The handler calls setSelectionMode(!selectionMode), which calls renderModifierControls() (src/client/main.ts:1454). renderModifierControls wipes the entire mobile control tray with mobileControls.innerHTML = "" (src/client/main.ts:1519) and re-creates every button, including a freshly bound Select button positioned under the user's finger.
Likely failure mode: the tail of the same gesture (synthesized click, or a follow-up event resolving against the replacement node) lands on the new Select button and triggers setSelectionMode(!selectionMode) a second time, toggling selection mode back off before the user can interact with it.
Supporting observations:
bindControlButtonActivation has no re-entrancy or "gesture consumed" guard — no pointerId capture, no debounce, no data-handled flag.
setSelectionMode(true) also calls selectionText.focus() (src/client/main.ts:1448), which on mobile triggers the virtual keyboard and a viewport resize — a secondary candidate path worth ruling out, though no obvious code toggles selection mode off in response.
Suggested fix direction
- Make
renderModifierControls not destroy and recreate the active Select button on every state change; toggle classes/labels on the existing nodes instead. This also avoids similar latent issues for other mode-toggle buttons.
- Or, as a narrower fix, guard
bindControlButtonActivation against being re-entered by a follow-up event of the same gesture (track pointerId, or set a one-frame "just activated" flag).
Notes
- Found during 0.1.1 dogfooding.
- No native selection workaround on mobile — long-press selection on the xterm.js canvas is not exposed, which is why the Select panel exists in the first place.
Summary
Tapping the Select button in the mobile control tray flashes the selection panel open and immediately closes it. Selection mode is unreachable on touch devices.
Repro
Suspected cause
The Select button's activation handler is registered via
bindControlButtonActivation(src/client/main.ts:657) onpointerup. The handler callssetSelectionMode(!selectionMode), which callsrenderModifierControls()(src/client/main.ts:1454).renderModifierControlswipes the entire mobile control tray withmobileControls.innerHTML = ""(src/client/main.ts:1519) and re-creates every button, including a freshly bound Select button positioned under the user's finger.Likely failure mode: the tail of the same gesture (synthesized
click, or a follow-up event resolving against the replacement node) lands on the new Select button and triggerssetSelectionMode(!selectionMode)a second time, toggling selection mode back off before the user can interact with it.Supporting observations:
bindControlButtonActivationhas no re-entrancy or "gesture consumed" guard — nopointerIdcapture, no debounce, nodata-handledflag.setSelectionMode(true)also callsselectionText.focus()(src/client/main.ts:1448), which on mobile triggers the virtual keyboard and a viewport resize — a secondary candidate path worth ruling out, though no obvious code toggles selection mode off in response.Suggested fix direction
renderModifierControlsnot destroy and recreate the active Select button on every state change; toggle classes/labels on the existing nodes instead. This also avoids similar latent issues for other mode-toggle buttons.bindControlButtonActivationagainst being re-entered by a follow-up event of the same gesture (trackpointerId, or set a one-frame "just activated" flag).Notes