Android keyCode-229 keyboards: a stray DEL rides the batched commit-plus-Enter path and eats a character #448
Description
Found while reviewing #441, which fixed the neighbouring half of this path. Pre-existing on master, not introduced there.
What happens
On a device whose keydowns report keyCode: 229 (Chrome on Android, and any soft keyboard that routes through composition), committing the last character of a prompt and pressing Enter in one InputConnection transaction makes xterm emit a stray DEL before the \r.
The mechanism is xterm's own keyCode-229 rescue. CompositionHelper.keydown() schedules _handleAnyTextareaChanges(), a zero-delay diff of textarea.value. Enter clears the textarea, so when that diff runs it sees the value shrink and emits the difference as a deletion. With local echo on (the default on every touch device, per MobileDetection.isTouchDevice()), that DEL reaches the composer before the \r does and eats a character.
Why it is worth a separate issue
#441 strictly improved this path rather than causing it: before that change the batched shape lost two characters here, after it one. So a report that still shows a missing character on an Android device after 1.30.0 is this, not a regression from #441, and I would rather that be written down somewhere than rediscovered.
Where to look
src/web/public/terminal-keycode229-recovery.jsis the module that already owns the neighbouring case (aninsertTextxterm's_inputEventguard refuses). It deliberately does not touch anything xterm emitted itself, which is why this is out of its scope as written.test/terminal-keycode229-recovery.browser.test.tshas the harness: it drives the real textarea and reports which bytes reach the send path and who produced them. The batched case added inea5323d9is the closest shape; a variant withkeyCode: 229and local echo enabled should show the strayDEL.
Not obvious, and worth deciding before writing code
Suppressing a DEL unconditionally would break real backspaces. The distinguishing evidence is that this one arrives from xterm's composition diff rather than from a key, in the same task as an Enter that has already cleared the textarea, so any fix needs to key off that rather than off the byte.
Not urgent: it costs one character in one input shape on one platform, and it has been there a while.
Activity
Ark0N commentedon Oct 14, 2026
Fixed by #541 (thanks @opticon454), which shipped in 1.40.0. Its review commit
f21ab39ahandles exactly this shape: the keyCode-229 controller now diffs the textarea against what was already sent, and a pending edit is settled synchronously at the next keydown, before xterm clears the textarea for Enter. So the diff never sees the value shrink and sends noDEL. That keys off the composition path rather than the byte, so real backspaces are untouched, which was the open question above.test/terminal-keycode229-recovery.browser.test.tspins it: "a 229 last character in the same task as Enter submits the whole line", with local echo both on and off, asserts no\x7freaches the wire and the line arrives ashello\r. I re-ran that file on master today and all 17 tests pass.