Skip to content

Feature Request: IME cursor position support for CJK input (Japanese/Chinese/Korean) #19207

@koshikawa-masato

Description

@koshikawa-masato

Summary

When using Claude Code in terminals like Ghostty, the IME (Input Method Editor) candidate window for CJK (Japanese/Chinese/Korean) input appears at the bottom-left corner of the screen instead of at the cursor position. This makes CJK input difficult as users cannot see the conversion candidates near where they are typing.

Problem

Ink-based TUI applications hide the terminal's real cursor and render a visual cursor using ANSI styles. However, IME systems use the terminal's real cursor position (via firstRect on macOS) to determine where to display the candidate window.

Current behavior:

  • IME candidate window appears at bottom-left of terminal
  • User must look away from their input location to see candidates

Expected behavior:

  • IME candidate window appears at the cursor/input position
  • Natural input experience similar to native applications

Proposed Solution

I've created an Ink fork that adds enableImeCursor option to solve this:

Repository: https://github.com/koshikawa-masato/ink-ime-fork/tree/ime-cursor-support

How it works

  1. Add a CURSOR_MARKER (\u001B[999m - invisible SGR sequence) in the render tree at the desired cursor position
  2. During rendering, replace the marker with \u001B[s (Save Cursor Position)
  3. After output is written, send \u001B[u\u001B[?25h (Restore Cursor Position + Show Cursor)
  4. The terminal's real cursor moves to the marker position, allowing IME to display candidates correctly

Usage in Ink

import { render, CURSOR_MARKER } from 'ink';

// In component: place CURSOR_MARKER where the cursor should appear
<Text>{textBeforeCursor}{CURSOR_MARKER}{textAfterCursor}</Text>

// Enable IME cursor in render options
render(<App />, { enableImeCursor: true });

Key files changed

  • src/cursor-marker.ts - Marker constant and ANSI sequence handling
  • src/log-update.ts - Save/restore cursor position logic
  • src/render.ts - enableImeCursor option
  • src/ink.tsx - Option propagation

Environment

  • Terminal: Ghostty (also affects other terminals with IME support)
  • OS: macOS
  • Languages affected: Japanese, Chinese, Korean (any language using IME)

Additional Context

This is a common issue for CJK users of terminal-based applications. The solution has been tested and confirmed working in Ghostty terminal with Japanese input.

I'm happy to contribute a PR if this feature is welcome.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions