dsh-push-to-talk — 按键语音输入(push-to-talk)
按住一个键(macOS 默认 Option ⌥,Windows 默认 Alt)开始录音,松开自动停止并转写,识别结果落进当前输入框草稿——不用再用鼠标点麦克风。
按住键可以在 设置 → 插件 → 按键语音输入 里改,改完立即生效并记进 profile,重启后仍是你的选择。
本插件不自己录音、不自己识别、不下载第二套模型:它只是把「按住 / 松开」翻译成官方语音输入插件
(@deepseek-ai/dsh-experimental-client-ui-voice-input)的两次点击,因此录音界面、识别模型、语言与
设备设置全部沿用官方那套。
English: hold a key (Option by default) to dictate into the DSH composer and release to transcribe. Recording, recognition and the model stay with the official voice-input plugin; this plugin only bridges keydown/keyup to that plugin's microphone and stop buttons. The hold key is configurable on the plugin page.
用起来是什么样
| 动作 | 底层发生的事 |
|---|---|
| 按住选定键 | 点官方麦克风按钮 → 官方录制栏出现、开始录音 |
| 松开 | 点录制栏里的「停止并识别」→ 转写并插入草稿 |
| 按住期间敲了别的键 | 点「取消」,这次按键照常生效(按住键不会变成第二个修饰键) |
| 上一轮识别失败/为空 | 再按住一次 = 点录制栏里的「重新录音」 |
| 窗口失焦 / 切页 | 取消本次录音(与官方插件自己的行为一致) |
选按住键
插件页里的那张卡片就是选择器,默认 Option ⌥(Windows 上是 Alt),点一下即保存并立刻生效; 「恢复默认」回到默认键。可选键随平台变:
| 平台 | 预设键 |
|---|---|
| macOS | ⌥ Option · ⇧ Shift · ⌃ Ctrl · ⌘ Command · F2 |
| Windows / Linux | Alt · Shift · Ctrl · F2(不出现 macOS 符号,也不放 Win 键) |
macOS 当前按住键 [ Option ⌥ ]
[ ⌥ Option ] [ ⇧ Shift ] [ ⌃ Ctrl ] [ ⌘ Command ] [ F2 ] 恢复默认
Windows/Linux 当前按住键 [ Alt ]
[ Alt ] [ Shift ] [ Ctrl ] [ F2 ] 恢复默认
三条规则:
- 修饰键左右两侧算同一个键:选 Option/Alt 时左右两侧都触发,Shift / Ctrl 同理
(存进设置的是归一后的名字
Alt/Shift/Control/Meta,不是原始的AltLeft/AltRight), 所以同一份 profile 配置在 macOS 和 Windows 上都指向「同一个键」。 - Windows 不放 Win 键:Win 组合被系统优先截获(Win+L 锁屏等),做成按住键不可靠;
Linux 上同理不放 Super。需要的话可以手写 profile patch 填
Meta,卡片上会显示成Win。 - Windows 的 AltGr 不误触发:Ctrl+Alt 合成的 AltGr(打特殊字符用)会被过滤,不会开始录音。
为什么不做「随便按一个键就设成它」?DSH 的配置写入要求客户端带上当前 revision,
configForms 那层在 revision 过期时会直接回 false,界面上就只剩一句「没有保存成功」;
所以这里不走那层,而是通过页面自己的 connection 服务直接发 RPC:
先 settings/describe 取最新 revision,再 settings/mutate;冲突时重试一次,
失败时把 Host 返回的错误码/原文连同通道诊断一起显示在卡片上。
设置值写在 profile patch 的 voice-hotkey 行 config.holdKey 里;字段本身仍是普通字符串,
所以手写 profile patch 时填任意 KeyboardEvent.code 名字也都认(例如 KeyK),只是界面只给常用键。
兜底:写设置失败时,选择仍会记在本页 localStorage(dsh-push-to-talk/holdKey),本次会话照常可用;
浏览器源一换(例如端口变化)就丢,所以真值仍以 profile 里的设置为准。
Windows / Linux 上要注意
- 安装同样走 profile 的
dsh.profile.bundles(link:或npm:都行),装完要重启 DSH; 浏览器半侧的改动刷新页面(⌘R / Ctrl+R)即可。 - 语音识别本身取决于官方语音输入插件:录音、识别模型和语言设置都在
@deepseek-ai/dsh-experimental-voice-input-bundle里,它是否在 Windows 上可用要以那个插件为准; 本插件只负责把「按住 / 松开」翻译成它的两次点击,官方插件不能用的话这里也无法转写。 - Alt 可能被窗口菜单占用:Electron 窗口有菜单栏时,单独按 Alt 可能先被系统拿去激活菜单。
本插件已经在
keydown里preventDefault,但如果你的环境里 Alt 仍然没反应,改成F2或Ctrl。 - 快捷键的判定用
KeyboardEvent.code(物理键位),不受输入法、键盘布局和大小写影响。
它是怎么实现的
两个半侧加起来很薄,没有后台常驻任务:
src/index.js(Host):只声明Config = z.object({ holdKey: z.string().default('Alt').volatile() })。.volatile()让 DSH 的设置表单能在不重载插件的情况下改它,并写回 profile patch——所以选择能跨重启保留 (GUI 每次启动的端口不同,localStorage靠不住)。client.js(浏览器):- 文档级
keydown/keyup(capture 阶段)驱动按键状态机; - 用
document.querySelector找到官方插件的麦克风 / 停止 / 重试按钮并.click(), 官方 DOM 只用稳定的类名后缀与data-voice-activity属性定位,失效时退化为aria-label匹配; - 把
KeyboardEvent.code归一成按住键名字(AltLeft/AltRight→Alt); - 通过 Host 的
settingsRPC 读写holdKey(先 describe 取最新 revision 再 mutate,冲突重试),并在插件页注册选择卡片; - 不联网、不读麦克风、不写文件,唯一的状态是「这一次按住到哪一步了」。
- 文档级
依赖
- DSH Desktop 0.2.1 及以上(用到了
plugins.bundle.configslot 与configForms服务); - 官方语音输入已就位:设置 → 插件里
@deepseek-ai/dsh-experimental-voice-input-bundle已启用, 本地识别模型已准备好(点一次官方麦克风按钮,按提示下载一次即可); - Host 侧依赖
@deepseek-ai/schemastery(在dependencies里,保证任何安装方式都能解析到; 版本与宿主自带的一致,不会分裂 cordis 实例)。
安装
先决条件:官方语音输入插件已启用(@deepseek-ai/dsh-experimental-voice-input-bundle,设置 → 插件里能看到
「语音输入」这一项),并且本地识别模型已经就绪(点一次官方麦克风按钮,按提示下载一次)。
# 从 git 安装(推荐;本包目前只走 GitHub,未发布到 npm)
dsh plugin --profile desktop add github:wengyingjian/dsh-push-to-talk
# 开发时从本地目录安装
dsh plugin --profile desktop add link:/path/to/dsh-push-to-talk
装好后重启 DSH(没有启用 HMR 的 profile 需要重启才会挂上新的插件行)。之后入口在 设置 → 插件 → 按键语音输入。
只改了浏览器半侧(client.js)时不用重启:在页面里按 ⌘R 刷新就会重新加载 Client 插件;
改了 Host 半侧(src/index.js 的 Config 等)才需要重启 DSH。
手工等价做法:把包目录软链到 ~/.dsh/profiles/<profile>/node_modules/dsh-push-to-talk,并在 profile 的
package.json 里登记依赖与 dsh.profile.bundles(本包自带 cordis.patch.yml,组合时会 insert 插件行
voice-hotkey,这一行的 name 要写 dsh-push-to-talk)。
分发状态
- 发现入口是 GitHub topic
dsh-plugin(DSH 官方没有自己的插件市场, topic 就是官方发现面)。仓库已经打了这个 topic,社区目录(如 dsh.works、 dsh.so)会按 topic 自动扫描收录,不需要手动提交。 - 没有发布到 npm:所以
dsh plugin add dsh-push-to-talk这种短名安装暂不可用,请用上面的github:形式。 DSH 内置的 Discover 市场只收 npm 条目,同理暂时搜不到。 - 兼容性声明:
engines.dsh = ">=0.2.1-rc.5 <0.4.0";本版本实际核对于 dsh 0.2.1-rc.5。
边界与已知限制
- 不用先把光标点进输入框:只要当前视图有输入框,按住选定键会自己把焦点交给输入框再开始 (在看记录、点了侧栏按钮时也能直接按住说话)。只有焦点停在别的输入框里(设置页搜索框等)才让出按键。
- 设置页等没有输入框的视图不触发;弹窗、菜单打开时让出按键。
- 键盘事件来自页面本身:DSH 窗口在后台(切到别的 app)时收不到按键。系统级「全局按住说话」需要
宿主半侧调用 Electron
globalShortcut,本插件只做网页层,不涉及。 - 按住时间太短(录音不足)会由官方插件提示「未识别到语音」;此时直接再按住一次即可重录。
- 首次使用会弹系统麦克风授权;授权对话框可能让窗口失焦而取消这一次,授权后第二次按住即正常。
- 官方插件的类名带 CSS Modules 哈希前缀,本插件按类名后缀(
triggerAnchor/_trigger)与data-voice-activity属性定位;若 DSH 升级改了结构,按住键会「没反应」而不是乱点,届时改client.js里的TRIGGER_SELECTORS即可,兜底的aria-label匹配(开始录音/Start recording)也会继续工作。 - 不用官方快捷键服务(
ctx.shortcuts):它只派发keydown、没有keyup,且要求组合必须带修饰键, 表达不了「按住一个键说话」。 - 设置表单写入的是 profile patch 里
voice-hotkey这一行的config.holdKey;如果这一行被更高层 (如命令行--patch)固定成别的值,DSH 会拒绝这次写入,卡片会提示保存失败。
测试
node --test test/hotkey.test.mjs
测试用 test/fake-dom.mjs 里的最小 DOM 桩验证按键状态机、安全边界与设置同步;真实选择器与设置写入
仍需在 DSH 窗口里实测。
文件
| 文件 | 作用 |
|---|---|
src/index.js |
Host 半侧:声明 holdKey 的 Config(设置表单的唯一来源),无其他行为 |
client.js |
浏览器半侧:键盘状态机 + 驱动官方语音输入插件的按钮 + 插件页配置卡片 |
cordis.patch.yml |
bundle patch:把插件行插进 profile 根层 |
locale/{zh,en}.json |
插件在插件列表里的标题与描述 |
test/ |
最小 DOM 桩与用例 |
许可
MIT
No comments yet. Be the first to write one.