Files
feresaria/docs/development/rime-poc.md
T
aria 993bc0f88f Integrate native Rime and stabilize input, output, and rendering
- Add optional modifier-only Super binding whose tap is cancelled by
  other input, focus changes, grabs, locks, and session teardown.
- Ship the native ferese-rime user service, Rime defaults, installer
  inventory, package dependencies, session environment, and docs.
- Vendor Smithay 8a27023 with the SHM texture-cache format fix and add
  GPU regressions for format changes and resize snapshots.
- Release reused CRTC owners before staging output modes, then restore
  changed outputs before former owners when a transaction fails.
- Wait for resize-capture GPU completion, expand filtered surface
  damage, and preserve IME popup origin under fractional scaling.
- Mark weekends like holidays in both calendar layouts.
2026-10-30 03:13:43 +09:00

207 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Ferese 原生 Rime 原型
本地分支:`twilight/rime-service-poc`。基线为 Ferese `v0.1.0`,提交
`f21167e1a22d527460e20a0eb3184790ee9754df`。这是本设备上的架构验证,尚未作为日常桌面版本发布。
## 进程与协议
```mermaid
flowchart LR
A[原生 Wayland 应用] <-->|text-input-v3| B[Ferese 合成器]
B <-->|input-method-v2 / virtual-keyboard-v1| C[独立 Rust Rime 服务]
C <--> D[librime 与独立测试词库]
B -->|主题 IPC| C
C -->|原生 input-popup SHM 缓冲区| B
```
`ferese-rime` 是独立进程。它直接调用系统 librime,通过原生 Wayland 协议接收按键、
提交文字和预编辑状态,并用 Rust 光栅化候选内容。候选颜色订阅现有 Ferese 主题 IPC。
Ferese 负责候选弹窗的父窗口关联、层级、坐标和屏幕边界处理。候选不是普通应用窗口。
本设备的字体默认改为 **MiSans**,候选服务优先加载 **MiSans / MiSans TC**。
候选使用紧凑的横向布局,编号和候选字按实际字形边界垂直居中,
圆角、底色、边框和选中态颜色取自 Ferese 主题。
组字时数字行 `-` 翻上页、`=` 或 `+` 翻下页;普通英文状态保留这些字符。
librime 仍是 C++ 引擎,通过一个由安装头文件检查 ABI 的小型 C 接口连接 Rust。
组字、词库和候选光栅化都在服务进程内执行。当前实现没有使用 Fcitx5、IBus 或其 D-Bus 兼容服务。
合成器的改动包括:
- 在输入法开关下增加 `virtual-keyboard-v1`;默认不公开这两个输入法全局接口。
- 为辅助键盘保留独立按键来源;输入法自身转发的按键绕过它自己的 grab,避免回环。
- 拒绝锁屏期间的虚拟按键,并清理离线辅助设备的按键状态。
- 失去嵌套窗口焦点时释放物理来源的按键,清除快捷键重复和拦截状态。
- 区分 input-method 与 xdg popup 的几何语义;候选不再被父窗口的圆角边界裁剪。
- 在输出底部向上展开候选,在左右边界约束位置;缩放使用逻辑坐标与原生 viewport。
## 构建与启动
### 本机日常会话安装
安装清单现包含 `ferese-rime`,Arch 包声明 `librime` 和 `rime-luna-pinyin`
依赖。公共方案与词库仍由系统包维护于 `/usr/share/rime-data`,不复制个人词库。
直接 DRM 会话默认启用原生输入法,并仅在 Ferese 会话内覆盖继承的 IBus Qt 环境。
GTK 不强制指定输入模块,由实际的原生 Wayland/X11 后端自行选择;
会话激活环境清空旧的 `GTK_IM_MODULE`,避免 XWayland 应用加载 GTK3 Wayland 模块时崩溃。
这些变量也导入该会话的 D-Bus/systemd 激活环境。嵌套预览保留原有的显式输入法启动方式。
会话在 `$XDG_DATA_HOME/ferese/rime`(默认 `~/.local/share/ferese/rime`)建立独立用户目录,
仅在 `default.custom.yaml` 不存在时安装默认简体拼音和每页九个候选的配置。
不读取、迁移或覆盖 IBus/Fcitx 的个人词库,也保留该目录内已有的用户定制。
Rime 由会话固定版本的 systemd 用户临时服务运行,异常后重启并启用十秒输入循环 watchdog;
服务名称由合成器控制套接字稳定生成,Shell 硬崩溃恢复时仅替换该会话的旧输入法实例。
会话结束时停止,输入法失败保留桌面。可用 `journalctl --user -u 'ferese-rime-session@*'`
查看日志。`FERESE_ENABLE_INPUT_METHOD=0` 可在登录前显式停用此集成。
以下预览与硬件验证记录早于此安装集成,不能代替新安装会话的验收。
需要仓库的构建依赖,以及 `librime`、`xkbcommon` 和 Wayland 开发文件。
验证环境使用系统 librime 1.17.0、GTK4 4.24.1、RTX 4090、NVIDIA 615.78.08。
Rust 工具链由仓库固定为 1.95.0。
```sh
cargo build -p ferese -p feresectl -p ferese-rime --locked -j 12
python3 scripts/rime-preview.py start
python3 scripts/rime-preview.py status
```
预览使用开发版合成器、开发版输入法和已安装的 0.1.0 Shell。它会打开原生 GTK 测试框,
并在本机存在 Strata 时打开单独的测试目录。GTK 使用 `GTK_IM_MODULE=wayland`。
`scripts/rime-preview.py restart` 重开开发预览;`stop` 停止它;`ime` 只启动输入法服务。
输入法由独立 systemd 用户临时服务管理。异常退出后 1 秒自动重启;输入循环停止响应时,
10 秒 watchdog 会终止旧进程并重启。心跳来自实际输入循环,librime 卡住时不会继续报健康。
每分钟最多尝试 5 次,避免配置错误造成无限快速重启;主动 `stop` 不会触发重启。
服务不可用期间桌面保留,英文继续由合成器直接处理。
本机应用菜单中已有“Ferese Rime 开发预览”入口,右键操作可重开或停止。
入口仅调用本仓库脚本;移动仓库后应更新
`~/.local/share/applications/ferese-rime-preview.desktop` 中的路径。
预览的配置、缓存、词库和证据位于 `.artifacts/rime-poc-20261028/`。
运行时套接字位于当前 UID 的 `/run/user/<uid>/ferese-rime-poc/`,目录权限为 0700。
它使用独立 D-Bus 和独立 systemd 用户临时服务,不导入宿主桌面的激活环境。
测试词库由系统方案建立,不导入原有 IBus/Fcitx 个人词库。
## 验证
### 按窗口保留状态
运行时按合成器会话 ID 和窗口 ID 隔离中英文模式、Rime schema;新窗口按应用 ID 恢复上次选择。
同一应用的两个现存窗口可保留不同状态;关闭后重开时采用该应用最后显式选择的状态。
输入法进程重启后也会恢复当前窗口偏好,不恢复未提交的组字。
`input-profiles.json` 位于独立 Rime 用户目录,通过 0600 临时文件、fsync 和原子重命名保存。
只保存应用标识和输入偏好,不保存窗口标题、聊天内容或组字文本。
`Ctrl+Space` 切换当前窗口的英文/Rime;原有 Shift 切换也会被保存。
```sh
# 在对应会话环境中查询或更改当前窗口;敏感输入框拒绝更改。
target/debug/ferese-rime --status
target/debug/ferese-rime --mode ascii
target/debug/ferese-rime --mode rime
target/debug/ferese-rime --select-schema luna_pinyin
```
控制套接字由 `FERESE_RIME_CONTROL` 指定,权限 0600。服务不运行时,查询命令不会初始化词库。
```sh
cargo test -p ferese input::binding_mode_tests -- --nocapture
cargo test -p ferese handlers::input_method::tests -- --nocapture
cargo test -p ferese-rime --lib --locked
cargo clippy -p ferese-rime -p ferese --all-targets --locked -- -D warnings
./target/debug/ferese-rime --user-data .artifacts/rime-poc-20261028/rime-self-test --self-test
FERESE_TEST_RIME=1 python3 scripts/tests/test_rime_native_isolated.py
FERESE_TEST_RIME=1 python3 scripts/tests/test_rime_resilience_isolated.py
```
最后一个测试实际启动构建树预览,操作专用原生 GTK 测试框,验证:
- 组字未提前提交、原生候选不是普通顶层窗口、空格和数字选字。
- 退格、取消、Shift 中英文切换、英文透传和 Ctrl+A 的按下/释放配对。
- 数字行减号、等号及 Shift+等号翻页,翻页后数字选字;候选保持单行横向排列。
- 敏感输入框直接收到测试英文,Rime 未收到这些组字事件。
- 底边候选组字和提交,以及候选主题的实时切换;截图单独检查位置和外观。
- 在组字期间 SIGKILL 输入法:合成器进程保持不变,服务自动重启并恢复当前窗口方案。
- SIGSTOP 停止输入循环,确认 watchdog 真正回收并重启进程;关闭重开应用仍保留模式和 schema。
- 输入法进程实际映射 librime,未映射 IBus/Fcitx 库。
- 测试输入工具连接真实宿主时拒绝输入。
`ferese-rime-probe` 只供集成测试使用,需要显式 `FERESE_TEST_INPUT=1`,且在创建虚拟键盘前
检查目标确为只有 `ferese-winit` 输出的 Ferese 嵌套实例。
独立 DRM 测试额外要求专用 runtime 目录和与连接端 SO_PEERCRED 一致的合成器 PID。
普通宿主显示连接仍被拒绝,测试不向宿主注入键盘事件。
测试框只输入可丢弃样本,其普通字段保存在 `entry-state.json` 便于独立读回;敏感字段只记录长度。
自动结果和截图保存在同一证据目录,不能用单纯的编译通过代替桌面输入验收。
2026-10-28 的本机自动检查全部通过;用户随后使用实际键盘确认
“显示、翻页和选字正常”。底边候选向上展开、浅深色主题已逐张检查截图。
后续故障注入中,SIGKILL 后约 2.4 秒恢复,SIGSTOP 后约 11 秒被 watchdog 回收并恢复。
### 本设备的图形路径
这台设备由 NVIDIA 负责三个物理显示器,AMD 核显没有连接显示器。
嵌套后端原先只公开 v3 格式列表,现增加实际 EGL 渲染设备的 v4 DMA-BUF 反馈。
DRM 后端在可识别主 GPU 时只向客户端公开其分配入口,保留已有的按表面分配反馈。
修复后 QQ 图形子进程使用 NVIDIA 渲染节点;GTK 原先的空白内容恢复显示。
独立会话已分别用 GTK Vulkan 和 OpenGL 路径完成三屏输入及锁定/解锁协议测试。
Super+左键拖动沿用上游默认绑定,已用实际输入处理路径验证窗口位置改变。
`FERESE_ENABLE_TEST_POINTER=1` 仅在本机测试启动器启用虚拟指针;默认不公开该全局接口,
锁定时也拒绝虚拟指针事件。此接口用于重现 QQ 对话切换和拖动,不用于候选点选。
### 独立 logind/DRM 会话
```sh
python3 scripts/rime-drm-validation.py start
FERESE_TEST_DRM=1 FERESE_TEST_GSK=vulkan python3 scripts/tests/test_rime_drm_isolated.py
FERESE_TEST_DRM=1 FERESE_TEST_GSK=gl python3 scripts/tests/test_rime_drm_isolated.py
python3 scripts/rime-drm-validation.py return
python3 scripts/rime-drm-validation.py stop
```
启动器在空闲 tty3 建立独立的临时 PAM/logind 会话,保留原 GNOME 会话。
启动前先安排独立的返回定时器;默认 60 秒返回,人工解锁测试使用 120 秒。
配置、D-Bus、运行时目录均独立,私有 runtime 在启动 D-Bus 前设置,避免影响宿主激活环境。
停止时清理本次输入法、测试应用、临时服务和本次 logind scope;不注销原会话。
已验证 DP-4、DP-5、DP-6 同时以 3840×2160、150% 缩放工作,刷新率约 60/160/144 Hz。
各屏组字、候选和提交正常。协议测试确认三个输出都完成保护帧后才报告锁定,
锁定时普通应用不收到测试键,截屏被拒绝;锁定期间输入法自动恢复后,解锁可继续中文输入。
协议测试夹具不校验 PAM 密码;人工密码解锁另用原版 `/usr/bin/ferese-lock --foreground` 验证。
真实锁屏已由用户输入本人密码完成,状态读回包含锁定到解锁的完整转换,锁屏程序正常退出。
用户确认“三屏显示和解锁正常”。该测试不读取或记录密码。
### QQ 与 Teams
```sh
python3 scripts/rime-app-preview.py qq
python3 scripts/rime-app-preview.py teams
python3 scripts/rime-app-preview.py stop
```
直接使用原生 Wayland Electron 输入参数,在各自独立测试资料目录中启动。
原 GNOME 下的 IBus/Fcitx 启动器、登录资料和 desktop 文件不修改。
QQ 已由用户登录,搜索输入和实际消息编辑框中的候选及“你好”提交通过,
测试文字随后删除,窗口关闭重开后仍保持 Rime。
已自动反复切换群助手和其他对话,对比屏幕帧及独立窗口重绘;首次加载图片导致的差异单独检查。
用户复测确认 QQ 切换对话“不再花屏”。未发送测试消息。
Teams 使用额外空白资料目录验证实际登录页文本框:原生 Rime 提交“你好”,
通过页面字段值独立读回,然后清空,未提交登录。
用户账户的 Teams 登录停在人脸/指纹/安全密钥验证页,用户确认 GNOME 下也有同样表现;
该登录条件尚未解除,不能把 Teams 的消息编辑器输入标为已验收。
## 当前边界
- 已覆盖原生 GTK4 输入路径和 Strata 的候选显示,当前默认方案为 `luna_pinyin_simp`。
- 候选只做键盘操作,按本次需求不实现鼠标选词;配置界面仍待实现。
- 使用 US 键盘布局和嵌套输出验证;多布局切换、其他方案、个人词库迁移尚未验收。
- 原生 QQ 搜索和消息编辑框、Teams 登录页输入已验证;Teams 消息编辑器、Qt、Xwayland 和 Shell 的 layer-surface 输入仍未验收。
- 独立 DRM 三屏及锁定协议已覆盖;物理热插拔、跨不同 GPU 的显示器组合和长期使用仍需验证。
- 当前为调试构建;字体加载、词库部署和重复绘制尚未进行性能优化。
- `FERESE_ENABLE_INPUT_METHOD=1` 仍沿用上游“受信任会话客户端”的许可边界,
专用私有连接授权属于后续工作。
后续可以继续复用这套独立进程边界,逐步补齐候选交互和会话管理。