DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

wengyingjian /

wengyingjian/dsh-push-to-talk

Verified

按住一个键说话、松开自动转写(push-to-talk):驱动 DSH 官方语音输入插件的麦克风,按住键可在插件设置页里按平台选。Hold a key to dictate, release to transcribe.

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@f8fdb643

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 的 settings RPC 读写 holdKey(先 describe 取最新 revision 再 mutate,冲突重试),并在插件页注册选择卡片;
    • 不联网、不读麦克风、不写文件,唯一的状态是「这一次按住到哪一步了」。

依赖

  • DSH Desktop 0.2.1 及以上(用到了 plugins.bundle.config slot 与 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

—/ 5

No ratings yet

Verified DSH bundle

Commit f8fdb64361e6

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout