Fix Korean IME arrow key inserting character at wrong position#20039
Merged
DHowett merged 1 commit intoMar 31, 2026
Conversation
When an arrow key is pressed during an active Korean IME composition, _KeyHandler was forwarding the key to the PTY immediately via _TrySendKeyEvent. This moved the cursor before the async TSF edit session had a chance to commit the finalized text, causing the committed character to land at the wrong position. The fix adds a guard that mirrors the existing behavior in the conhost v1 key handler (src/interactivity/win32/windowio.cpp lines 361-364): suppress all key events from being forwarded to the PTY while TSF has an active composition. The IME re-injects navigation and confirmation keys after the composition ends, at which point HasActiveComposition() returns false and they are forwarded normally. Historical note: this guard was not needed before PR microsoft#17067 (v1.22) because the old TSF implementation used WinRT CoreTextServices via XAML (TSFInputControl.xaml/.cpp). In that model the XAML framework handled composition key events before they reached _KeyHandler, so _KeyHandler never received them during composition. The new custom Win32 TSF context introduced in microsoft#17067 no longer intercepts keys at the XAML level, making _KeyHandler responsible for this check. The bug was not visible in v1.22-v1.23 for Korean because the Korean IME was excluded from the TSF path by TF_TMAE_UIELEMENTENABLEDONLY. It became visible in v1.24 when PR microsoft#19738 removed that flag, causing the Korean IME to activate through TSF for the first time. Closes microsoft#20038
Member
|
/azp run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
lhecker
approved these changes
Mar 31, 2026
Member
lhecker
left a comment
There was a problem hiding this comment.
Thank you for investigating this for us!
DHowett
pushed a commit
that referenced
this pull request
Mar 31, 2026
Fix a regression introduced in v1.24 where pressing an arrow key during Korean IME composition caused the committed character to be inserted at the wrong cursor position. Before #19738, the Korean IME activated through IMM32 (excluded from TSF by `TF_TMAE_UIELEMENTENABLEDONLY`) and was not affected by `TermControl::_KeyHandler` forwarding keys to the PTY during composition. After #19738, the Korean IME activates through TSF, making a missing composition guard in `_KeyHandler` visible as a bug. The sequence of events that causes the bug: 1. User presses Left arrow during active Korean IME composition (e.g. composing `가`). 2. `_KeyHandler` calls `_TrySendKeyEvent(VK_LEFT)` which enqueues `\x1b[D` to the PTY input queue. The cursor moves. 3. TSF processes the key. The Korean IME sees the arrow and ends the composition. 4. `OnEndComposition` schedules `_doCompositionUpdate` with `TF_ES_ASYNC`. 5. The async session fires, reads finalized text `가`, calls `HandleOutput("가")`. 6. PTY processes `[\x1b[D, "가"]`: cursor moves left first, then `가` is inserted at the wrong (already-moved) position. The fix adds a guard before `_TrySendKeyEvent`, which mirrors the existing behavior in conhost (windowio.cpp). When TSF has an active composition, key events are not converted into input. The Korean IME re-injects navigation and confirmation keys after the composition ends, at which point `HasActiveComposition()` returns false and they are forwarded normally. **Historical note:** This guard was not needed before PR #17067 (v1.22) because the old implementation used WinRT `CoreTextServices` via XAML (`TSFInputControl.xaml`). The XAML framework intercepted composition key events before `_KeyHandler`. The new custom Win32 TSF context in #17067 no longer does this. The bug was latent from v1.22 but only became visible for Korean in v1.24 when #19738 removed `TF_TMAE_UIELEMENTENABLEDONLY`. ## Validation Steps Performed 1. Open Windows Terminal with Korean IME (Dubeolsik layout). 2. Type `rk` to begin composing `가` (composition active, syllable not yet committed). 3. Press the Left arrow key. 4. Before fix: `가` is inserted one cell to the left of the intended position. 5. After fix: `가` is inserted at the correct position, then cursor moves left. Also verified: - Normal Korean text input (typing without arrow keys) still works correctly. - Arrow key navigation when no composition is active still works correctly. - English and other IME input is not affected. Closes #20038 Refs #19738 (cherry picked from commit 14f4271) Service-Card-Id: PVTI_lADOAF3p4s4BQX0-zgo0JpM Service-Version: 1.25
DHowett
pushed a commit
that referenced
this pull request
Mar 31, 2026
Fix a regression introduced in v1.24 where pressing an arrow key during Korean IME composition caused the committed character to be inserted at the wrong cursor position. Before #19738, the Korean IME activated through IMM32 (excluded from TSF by `TF_TMAE_UIELEMENTENABLEDONLY`) and was not affected by `TermControl::_KeyHandler` forwarding keys to the PTY during composition. After #19738, the Korean IME activates through TSF, making a missing composition guard in `_KeyHandler` visible as a bug. The sequence of events that causes the bug: 1. User presses Left arrow during active Korean IME composition (e.g. composing `가`). 2. `_KeyHandler` calls `_TrySendKeyEvent(VK_LEFT)` which enqueues `\x1b[D` to the PTY input queue. The cursor moves. 3. TSF processes the key. The Korean IME sees the arrow and ends the composition. 4. `OnEndComposition` schedules `_doCompositionUpdate` with `TF_ES_ASYNC`. 5. The async session fires, reads finalized text `가`, calls `HandleOutput("가")`. 6. PTY processes `[\x1b[D, "가"]`: cursor moves left first, then `가` is inserted at the wrong (already-moved) position. The fix adds a guard before `_TrySendKeyEvent`, which mirrors the existing behavior in conhost (windowio.cpp). When TSF has an active composition, key events are not converted into input. The Korean IME re-injects navigation and confirmation keys after the composition ends, at which point `HasActiveComposition()` returns false and they are forwarded normally. **Historical note:** This guard was not needed before PR #17067 (v1.22) because the old implementation used WinRT `CoreTextServices` via XAML (`TSFInputControl.xaml`). The XAML framework intercepted composition key events before `_KeyHandler`. The new custom Win32 TSF context in #17067 no longer does this. The bug was latent from v1.22 but only became visible for Korean in v1.24 when #19738 removed `TF_TMAE_UIELEMENTENABLEDONLY`. ## Validation Steps Performed 1. Open Windows Terminal with Korean IME (Dubeolsik layout). 2. Type `rk` to begin composing `가` (composition active, syllable not yet committed). 3. Press the Left arrow key. 4. Before fix: `가` is inserted one cell to the left of the intended position. 5. After fix: `가` is inserted at the correct position, then cursor moves left. Also verified: - Normal Korean text input (typing without arrow keys) still works correctly. - Arrow key navigation when no composition is active still works correctly. - English and other IME input is not affected. Closes #20038 Refs #19738 (cherry picked from commit 14f4271) Service-Card-Id: PVTI_lADOAF3p4s4BBcTlzgo0JpQ Service-Version: 1.24
DHowett
pushed a commit
that referenced
this pull request
Apr 17, 2026
This commit fixes a regression in v1.24, where composing Korean text in-between existing characters causes text to the right to be hidden. This is problematic for the Korean IME, because it commonly inserts the composed syllable between existing characters. The fix compresses (removes/absorbs) available whitespace to the right of the composition to make space for any existing text. This means that a composition now virtually acts in insert mode. Closes #20040 Refs #19738 Refs #20039 ## Validation Steps Performed 1. Korean IME: compose `ㄷ` between `가` and `나` → display shows `가ㄷ나`, `나` visible. 2. TUI box (vim prompt with padding): compose inside padded text box → border preserved in place. 3. Composition at end of line (no chars to right): unaffected. 4. English and other IME input: not affected (no active composition row). Co-authored-by: jason <drvoss@users.noreply.github.com> Co-authored-by: Leonard Hecker <lhecker@microsoft.com>
DHowett
pushed a commit
that referenced
this pull request
Apr 17, 2026
This commit fixes a regression in v1.24, where composing Korean text in-between existing characters causes text to the right to be hidden. This is problematic for the Korean IME, because it commonly inserts the composed syllable between existing characters. The fix compresses (removes/absorbs) available whitespace to the right of the composition to make space for any existing text. This means that a composition now virtually acts in insert mode. Closes #20040 Refs #19738 Refs #20039 ## Validation Steps Performed 1. Korean IME: compose `ㄷ` between `가` and `나` → display shows `가ㄷ나`, `나` visible. 2. TUI box (vim prompt with padding): compose inside padded text box → border preserved in place. 3. Composition at end of line (no chars to right): unaffected. 4. English and other IME input: not affected (no active composition row). Co-authored-by: jason <drvoss@users.noreply.github.com> Co-authored-by: Leonard Hecker <lhecker@microsoft.com> (cherry picked from commit 7a83c0f) Service-Card-Id: PVTI_lADOAF3p4s4BQX0-zgo0JpY Service-Version: 1.25
DHowett
pushed a commit
that referenced
this pull request
Apr 30, 2026
This commit fixes a regression in v1.24, where composing Korean text in-between existing characters causes text to the right to be hidden. This is problematic for the Korean IME, because it commonly inserts the composed syllable between existing characters. The fix compresses (removes/absorbs) available whitespace to the right of the composition to make space for any existing text. This means that a composition now virtually acts in insert mode. Closes #20040 Refs #19738 Refs #20039 1. Korean IME: compose `ㄷ` between `가` and `나` → display shows `가ㄷ나`, `나` visible. 2. TUI box (vim prompt with padding): compose inside padded text box → border preserved in place. 3. Composition at end of line (no chars to right): unaffected. 4. English and other IME input: not affected (no active composition row). Co-authored-by: jason <drvoss@users.noreply.github.com> Co-authored-by: Leonard Hecker <lhecker@microsoft.com> (cherry picked from commit 7a83c0f) Service-Card-Id: PVTI_lADOAF3p4s4BBcTlzgo0Jpc Service-Version: 1.24
Qmoony
pushed a commit
to Qmoony/terminal
that referenced
this pull request
May 11, 2026
…osoft#20041) This commit fixes a regression in v1.24, where composing Korean text in-between existing characters causes text to the right to be hidden. This is problematic for the Korean IME, because it commonly inserts the composed syllable between existing characters. The fix compresses (removes/absorbs) available whitespace to the right of the composition to make space for any existing text. This means that a composition now virtually acts in insert mode. Closes microsoft#20040 Refs microsoft#19738 Refs microsoft#20039 ## Validation Steps Performed 1. Korean IME: compose `ㄷ` between `가` and `나` → display shows `가ㄷ나`, `나` visible. 2. TUI box (vim prompt with padding): compose inside padded text box → border preserved in place. 3. Composition at end of line (no chars to right): unaffected. 4. English and other IME input: not affected (no active composition row). Co-authored-by: jason <drvoss@users.noreply.github.com> Co-authored-by: Leonard Hecker <lhecker@microsoft.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 of the Pull Request
Fix a regression introduced in v1.24 where pressing an arrow key during Korean IME composition caused the committed character to be inserted at the wrong cursor position.
References and Relevant Issues
Closes #20038
Related to #19738 (Remove TF_TMAE_UIELEMENTENABLEDONLY).
Detailed Description of the Pull Request / Additional comments
Before #19738, the Korean IME activated through IMM32 (excluded from TSF by
TF_TMAE_UIELEMENTENABLEDONLY) and was not affected byTermControl::_KeyHandlerforwarding keys to the PTY during composition. After #19738, the Korean IME activates through TSF, making a missing composition guard in_KeyHandlervisible as a bug.The sequence of events that causes the bug:
가)._KeyHandlercalls_TrySendKeyEvent(VK_LEFT)which enqueues\x1b[Dto the PTY input queue. The cursor moves.OnEndCompositionschedules_doCompositionUpdatewithTF_ES_ASYNC.가, callsHandleOutput("가").[\x1b[D, "가"]: cursor moves left first, then가is inserted at the wrong (already-moved) position.The fix adds a guard before
_TrySendKeyEvent:cpp if (GetTSFHandle().HasActiveComposition()) { return true; }This mirrors the existing behavior in conhost v1 (
src/interactivity/win32/windowio.cpplines 361-364). When TSF has an active composition, key events are suppressed from the PTY. The Korean IME re-injects navigation and confirmation keys after the composition ends, at which pointHasActiveComposition()returns false and they are forwarded normally.Historical note: This guard was not needed before PR #17067 (v1.22) because the old implementation used WinRT
CoreTextServicesvia XAML (TSFInputControl.xaml). The XAML framework intercepted composition key events before_KeyHandler. The new custom Win32 TSF context in #17067 no longer does this. The bug was latent from v1.22 but only became visible for Korean in v1.24 when #19738 removedTF_TMAE_UIELEMENTENABLEDONLY.Validation Steps Performed
rkto begin composing가(composition active, syllable not yet committed).가is inserted one cell to the left of the intended position.가is inserted at the correct position, then cursor moves left.Also verified:
PR Checklist