React Inkは現在、IME(Input Method Editor)のコンポジション イベントをサポートしていません。 これは根本的なアーキテクチャの制限によるものです。
React InkのuseInputフックは、キーボード入力を文字単位で処理します:
const handleData = (data: string) => {
const keypress = parseKeypress(data);
let input = keypress.ctrl ? keypress.name : keypress.sequence;
inputHandler(input, key);
};主な制限事項:
setRawMode(true)により端末の行編集をバイパス なぜRawモードがコンポジション イベントを妨げるのか:
技術的な回避策の可能性(すべて非常に複雑):
// 理論的なアプローチ - 現在は不可能
if (isCompositionActive()) {
setRawMode(false); // 端末コンポジションを許可
waitForCompositionEnd();
} else {
setRawMode(true); // 通常のキー処理
}React InkのGitHubリポジトリには:
これは、この技術的課題に対する認識が限定的であることを示しています。
通信プロトコル階層:
アプリケーション層 │ アプリケーションがXIMライブラリ関数を呼び出す
インターフェース層 │ XIMライブラリがリクエスト/レスポンスを処理
プロトコル層 │ XIMプロトコル メッセージのフォーマット
トランスポート層 │ Xプロトコル、TCP/IP、Unix ソケットCookedモード(正規モード):
Rawモード(非正規モード):
struct termios raw;
tcgetattr(STDIN_FILENO, &raw);
raw.c_lflag &= ~(ICANON | ECHO | ISIG | IEXTEN);
raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);XIM入力スタイル:
VTE(Virtual Terminal Emulator)実装:
typedef struct {
char *text; // プリエディット文字列
PangoAttrList *attrs; // テキスト属性
int cursor_pos; // プリエディット内のカーソル位置
} VteIMContext;| 機能 | Terminal.app | iTerm2 | Alacritty | Kitty | WezTerm |
|---|---|---|---|---|---|
| 基本IMEサポート | ✅ 良好 | ✅ 優秀 | ⚠️ 普通 | ✅ 良好 | ✅ 非常に良好 |
| インライン コンポジション | ✅ 基本 | ✅ 高度 | ⚠️ 最近 | ✅ あり | ✅ あり |
| プリエディット表示 | ✅ 標準 | ✅ 拡張 | ⚠️ 基本 | ✅ 良好 | ✅ 良好 |
| 候補選択 | ✅ 標準 | ✅ 拡張 | ❌ 限定的 | ✅ 良好 | ✅ 良好 |
| 設定オプション | ❌ なし | ⚠️ 限定的 | ⚠️ 限定的 | ⚠️ いくつか | ✅ 豊富 |
| 日本語キーボード サポート | ✅ ネイティブ | ✅ 優秀 | ❌ 問題あり | ✅ 良好 | ✅ 良好 |
iTerm2:最も洗練された日本語入力体験を提供
config.use_ime = true
config.macos_forward_to_ime_modifier_mask = 'SHIFT|CTRL'Terminal-Kit:
const termkit = require('terminal-kit');
const term = termkit.terminal;
term.inputField({
echo: true,
default: '',
cancelable: true
}, function(error, input) {
// 基本的な入力よりも良好なコンポジション イベント処理
term.green("\nあなたの入力: '%s'\n", input);
});Neo-Blessed(メンテナンスされたフォーク):
Windows(node-ffi-napiを使用):
const ffi = require('node-ffi-napi');
const user32 = ffi.Library('user32', {
'ImmGetContext': ['pointer', ['pointer']],
'ImmGetCompositionStringW': ['int', ['pointer', 'uint32', 'pointer', 'uint32']]
});macOS(子プロセスを使用):
const { execSync } = require('child_process');
function getCurrentInputSource() {
const result = execSync(`
osascript -e 'tell application "System Events"
to return name of current keyboard layout'
`).toString().trim();
return result;
}ハイブリッド アプローチ:
const blessed = require('blessed');
const pty = require('node-pty');
class IMETerminal {
constructor() {
this.screen = blessed.screen({
smartCSR: true,
fullUnicode: true
});
this.pty = pty.spawn('bash', [], {
env: { ...process.env, LANG: 'ja_JP.UTF-8' }
});
}
}イベント フロー アーキテクチャ:
キーボード ハードウェア
↓
カーネル入力サブシステム
↓
X11サーバー / Waylandコンポジター
↓
端末エミュレータ(xterm、VTEなど)
↓
XIMクライアント ライブラリ
↓
IMEサーバー(ibus、fcitxなど)
↓
IMEエンジン(pinyin、mozcなど)
↓
アプリケーション(shell、vimなど)現在の制限:カーソル位置(ESC[6n)やデバイス属性(ESC[0c)のような他の端末状態クエリとは異なり、** IMEコンポジション状態をクエリする標準化された制御シーケンスは存在しません**。
理論的な提案(未実装):
ESC[?1000$p - IMEアクティブ状態のクエリ
ESC[?1001$p - コンポジション文字列のクエリ
ESC[?1002$p - 候補数のクエリClear Code GLFW IME拡張:
glfwSetPreeditCursorPos()
glfwGetPreeditCursorPos()
glfwSetPreeditString()Windows Terminal IMEの改善:
React Inkは根本的なアーキテクチャの制限により、IMEコンポジション イベントをサポートできません。 この制限は、React Inkの実装ではなく、Node.jsのRawモード端末制約に起因しています。
IMEサポートが重要なアプリケーションの場合:
この分析により、React InkでのIMEコンポジション イベント サポートは、現在の端末およびNode.jsアーキテクチャの制約では簡単に克服できない重大な技術的障壁に直面していることが示されています。