Skip to content

fix(input): handle ESC during CSI and SS3 parse states per ECMA-48#1054

Merged
gdamore merged 1 commit into
gdamore:v2from
ModeEngage:fix-esc-during-csi-v2
Apr 19, 2026
Merged

fix(input): handle ESC during CSI and SS3 parse states per ECMA-48#1054
gdamore merged 1 commit into
gdamore:v2from
ModeEngage:fix-esc-during-csi-v2

Conversation

@ModeEngage

Copy link
Copy Markdown
Contributor

Disclosure: I stumbled across this while working on a personal project. AI tools were used to diagnose and resolve the issue as well as generate this potential upstream fix. Systems programming at this level is not my expertise, but the fix seemed small, contained, and testable so I thought it worthwhile to open a PR.

The input parser's CSI and SS3 state handlers do not check for ESC (0x1B). Per ECMA-48 §5.3.1, ESC is "always effective" and should restart the escape sequence machine from any intermediate state. Instead, ESC falls into the "bad parse" branch in inpStateCsi and is silently discarded, and in inpStateSs3 it fails the key lookup and is similarly lost.

This causes the byte(s) following the discarded ESC to be misinterpreted. In practice, the user's first keystroke after Suspend/Resume can be swallowed: engage() sends escape sequences that may provoke terminal responses, and if those responses leave the parser mid-CSI, the next ESC-prefixed key (arrow keys, function keys) is consumed as the tail of the stale sequence.

The tty input flush added in #1048 reduces the likelihood of stale bytes reaching the parser, but does not eliminate it — terminal responses can arrive after the flush and before inputLoop starts, or bytes can be split across reads leaving a partial sequence in the parser's state machine.

This adds an ESC check to both inpStateCsi and inpStateSs3 that transitions to inpStateEsc with the standard timeout setup, matching the behavior of inpStateInit. Tests verify that a partial CSI or SS3 followed by a new escape sequence produces the correct key event.

Backport of the equivalent fix on main (#1053)

The input parser's CSI and SS3 state handlers do not check for ESC
(0x1B). Per ECMA-48 §5.3.1, ESC is always effective and should restart
the escape sequence machine from any intermediate state. Instead, ESC
falls into the "bad parse" branch in inpStateCsi and is silently
discarded, and in inpStateSs3 it fails the key lookup and is lost.

This causes the byte(s) following the discarded ESC to be
misinterpreted. In practice, the user's first keystroke after
Suspend/Resume can be swallowed: engage() sends escape sequences that
may provoke terminal responses, and if those responses leave the parser
mid-CSI, the next ESC-prefixed key (arrow keys, function keys) is
consumed as the tail of the stale sequence.

Add an ESC check to both inpStateCsi and inpStateSs3 that transitions
to inpStateEsc with the standard timeout setup, matching the behavior
of inpStateInit.
@ModeEngage ModeEngage requested a review from gdamore as a code owner April 11, 2026 14:56
@coderabbitai

coderabbitai Bot commented Apr 11, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3449edb3-2e0a-41be-bb8e-63e7068f0c38

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gdamore gdamore left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No immediate plans for an update on tcell v2 though.

@gdamore gdamore merged commit 2fdac94 into gdamore:v2 Apr 19, 2026
1 check passed
@ModeEngage ModeEngage deleted the fix-esc-during-csi-v2 branch May 11, 2026 00:29
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.

2 participants