Skip to content

Conversation

@hongsw
Copy link

@hongsw hongsw commented Jan 25, 2026

Summary

  • Fix IME composition events not being captured for Korean, Chinese, Japanese input
  • Fix spaces appearing between CJK characters when copying text from terminal

Fixes #119

Problem

IME composition events (compositionstart, compositionupdate, compositionend) fire on the focused element. When using a hidden textarea for keyboard input (as ghostty-web does), the textarea receives focus, but composition event listeners were attached to the container element. This caused all IME events to be missed.

Current:
  Canvas click → textarea.focus()     (focus goes to textarea)
  IME listeners → attached to container  ❌ MISMATCH

Fixed:
  Canvas click → textarea.focus()
  IME listeners → attached to textarea  ✅

Additionally, when copying CJK text from the terminal, spaces appeared between characters because the continuation cells (width=0) for wide characters were being treated as empty spaces.

Changes

  1. input-handler.ts: Attach composition events to inputElement (textarea) if available
  2. terminal.ts: Focus textarea instead of container in focus() method
  3. selection-manager.ts: Skip wide character continuation cells when extracting text

Test Plan

  • Type Korean text (e.g., "안녕하세요") - characters appear correctly
  • Type Chinese text (e.g., "你好") - characters should appear correctly
  • Type Japanese text (e.g., "こんにちは") - characters should appear correctly
  • Select and copy CJK text - no extra spaces between characters
  • English typing still works normally

Known Limitation

Fast Korean typing may occasionally insert extra spaces due to composition event timing. This is tracked as a separate issue.

🤖 Generated with Claude Code

IME composition events (compositionstart, compositionupdate, compositionend)
fire on the focused element. When using a hidden textarea for input,
the textarea receives focus, but composition event listeners were attached
to the container element, causing the events to be missed.

Changes:
- input-handler.ts: Attach composition events to inputElement (textarea)
  if available, otherwise fall back to container
- terminal.ts: Focus textarea instead of container in focus() method
- selection-manager.ts: Skip wide character continuation cells when
  extracting selection text (fixes spaces between CJK characters)

This fixes Korean, Chinese, Japanese and other IME input methods.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f572fa14f7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +721 to +725
// Focus the textarea for keyboard/IME input.
// The textarea is the actual input element that receives keyboard events
// and IME composition events. Focusing the container doesn't work for IME
// because composition events fire on the focused element.
const target = this.textarea || this.element;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep blur behavior aligned with textarea focus

The new focus path now targets the hidden textarea when it exists, but blur() still calls this.element.blur(). When the terminal is open (default case creates the textarea), calling terminal.blur() will leave the textarea focused, so keyboard/IME input continues to be captured even though callers expect blur to release focus. This is a regression introduced by switching focus to the textarea. Consider blurring the same target (this.textarea || this.element) or explicitly blurring the textarea when present.

Useful? React with 👍 / 👎.

@hongsw
Copy link
Author

hongsw commented Jan 25, 2026

#119

aibaryonai-ctrl and others added 3 commits January 26, 2026 04:26
Display a small "조합중: X" indicator in the top-right corner during
IME composition. This helps users see what character is being composed
before it's finalized.

Korean is a compositional writing system where characters are built
step-by-step (e.g., ㅅ → 세 → 셰). This visual feedback makes the
composition process clearer.

Closes #2

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When pressing space or period to end Korean IME composition, the keydown
event fires before compositionend. This caused the triggering character
to be output before the composed text (e.g., "세요" becomes "세 요").

Added compositionJustEnded flag that blocks the first keydown after
composition ends, preventing the character order reversal.

Fixes #1

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove contenteditable from container (causes IME to insert text as DOM nodes)
- Set container tabindex="-1" so it's not focusable
- Add focus redirection from container to textarea
- Queue composition-ending key (space, period) to process after compositionend
- This ensures correct character order: "세요 " instead of "세 요"

Key changes:
1. input-handler.ts: Add pendingKeyAfterComposition to queue the terminating key
2. terminal.ts: Remove contenteditable, set tabindex="-1", add focus redirection

Fixes Korean, Chinese, and Japanese IME input.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@hongsw
Copy link
Author

hongsw commented Jan 25, 2026

스크린샷 2026-01-26 05-47-46

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Korean (Hangul) IME input not working

2 participants