# CodeLin TUI Raw Input Zig 改造方案（v0.1）

> 目标：以 Zig 重写 `/ffi/raw_input_{win,linux}.c`，在维持现有 C ABI（`enterRaw/exitRaw/getRawUtf8/getByte`）基础上，获得更安全的内存模型、更易维护的跨平台输入层，为后续 TUI 重构打下基础。

---

## 1. 背景与关键诉求

1. 现有 C 实现逻辑复杂、缺乏测试，维护成本高。
2. Zig 具备：
   - 直接调用 C/Win32 API 的零成本互操作。
   - 更安全的内存管理（`defer`、`errdefer`、内置检查）。
   - `std.os` 提供跨平台终端控制封装，可精确掌控行为。
3. 约束：
   - CLI 仍通过 FFI 调用，暂不改动 Cangjie 代码。
   - 编译产物需生成 `.a/.dylib/.dll` 供 `cjpm build` 链接。
   - 计划需便于逐步 rollout，可随时回滚到 C 版本。

---

## 2. Zig 生态调研（含参考库）

| 类别 | 库/模块 | 亮点 | 适用性评估 |
|------|---------|------|------------|
| Win32 绑定 | [`zigwin32`](https://github.com/marlersoft/zigwin32) | 自动生成的 Win32 接口，支持 Console API、输入事件。 | ✅ 用于 `ReadConsoleInputW`、`SetConsoleMode` 等。 |
| TUI/终端 | [`xig`](https://github.com/andrewrk/xig) | Zig 编写的迷你终端工具，可参考事件循环。 | 🔍 可借鉴键盘解析逻辑，但不直接依赖。 |
| POSIX Raw 模式 | Zig `std.os.tty`, `std.os.linux.termios` | 内置 termios 封装，可直接控制 `ICANON/ECHO`。 | ✅ 主力方案。 |
| 事件/抽象 | [`zgt`](https://github.com/zenith391/zgt) | GUI/TUI 抽象层，示例多，但依赖更重。 | ⚠️ 当前只需原生输入，不引入。 |
| 构建辅助 | Zig `build.zig` + `zig build-lib` | 原生生成 `.a/.dylib/.dll`。 | ✅ 直接使用。 |

Rust 生态（如 `crossterm`、`termion`）仍可作为行为参考，但 Zig 方案将完全基于标准库 + `zigwin32` 实现，避免额外依赖。

---

## 3. 目标架构

```
ffi/
  zig_rawinput/
    build.zig
    src/
      lib.zig            # 导出 C ABI
      backend/
        common.zig       # 事件枚举/UTF-8 编码工具
        windows.zig      # Win32 Console 输入
        unix.zig         # termios + poll
    include/raw_input.h  # cbindgen 或 Zig 导出头文件
```

- `backend.common`: 定义 `RawKey`/`RawEvent`、UTF-8 编码函数、虚拟键映射。
- `backend.windows`: 使用 `zigwin32` 调用 `GetStdHandle`, `ReadConsoleInputW`, `WaitForSingleObject`。
- `backend.unix`: 使用 `std.os.termios` 控制 raw mode，`std.os.poll`（或 `epoll/kqueue`）实现超时读取。
- `lib.zig`: 暴露 `extern` 函数，并在内部缓存单例状态（如 `raw_mode_enabled`）。
- 构建：`zig build-lib -Drelease-fast -target <triple>`，输出静态/动态库；在 `build.zig` 中根据目标平台决定导出格式。

---

## 4. 分阶段实施计划

### Phase 0：Zig FFI 原型（1 Sprint）
1. 新建 `ffi/zig_rawinput`，编写最小 `lib.zig`：
   ```zig
   export fn enterRaw() bool { ... }
   export fn exitRaw() void { ... }
   export fn getRawUtf8(buf: [*]u8, len: usize) c_int { ... }
   export fn getByte(timeout_ms: u32, key_code: [*]u16) c_int { ... }
   ```
2. Linux/macOS：使用 `std.os.termios` 切 raw 模式，`std.os.read` 读取单字节并解析 ESC 序列。
3. Windows：先直接 `@cImport` Win32 头文件完成最小 demo。
4. 输出 `.a`，在 CLI 中试编译（本地/CI），确保 ABI 兼容。

### Phase 1：功能对齐（1–2 Sprint）
1. UTF-8 编码&虚拟键映射：
   - 保持与 C 版本一致的 ESC 序列 → Unicode 箭头 / Ctrl+A/E 等。
   - Zig 提供 `std.unicode.utf8Encode`, `std.unicode.utf16leToUtf8`，处理 surrogate。
2. 超时读取：
   - Windows：`WaitForSingleObject` + `ReadConsoleInputW`。
   - POSIX：`std.os.poll` + 非阻塞 `read`。
3. 错误处理：统一返回 `bool`/`c_int`，并通过 `std.log` 输出调试信息，支持 `ZIG_LOG_LEVEL` 控制。
4. 自动化测试：
   - `zig test src/backend/common.zig` 验证编码逻辑。
   - 在 CI 中运行 `zig test` + `cjpm build`。

### Phase 2：优化与扩展（1 Sprint）
1. 性能调优：
   - Windows：若 `zigwin32` 调用开销大，可直接 `@cImport("windows.h")`。
   - Linux：必要时切换到 `epoll`/`kqueue`，减少 wake-up。
2. 新增能力预留：
   - `export fn flushInput()` / `export fn peekEvent()`（暂不在 C 层使用）。
   - 统一事件枚举（键盘/鼠标），便于未来 TUI 调用。
3. 文档与切换：
   - 更新 `ffi/README.md`（Zig 构建方法、环境要求）。
   - 在 `cangjie1.md` / `codelin15.md` 标记 Zig Raw Input 计划（实施后）。

---

## 5. 工程细节

1. **跨平台构建**  
   - Linux/macOS：`zig build-lib src/lib.zig -target x86_64-linux-gnu` / `x86_64-macos-none`。  
   - Windows：`zig build-lib src/lib.zig -target x86_64-windows-msvc`，输出 `.dll`+`.lib`。  
   - `build.zig` 中加入 `install` 步骤，把产物复制到 `ffi/` 根目录并命名为 `librawinput.*`。

2. **C 头文件生成**  
   - 使用 Zig 的 `@cDefine` + `std.Build` 生成 `raw_input.h`，包含 extern 函数签名。  
   - 在 Cangjie 侧替换旧头文件，确保结构体/常量一致。

3. **回滚策略**  
   - 保留原 C 版本，通过环境变量 `CODELIN_RAWINPUT=zig|c` 控制链接库（可在 `build.cj`/CI 中配置）。  
   - 首次上线仅在 macOS/Linux 使用 Zig，Windows 暂时继续 C 版本，待验证后再切换。

---

## 6. 产出物（写入 `tui2.md` 即本文）

1. `ffi/zig_rawinput` 完整源码 + `build.zig` + README。
2. 新 `librawinput` 静态/动态库（各平台）。
3. Zig 单元测试 & 集成测试脚本。
4. 更新后的 `raw_input.h`。
5. 完成后的状态同步（`cangjie1.md`/`codelin15.md`）。

---

> 下一步：按照 Phase 0 创建 `zig_rawinput` 原型，验证 zigwin32 与 termios 封装，确认能在 macOS/Linux 输出与旧版本一致的 UTF-8 序列后，再进入 Phase 1 做全面替换。

