fix(tui): guard Enter submit against IME composition via timestamp - #39246
fix(tui): guard Enter submit against IME composition via timestamp#39246wuyang9311 wants to merge 1 commit into
Conversation
When using an IME (Chinese/Japanese/Korean/etc.) in TUI mode, pressing Enter to confirm the IME candidate and pressing Enter to submit the message are the same keystroke. In a terminal there is no isComposing property to distinguish them. Fix: track when the last non-paste printable input arrived. If Enter follows within 30ms, the text and the Enter came in the same event- loop tick -- this is an IME commit, not a user submit. Reset the guard and return without modifying the buffer content. The next Enter submits normally. 30ms is well below human key-repeat speed (50ms+) but above the IME commit + Enter synchrony (~0-5ms on all tested platforms). Paste operations are excluded (event.keypress.isPasted) so pasting and pressing Enter still works. Fixes: NousResearch#39195
teknium1
left a comment
There was a problem hiding this comment.
Thanks for tackling a real TUI IME problem. Current main still submits unconditionally in ui-tui/src/components/textInput.tsx:990-1000, so the premise remains live.
Problems
- The new guard is evaluated before the modified-Return branch (
ui-tui/src/components/textInput.tsx:980in this diff). A printable input followed within 30ms by Shift/Ctrl/Meta Return is swallowed instead of taking the existing newline path. - The timestamp is recorded only below the early Return path (
ui-tui/src/components/textInput.tsx:1127in this diff). It therefore cannot handle a commit and Return delivered in the same input event. The linked PR #39695 documents that xterm burst shape and preserves its printable prefix before submission. - This behavior change has no focused regression coverage.
Suggested changes
- Limit any composition-confirmation guard to unmodified plain Return, after preserving modified-newline behavior.
- Preserve printable text carried by a Return event before submitting, and add tests for separate-event IME confirmation, same-event commit-plus-Return, modified Return, and paste.
Automated hermes-sweeper review.
| if (k.return) { | ||
| flushKeyBurst() | ||
|
|
||
| const imeGuard = Date.now() - lastInputAt.current < IME_GUARD_MS |
There was a problem hiding this comment.
This guard runs before the existing Shift/Ctrl/Meta Return branch. A printable input followed within 30ms by a modified Return will now be absorbed instead of inserting the configured newline; restrict this guard to unmodified plain Return.
| const bracketed = event.keypress.isPasted || inp.includes('[200~') | ||
| const text = inp.replace(BRACKET_PASTE, '').replace(/\r\n/g, '\n').replace(/\r/g, '\n') | ||
|
|
||
| if (!event.keypress.isPasted) { |
There was a problem hiding this comment.
This timestamp is never reached when xterm delivers finalized IME text together with Return in one input event: the k.return branch returns first. The timeline-linked PR #39695 covers that event shape by preserving the printable Return payload before submission.
What does this PR do?
--tuimode) rejecting CJK/IME users: pressing Enter to confirm an IME candidate was treated as message submit because the terminal does not expose anisComposingproperty.Related Issue
Fixes #39195
Type of Change
Changes Made
ui-tui/src/components/textInput.tsx: addIME_GUARD_MSconstant (30ms),lastInputAtref, guard in Enter handler, and timestamp recording in non-paste printable input path. 19 lines added.Why 30ms?
30ms is well below human key-repeat speed (50ms+) but safely above IME commit + Enter synchrony (~0-5ms). Pastes are excluded via
isPasted.How to Test
hermes --tui