-
Notifications
You must be signed in to change notification settings - Fork 18.2k
Korean IME composition window appears at wrong position (bottom-left of terminal) #25186
Description
Korean IME composition window appears at wrong position (bottom-left of terminal)
Summary
When typing Korean (or other CJK languages) in Claude Code, the IME composition/candidate window renders at the bottom-left corner of the terminal instead of at the cursor position. This makes Korean input extremely difficult — the composing character appears far from where text is being typed.
Environment
- OS: macOS (Darwin 25.2.0)
- Claude Code model: Opus 4.6
- Input method: macOS default Korean input (2-set / du-beol-sik)
- Terminal: iTerm2 / Terminal.app (reproducible in both)
Steps to Reproduce
- Launch Claude Code in a terminal on macOS.
- Switch to Korean input method.
- Type Korean text in the input prompt (e.g., keystrokes for "한글").
- Observe where the IME composition window appears.
Expected Behavior
The IME composition window should appear directly adjacent to the text cursor in the input field.
Actual Behavior
The IME composition window appears at the bottom-left corner of the terminal, completely detached from the input area:
- Split attention: The composing syllable (ㅎ → 하 → 한) appears far from where text is inserted.
- Disorienting feel: Characters feel "pushed away" or "lagging" due to spatial disconnect.
- Affects all Korean input: Korean users all experience this.
Screenshot
Technical Analysis
Root Cause
Claude Code uses React Ink, which hides the real terminal cursor and renders a fake cursor via chalk.inverse(). macOS IME relies on the real terminal cursor position to place the composition window. Since the real cursor is hidden, the IME window falls back to position (0,0).
The Fix: Ink's useCursor API
Ink 6.7.0 introduced useCursor (PR #866) which moves the real terminal cursor to specified coordinates after each render:
import { useCursor } from 'ink';
import stringWidth from 'string-width';
const { setCursorPosition } = useCursor();
setCursorPosition({
x: stringWidth(prompt + textBeforeCursor),
y: inputRow,
});Local verification: Tested with ink@6.7.0 + useCursor — IME composition window appears at the correct position. Korean input works as expected.
Related Issues
- [BUG] IME input causes performance issues and duplicate conversion candidates #1547, IME Composition Failure for Korean Character Input #2620, Investigation: Fixing IME Issues in Claude Code by Patching React Ink / React Inkのパッチによる Claude Code のIME問題修正について #3045, [BUG] CJK IME (Chinese/Japanese/Korean) preedit & candidate window anchored to wrong position on macOS (real cursor not moved) #16372, Feature Request: IME cursor position support for CJK input (Japanese/Chinese/Korean) #19207, [BUG] Korean IME composition fails in Quick Launcher (Option+Space) on macOS #21382
Proposed Fix
- Integrate
useCursorfrom ink >=6.7.0 into Claude Code's text input component - Use
string-widthfor CJK-aware cursor column calculation - Show the real terminal cursor alongside the existing visual cursor
Upstream PRs
ink-text-input#93: Add IME cursor positioning viauseCursor@inkjs/ui#24: Add IME cursor positioning to TextInputink#876: Improve cursor-ime example with full TextInputink#866:useCursorhook (merged)ink#872:<Cursor>component (open)
Reproduction
Available at korean-terminal:
| Script | Description | IME behavior |
|---|---|---|
npm run test1 |
Fake cursor (current behavior) | IME at bottom-left (broken) |
npm run test2 |
useCursor with real cursor |
IME at correct position (fixed) |
npm run test3 |
Full TextInput + useCursor |
IME at correct position (fixed) |