[BUG] Mods: hardware cursor stays at the prompt while a Client has key focus, so IME composition (Korean) is drawn in the prompt box
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report
- [x] Observed on 2.1.290; I checked the 2.1.296 build and the same code is there (see Version)
What's Wrong?
While a mod's Client element has keyboard focus (after the user clicks it), Claude Code keeps the terminal's hardware cursor at the prompt input's caret. Terminals that draw IME pre-edit text at the hardware cursor therefore show the composing character in the prompt box, not in the Client the user is typing into. I saw this in Orca, which is built on xterm.js. xterm.js places its composition view at the buffer cursor.
With Korean input, each syllable's in-progress text (ㅇ, then 아, then 안) appears in the prompt box. The Client's onKey gets only the committed syllable. The prompt itself is not changed, but it looks as if the user is typing into both places.
A mod can't fix this. ClientSurface has no way to declare a caret: its members are elements, state, columns, rows, setState, every, onPointer, onKey and post.
What Should Happen?
While a Client holds key focus, the hardware cursor should not stay at the prompt caret. Ideally a Client could declare its caret cell, so Claude Code parks the cursor there the way it does for the prompt and the built-in Input element. At minimum, the cursor should move into the focused Client's region.
Error Messages/Logs
None.
Steps to Reproduce
- Make a mod with a
Panewhose tree holds aClientwith this module:
``js``
export default (props, surface) => {
const { Text } = surface.elements
if (surface.state === undefined) {
surface.setState('')
surface.onKey(k => surface.setState(surface.state + k.key))
}
return Text({ children: surface.state || 'click here and type' })
}
- Start Claude Code with the fullscreen renderer, open the pane and click the
Client. - Switch the macOS input source to Korean (2-Set) and type
안. - The pre-edit
ㅇ→아→안is drawn at the prompt caret. TheClientshows안only after the syllable is committed.
You can check the cursor without an IME in tmux. After clicking the Client and typing into it, tmux display -p '#{cursor_x},#{cursor_y}' still reports the prompt caret cell (2,35 on the ❯ row in a 160x40 window), and #{cursor_flag} is 1.
Claude Model
Not relevant (Haiku 4.5 in the test session)
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.290 (Claude Code). The 2.1.296 darwin-arm64 build has the same Client surface members and no caret declaration.
Platform
Other (Claude Team subscription)
Operating System
macOS 27.0.1
Terminal/Shell
Orca 1.4.220 (xterm.js). Cursor position checked in tmux 3.6a.