键盘演奏:我写了一个键盘音效引擎

当我写代码戴上降噪耳机的时候, 听不到键盘声,有些不习惯, 于是想找一个按键音的软件, 但不是收费就是占我的内存, 功能也不符合我的需求.

所以------自己写了一个

KeyTone,常驻菜单栏的键盘 / 鼠标音效引擎,MIT 开源。


它能做什么

把每一次敲击和点击变成声音:机械轴的清脆、打字机的咔哒、老式薄膜键盘的闷响。

内置 21 个音色包------19 个是真实录音采样,2 个是运行时用波形合成的。键盘和鼠标各自独立,可以分别切换。

挑几个名字你大概有感觉:Cherry MX 棕 / 蓝 / 黑、Holy Panda、NK Cream、Gateron 红墨 / 黑墨、Alpaca、Logitech G915 TKL、打字机、iOS 键盘。鼠标那边有 G502 X、Corsair M65 Elite、M570 轨迹球、Magic Mouse。

一共 174 个音频文件,全部编译进二进制,首次启动自动装好,不用你手动找素材。


三个我真正在意的细节

一、延迟必须压到感觉不到

这是最容易被做砸的地方。很多实现是"收到事件 → 读文件 → 解码 → 播放",一路下来几十毫秒就出去了,打字快的时候声音会拖在手指后面,非常难受。

KeyTone 的做法是启动时把音频全部预解码进内存,按下时直接推给音频线程。实测从按键到出声在 10ms 级别------比你眨眼快两个数量级。

中间还踩了个坑:rodio 默认按 采样率 / 20 算缓冲(48kHz 下是 2048 帧),但部分声卡实际只接受几百帧的区间,直接开会失败。最后改成按 [480, 960, 256, 240] 逐个降级试,480 帧正好 10ms。

二、同一个键不能永远是同一个声音

真人敲键盘,每一下的力度、角度、时机都不同,所以听起来是"活的"。如果每个键只有一份采样,连打就变成了复读机。

所以每个键位可以绑定多个采样变体,播放时随机挑一个。同时做了峰值归一化------不同音色包的录音电平差异最大能到 10 倍,加载时统一归一到接近满刻度,切包不会出现"这个听不见、那个炸耳朵"。

三、它不该打扰你

这一条听着像产品废话,但落到实现上很具体:

  • 本应用窗口在前台时不发声。 你点自己的界面、在自己的窗口里打字,不该被自己的音效吵到。
  • 关闭窗口是真的销毁 WebView,不是隐藏。常驻内存明显下降------毕竟 99% 的时间它只是躺在菜单栏里。
  • 关窗口只是收进托盘,进程不退出,音效一直在。

一个有点怪但很好用的功能

键位语音播报。

打开之后,每按一个键,系统会用语音把键名念出来。中文模式下 A 念"啊"、B 念"波"------这里做了个小处理:直接把拉丁字母丢给中文语音,它会把 A 读成英文字母名,很出戏,所以用同音汉字把读音锁死。

中文模式还特意区分了鼠标左键 和左箭头键:前者念"左键",后者念"左箭头",不会混。

说实话我一开始觉得这是个玩具功能,直到我开始用它检查键盘------哪个键没触发、哪个键连击,听声音比看日志快多了。打字快的时候它会打断上一句,保证念的永远是你刚按下的那个键。


技术上几个不太显然的点

如果你也是写 macOS 应用的,这几条能帮你省几天:

CGEventTap 的修饰键走 FlagsChanged 事件,没有独立的按下 / 抬起。必须读事件里的 flag 位判断当前状态,否则 Shift 和 Command 会一直被判为"按住不放"。

AXIsProcessTrusted() 永远不会弹授权框。 想弹只能用 AXIsProcessTrustedWithOptions 配 kAXTrustedCheckOptionPrompt。

菜单栏图标会被系统强制缩放到 18pt 高。 你提高 PNG 分辨率不会让它变大,只会变糊。想让图形占满画框,只能收紧 SVG 的 viewBox。

还有一个不算技术但很要命的:打包时如果没签名,辅助功能授权是拿不到的。 TCC 必须把授权绑定到一个稳定的代码签名身份上,.app 包没签名(只有内层可执行文件带链接器的 ad-hoc 签名)时,用户在系统设置里勾了也没用,AXIsProcessTrusted() 永远返回 false。

更麻烦的是 ad-hoc 签名的授权绑在 cdhash 上,每次重新编译都失效。解法是本机造一张自签名证书来签,授权就绑在证书上,只需要勾一次。


现在能用到什么程度

说清楚,免得你装完失望:

平台 状态
macOS 13+ 已实机验证,键盘 / 鼠标 / 语音全部可用
Windows 10+ 已实现并通过编译与单测,还没实机验证
Linux evdev 实现已写,未验证,需要 input 组权限

Windows 那边低级钩子(WH_KEYBOARD_LL + WH_MOUSE_LL)已经接好了,不需要任何授权------这点比 macOS 省事。但语音播报还没做,Windows 要接 SAPI,暂时是隐藏状态。

macOS 安装时 Gatekeeper 会拦一次(没做公证),右键「打开」就行,或者:

sh 复制代码
xattr -dr com.apple.quarantine /Applications/KeyTone.app

然后记得去「系统设置 → 隐私与安全性 → 辅助功能」勾上,否则捕获不到全局按键。


关于开源

MIT,代码在 GitHub 上:github.com/PikachuGits...

技术栈是 Tauri 2 + Rust,前端就是一个单文件静态 HTML,没有框架也没有构建步骤------改完 HTML 直接 cargo build 就能看效果,这点我挺喜欢的。

音色包的命名沿用了这个生态里的通行写法(backspace / enter / leftshift),所以现成的音色包可以原样导入 ,不用改包。想自己做一套也很简单,一个 profile.yaml 加几个音频文件就行。


最后说一句为什么做这个。

不是因为市面上没有同类工具,是因为我想要一个不用配置、装上就响、敲起来像那么回事的东西。它不该是一个需要研究的软件,应该像键盘本身的一部分------你在打字,它在发声,仅此而已。

如果你也总觉得敲键盘少了点声音,可以试试。

相关推荐
清风微拂1 小时前
别再用记事本看日志了:我给程序员做了个大日志查看器
程序员
穆梓兰煊1 小时前
Rust 在 AI 基础设施中的边界:从 WASI Preview 2 到可插拔推理组件
github
Ka1ros1 小时前
可暂停的Agent编排引擎
github
kyriewen2 小时前
别再用防抖做懒加载了:120 张图只加载出 4 张
前端·javascript·程序员
一只爱撸猫的程序猿2 小时前
当任何人都能生成一万行代码:什么变得稀缺
人工智能·后端·程序员
LeoLi6383 小时前
随机应变,不是见招拆招:AI 干 6 倍工时之后,我把它做成了三层降级链路
人工智能·程序员
shiyan6883 小时前
PadNote:把平板笔记接入 AI 与电脑 Agent
github
wflynn3 小时前
GitHub 日榜趋势速报 | 2026-10-26
开源·github
逛逛GitHub4 小时前
在电脑和手机上玩 Switch 游戏?这 5 个GitHub 项目值得看看。
github