feat(terminal): Chinese / IME input (P3)
Implement IME composition support and migrate regular character input to a hidden textarea, matching the xterm.js approach. Key changes: - Add a hidden, absolutely-positioned `<textarea>` inside `.terminal-screen` that follows the terminal cursor cell. It receives focus on click, connect, and resize so the OS/browser IME candidate window appears at the cursor. - `on:input` now sends regular printable characters; `on:keydown` only handles special keys (arrows, Enter, Esc, Backspace, F-keys, Ctrl combos). - `on:compositionstart/end` track IME sessions and send the final composed string at the end, avoiding partial pinyin/jamo/kana leaks. - Move `on:paste` and `on:keydown` from `.terminal-screen` to the textarea so focus stays on the IME target. - Replace `.terminal-screen:focus` with `:focus-within` since the screen div no longer holds focus. - Add `is_regular_text_input` helper and unit test. Web-sys features extended with `InputEvent` and `CompositionEvent`. Tests: 24/24 pass, clippy clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -36,6 +36,7 @@
|
||||
| 粘贴(Ctrl-V / Ctrl-Shift-V / 右键菜单,含 bracketed paste) | `component.rs::handle_paste` / `prepare_paste` |
|
||||
| 文本选区 + 复制(自建模型,Ctrl-Shift-C / 选区存在时 Ctrl+C,跨滚动) | `component.rs` 鼠标处理 / `core.rs::selection_text` |
|
||||
| 鼠标上报(vim/htop/tmux 鼠标,SGR/Default/UTF-8 编码,滚轮) | `component.rs` 鼠标处理 / `encode_mouse_report` |
|
||||
| 中文 / IME 输入(拼音/日文/韩文,隐藏 textarea + composition 事件) | `component.rs::handle_input` / `handle_composition_*` |
|
||||
|
||||
---
|
||||
|
||||
@@ -111,33 +112,45 @@
|
||||
|
||||
---
|
||||
|
||||
### P3 — 中文 / IME 输入
|
||||
### P3 — 中文 / IME 输入 ✅ 已完成
|
||||
|
||||
**现状**:`map_key_to_terminal_input` 只处理 `key.chars().count() == 1` 的单字符,IME 组合输入(拼音候选)完全没接。
|
||||
**现状**:已实现。拼音、日文、韩文等 IME 组合输入可以正常工作;普通英文/数字输入也迁到了 `textarea` 的 `input` 事件,确保和 IME 走同一条路径。
|
||||
|
||||
**计划实现**:
|
||||
1. 改用 **`composition` 事件 + 隐藏 `<textarea>`** 的标准方案(xterm.js 也是这套):
|
||||
- 一个 1×1 透明、跟随光标的 `textarea` 承接 IME。
|
||||
- 监听 `compositionstart` / `compositionupdate` / `compositionend`。
|
||||
- 组合进行中不发字节;`compositionend` 时把最终文本一次性作为 Input 发送。
|
||||
- 普通 `input` 事件(非组合)也走这个 textarea,替代部分 `keydown` 逐字符逻辑。
|
||||
2. 光标定位:把隐藏 textarea 定位到终端光标处,让候选框出现在正确位置。
|
||||
**已实现**:
|
||||
1. **隐藏 `<textarea>` IME 载体**(`component.rs` view)
|
||||
- 绝对定位、透明、无边框、大小跟随终端光标单元格。
|
||||
- 通过 `tabindex="0"` 成为焦点目标;`terminal-screen` 改用 `:focus-within` 显示焦点环。
|
||||
2. **事件模型迁移**
|
||||
- `on:input`:普通字符/数字/空格输入,读取 textarea value 后清空并发送。
|
||||
- `on:compositionstart` / `on:compositionend`:IME 组合期间不发字节,`compositionend` 时发送最终文本。
|
||||
- `on:keydown`:仍处理方向键、Enter、Esc、Backspace、F 键、Ctrl 组合等**非打印键**。
|
||||
- `on:paste`:从 `terminal-screen` 移到 textarea,确保 focus 在 textarea 时右键/菜单粘贴也能触发。
|
||||
3. **焦点管理**
|
||||
- 点击 terminal-screen、WebSocket 连接成功、窗口 resize 后都聚焦 IME textarea。
|
||||
4. **测试**:新增 `is_regular_text_input_detects_printable_keys` 单测,确保打印字符被正确交给 textarea;24 个 terminal 测试全过,clippy 干净。
|
||||
|
||||
**风险**:中高。事件模型要从「keydown 逐键」迁一部分到「textarea + composition」,需保证不回归现有按键。建议**先把 P1 功能键做完再动这块**,避免两套输入逻辑互相打架。
|
||||
**已知限制**:
|
||||
- 主屏幕 scrollback 滚动后,光标可能位于可见区域下方,IME 候选框位置会对应到光标逻辑位置(可能偏下)。IME 主要用于当前输入, scrolled-back 场景输入较少见。
|
||||
- 目前不支持 textarea 自动滚动延伸选区(和 P0 同一限制)。
|
||||
|
||||
---
|
||||
|
||||
## 3. 其余缺口(暂不排期,记录备查)
|
||||
### P4 — Canvas / WebGL 渲染器(性能目标)
|
||||
|
||||
xterm.js 还有这些,本项目暂列「按需再做」:
|
||||
**现状**:DOM 渲染。常规 80×24–160×40 终端流畅,但大终端(≥200×100)或高刷新率连续输出时,DOM 节点多、重排重绘开销大。
|
||||
|
||||
- **链接检测**(点 URL 打开)、**搜索 / 查找**(Ctrl-F 高亮)
|
||||
- **光标样式**:块 / 竖线 / 下划线 + 闪烁(目前固定块状反色)
|
||||
- **Canvas / WebGL 渲染器**:当前是 DOM 渲染,够用但不如 Canvas 快;超大终端 + 高刷新率场景才需要 → **已纳入长期性能目标,P3 后推进**
|
||||
- **sixel / 图片协议**、**字形连字控制**
|
||||
- **Unicode 11/15 宽度表**:目前依赖 vt100 的宽度判断,极端 emoji / 新字符可能不准
|
||||
- **无障碍**(屏幕阅读器 live region)
|
||||
- **公开 API / 插件系统 / 配置项**:当前是项目内定制组件,无对外 API
|
||||
**计划实现**:
|
||||
1. **Canvas 2D 渲染器(先做)**
|
||||
- 一屏单元格一次 `fillText` / `fillRect` 绘制,减少 DOM 节点。
|
||||
- 保留现有 `TerminalCore` 数据模型,渲染层换成 Canvas。
|
||||
- 文本选区用 Canvas 半透明矩形;光标用 Canvas 反色或额外 DOM overlay。
|
||||
2. **WebGL 渲染器(后做)**
|
||||
- 把字符集预渲染到 texture atlas,用 shader 批量绘制。
|
||||
- 适合超大终端 + 高刷新率场景,但实现复杂度高。
|
||||
3. **可切换**
|
||||
- 默认 DOM,提供 prop/api 切到 Canvas/WebGL。
|
||||
|
||||
**风险**:高。需要重新实现渲染层、文本测量、选区高亮、滚动逻辑,同时保证和现有 `TerminalCore` 数据模型兼容。
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user