双拼键位提醒(Shuangpin Keys)
Harness Web UI 插件。默认嵌入在会话内容与输入框之间(占真实布局,不遮挡任何内容),也可一键切换为可拖动的浮窗;它在你正常打字时自动收集速度与卡顿,把常卡的键标红,打字时在键盘上白框提示候选键位,并把「卡过的字」变成练习。
支持 小鹤双拼 / 自然码 / 微软双拼 / 智能ABC / 拼音加加 五种常见方案,以及自定义键位。
- 插件包:
@local/shuangpin-reminder(v1.5.0) - 双挂载:
conversation.input.dock(嵌入模式,会话与输入框之间)+shell.overlay(浮窗模式) - 默认收起成一条细栏(点「展开」即出键盘),嵌入/浮窗状态都会被记住
方案切换
面板左上角标题就是方案下拉框(显示当前方案名,如「小鹤双拼」),点开即可换方案;键位页本身不再放方案栏。选中「自定义…」会打开键位编辑器:可先选一个内置方案作模板,再逐个韵母改键,另可切换零声母规则(照全拼 / o 打头)。
键位表不是手写的,而是从 rime 官方 schema 的 speller/algebra 规则机械推导而来,并用 src/derive-check.cjs 校验,避免抄错:
node src/derive-check.cjs <rime schema 目录> --check # 与 src/schemes.cjs 内置表比对
界面(嵌入模式 = 默认)
(会话内容)
────────────────────────────────────────
⠿ 小鹤双拼 ▾ [键位][练习][记录] ◐ 📌 ⧉ ← 悬停面板才出现
┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐
│Q │W │E │R │T │Y │U │I │O │P │ ← 打 x 时:X[下] K[行] L[想] N[小] R[先] 白框提示
├──┴──┴──┴──┴──┴──┴──┴──┴──┤
│A │S │D │F │G │H │J │K │L │
│Z │X │C │V │B │N │M │
▸ 声母 / 韵母提示
────────────────────────────────────────
(输入框)
- 嵌入模式(默认):键盘插在会话与输入框之间,宽度自动跟随输入框区域,键位很大;不覆盖、不遮挡对话。展开/收起只用工具行(模型选择旁)的「鹤」开关,收起后完全不渲染。
- 浮窗模式:点标题栏的
🗗(U+1F5D7)切换(原地浮起)——可拖动(按住标题栏)、右下角⤡拉伸、滑杆调透明度、📌 固定;切回嵌入点🗖(U+1F5D6)。 - 悬停显影(两种模式一致):平时只显示三行键盘;鼠标移上面板,控制行才出现。
- 展开/收起:只用工具行(模型选择旁)的「鹤」开关——两种模式收起后都完全不渲染,恢复也用这个开关。
- 热力标记:只有出问题的键才有标记——黄条=不稳(卡壳率 25%–45%),红条+红边+韵母变红=常卡(≥45%);掌握较好的键不做任何标记。样本不足 2 次不显示。
提醒是怎么"即时"的
先说边界:双拼跑在系统输入法里,网页拿不到按键流。浏览器在合成时只给 compositionstart/update/end 和上屏文本,拿不到"你按了哪几个键"。所以能做到的是:
- 上屏后立刻(约 0.1 秒)在输入框上方弹出小条:
学 xt,同时键位图上X、T两个键高亮 2.6 秒。慢的会带「慢」。 - 合成过程中读输入法的预编辑文本:如果它暴露的是拼音(例如
xue),面板上会实时显示正在打:xue → xt。这条依赖输入法行为——有的输入法只显示双拼码或直接显示候选,那就只显示原文。获取方式是标准 DOM 事件:合成期间输入法会通过compositionupdate主动把预编辑文本报给页面,插件在document上捕获(此时keydown只有 keyCode 229,拿不到按键)。每次回显会带相对毫秒数记入「记录」页的「输入法回显采样」,用来确认你的输入法到底给了什么。 - 练习里才是真正提前的:卡住 1.2 秒自动亮出两个键(可关),答错直接给正确键位。
- 键盘框选(主要提醒面):面板上的键盘直接高亮,不用看别处——
- 打了声母、韵母还没打(如
x):常用字(下/行/想/小/先…)对应的韵母键被白框框选,键上标出候选字; - 打完一个字:按你的「上一个字 → 下一个字」历史(不足时用常用接续兜底),把下一个字的双拼键框选出来,首选键加重;
- 合成中已完成的音节键会轻框确认。 原先输入框上方的小条已移除,提醒统一收敛到键盘区域。
- 打了声母、韵母还没打(如
也就是说:真实输入是"上屏即提示",练习是"提前提示"。想更提前,只能靠练习把键位练熟。
数据收集(先收集,再变准)
- 每次上屏记录:哪些字、这次合成花了多久、中间退格几次。
- 卡壳过程:合成期间预编辑串一旦变短(你退格改码),整条轨迹会被记下来,如
q→qi→qin→qi→qing(想打情,韵母忘了先按了 N)。 - 按键混淆:从卡壳轨迹里推断「该按的键 vs 实际按的键」,如
该按 K,实按 B ×4。仅在输入法预编辑暴露拼音时可归因;只暴露码时保留轨迹。 - 字级二元:记录「上一个字 → 下一个字」的接续频率,驱动键盘框选的下一个字预测(个人历史优先,内置常用接续兜底,上限 500 组)。
- 单字耗时 > 你近期均值的 1.5 倍 + 120ms,或退格 ≥ 2 次 → 记为一次「卡」。
- 字 → 拼音 → 双拼两键(内置 3755 个常用字的表),于是「哪些键常出现在卡顿的字里」就出来了。
- 「记录」页显示:收集进度、最容易卡的键与常按错的键(并排)、卡过的字,以及最近输入 / 输入法回显采样 / 卡壳过程三栏并列。面板高度有上限、只滚正文,所以记录页再长也能随时点回「键位」页。
- 记录按方案分开存:同一套键位在不同双拼方案下含义不同(比如
k在小鹤是ei、在自然码是iao), 混在一起的热力图没有意义。所以在标题栏切换方案后,进度、弱键、错键、卡过的字、最近输入都只算当前方案; 换回来时原来的记录还在。记录页标题旁的小标签标出这份数据属于哪个方案。 - 旧记录归谁:1.5.0 之前的统计没有记录方案(那时插件只支持小鹤), 升级后统一归到小鹤。不归给「升级那一刻停留的方案」——否则你切到别的方案再重启, 小鹤攒下的记录就会跑到那个方案下,看起来像「换方案后记录还在」。 早期中间版本确实犯过这个错,现在会自动把错放的数据挪回小鹤(只搬一次)。
- 「练习」页可以切到 我的错字,只练你卡过的字。
隐私
不联网、不上传、无第三方请求。 全部数据只留在本机浏览器里,可用「记录」页的「清空」一键清除。
这个插件需要在输入框上统计打字,因此有必要说清楚它读了什么、存在哪:
读什么:只监听宿主的可编辑区域(textarea、文本输入框、contenteditable),
读取输入法上屏的文本与合成期间暴露的预编辑串,用于计算速度、退格与卡顿。
不读按键内容之外的任何东西:不注入输入框、不改写你的输入、不拦截按键默认行为、
不读取其它页面、不做任何网络请求。插件自己的面板(如「改键位」输入框)已被显式排除,
不会被计入统计。
存在哪:
| 位置 | 内容 | 说明 |
|---|---|---|
localStorage dsh.shuangpin-reminder.prefs.v4 |
位置、宽度、透明度、页签、方案、自定义键位 | 纯偏好 |
localStorage dsh.shuangpin-reminder.stats.v2 |
按方案分桶的逐字/逐键统计、最近 30 条输入、回显采样、卡壳过程 | 完整数据,仅此端口可见 |
cookie dsh.shuangpin.mirror.* |
仅聚合计数:键次数、错键次数、进度基数 | 见下 |
cookie 镜像的存在理由:GUI 端口每次启动会变,而 localStorage 按端口隔离、
cookie 不分端口,所以用一条小 cookie 让统计在换端口后还能接上。
镜像刻意不含用户输入原文——不带打过的字、不带拼音、不带卡壳序列,
因为 cookie 会随同源请求自动发送、且同域脚本可读。镜像约 1KB、1 条 cookie,
SameSite=Lax,https 下自动加 Secure。旧版本曾把原文写进镜像,
升级后会检测并自动重写清除。
关于旧存储键:1.5.0 之前包名为 @local/xiaohe-shuangpin-reminder,
存储键前缀是 dsh.xiaohe.*。改名后首次启动会自动把旧键的数据迁移到
dsh.shuangpin-reminder.*(新键已有数据时不覆盖),老用户的偏好与统计不会丢。
键位表(小鹤双拼;其余方案在面板标题里切换)
| 键 | 韵母 | 例 | 键 | 韵母 | 例 |
|---|---|---|---|---|---|
| Q | iu | 求 qiú → qq | A | a | 大 dà → da |
| W | ei | 杯 bēi → bw | S | ong / iong | 中 zhōng → vs |
| E | e | 饿 è → ee | D | ai | 买 mǎi → md |
| R | uan | 转 zhuǎn → vr | F | en | 人 rén → rf |
| T | ue / üe | 学 xué → xt | G | eng | 能 néng → ng |
| Y | un | 云 yún → yy | H | ang | 上 shàng → uh |
| U | 声母 sh;韵母 u | 是 shì → ui | J | an | 看 kàn → kj |
| I | 声母 ch;韵母 i | 吃 chī → ii | K | ing / uai | 平 píng → pk |
| O | uo / o | 多 duō → do | L | iang / uang | 想 xiǎng → xl |
| P | ie | 写 xiě → xp | Z | ou | 走 zǒu → zz |
| V | 声母 zh;韵母 ui / ü | 中 zhōng → vs · 女 nǚ → nv | X | ia / ua | 下 xià → xx |
| B | in | 心 xīn → xb | C | ao | 好 hǎo → hc |
| N | iao | 小 xiǎo → xn | M | ian | 天 tiān → tm |
- 每个音节两个键:声母键 + 韵母键。
- 小鹤零声母:单字母双写(啊
aa、鹅ee),双字母照全拼(爱ai、安an、欧ou、恩en、而er),ang/eng 用ah、eg。 ü一律按v:女nv、绿lv、略lt;ju/qu/xu/yu里的 u 也按v:去qv。
其他方案的差异(键位细节见面板内的键帽):
| 方案 | 声母 zh/ch/sh | 零声母 | 特点 |
|---|---|---|---|
| 小鹤双拼 | v / i / u | 照全拼 | 本表 |
| 自然码 | v / i / u | 照全拼 | ai=l、ei=z、ing=y、un=p |
| 微软双拼 | v / i / u | o 打头 | ing=; 键、ü=y |
| 智能ABC | a / e / v | o 打头 | ian=w、in=c、iao=z |
| 拼音加加 | v / u / i | o 打头 | ao=d、an=f、en=r |
目录
package.json 插件清单
cordis.patch.yml 插入 Host 行
index.js Host 半边(空实现)
client.js 生成的 Client 模块(含拼音表与方案表)
src/client.template.js 可读源码(UI 与业务逻辑,只改这里)
src/schemes.cjs 双拼方案数据层(键位表 / 编码 / 拼音解析,可独立测试)
src/derive-check.cjs 从 rime schema 推导键位并校验内置表
src/schemes.test.cjs 方案数据层断言测试
src/dict-src.txt 字 + 拼音数据(3755 条)
src/build-client.cjs 生成脚本(内联方案层与拼音表)
src/smoke.cjs 本地渲染/捕获冒烟测试
src/smoke-scheme.cjs 方案切换渲染测试
src/smoke-picker.cjs 自绘下拉交互测试(展开/选中/收起)
src/smoke-height.cjs 新会话高度回归(面板/键盘不被压扁)
src/smoke-mirror.cjs cookie 镜像行为(不含原文 / 可恢复 / 旧数据清除)
src/smoke-migrate.cjs 旧存储键迁移(不丢偏好与统计)
src/smoke-per-scheme.cjs 记录按方案隔离(切方案不串数据)
src/smoke-records-switch.cjs 记录页文本随方案变化
src/smoke-switch-live.cjs 同一 store 上实时切换方案
src/smoke-repair.cjs 旧统计错放到其他方案时的修复
src/mirror-size.cjs 镜像体积与隐私体检(估算 cookie 条数与上限)
src/smoke-proto.cjs 恶意统计数据不污染原型
src/add-fallbacks.cjs 给主题变量补兜底色(幂等,人工执行)
src/lint-locale.cjs 文案体检(死字符串 / 重复 key),构建时自动跑
src/layout-check.cjs 记录页三栏布局估算(窄面板是否会被挤扁)
src/key-size.cjs 键位尺寸换算表(人工核对用)
locale/ zh/en 标题与描述
icon.svg 图标
LICENSE MIT(含第三方数据说明)
改完源码后:
node src/build-client.cjs src client.js
node --check client.js
node src/schemes.test.cjs # 方案数据层
node src/smoke.cjs . map # 还有 drill / stats / float / fab / capture
node src/smoke-scheme.cjs . # 方案切换与自定义编辑器
node src/smoke-picker.cjs . # 下拉展开/选中/收起
node src/smoke-height.cjs . # 面板/键盘不可被压扁
node src/smoke-mirror.cjs . # cookie 镜像不含输入原文、可跨端口恢复
node src/smoke-migrate.cjs . # 旧存储键迁移不丢数据
node src/smoke-per-scheme.cjs . # 记录按方案隔离
node src/smoke-records-switch.cjs . # 记录页文本随方案变化
node src/smoke-switch-live.cjs . # 同一 store 上实时切换方案
node src/smoke-repair.cjs . # 旧统计错放时能被修回
node src/mirror-size.cjs # 镜像体积与隐私体检
node src/smoke-proto.cjs . # 恶意统计数据不污染原型
node src/layout-check.cjs # 记录页三栏布局估算
node src/derive-check.cjs <rime schema 目录> --check
也可以直接 npm test(等价于上面除 derive-check 的全部检查)与 npm run build。
已知限制
- 拿不到输入法按键流;真实输入只能"上屏即提示",无法在按键前预测。
- 「卡顿」是按时长/退格估算的;拼音表外的生僻字只计时间,不更新键位。
- 透明度过低时文字一起变淡(要的就是"看得见但不挡事")。
- 面板宽度 340–860px;更窄的窗口会按屏幕宽度自动限制。
No comments yet. Be the first to write one.