paper-key

纸上键 · paper-key

给你的键盘一百种灵魂 · 打字即禅

一个极简的 macOS 机械键盘音效 App — 在任何 App 里敲任何键,都能出真实机械键盘的声音。18 款真实录音 · 23 MB 原生 · 不带 Electron。

release macOS arch license

这是 Mechvibes 在 macOS 上的精神续作 — 同样的音色库,但用 Tauri 2 + Rust 原生重写,零 Electron 开销。


特点


下载 & 安装

1. 下载

Releases 页面,下载最新的 纸上键-v*.dmg(Apple Silicon,macOS 11+)。

2. 拖到应用程序

打开 DMG,把「纸上键」拖到 /Applications/

3. 首次打开:右键 → 打开

⚠️ 本 App 使用 ad-hoc 签名,没经过 Apple 公证。双击会被 Gatekeeper 拦。

正确姿势:在 /Applications/ 里找到「纸上键」,右键 → 打开,弹窗里再点「打开」。之后就可以双击了。

4. 授权输入监控

跟着 App 里的三步引导走:

欢迎解释权限用途点「去开启」(会弹系统授权对话框)

然后在系统设置 → 隐私与安全性 → 输入监控 里打开「纸上键」开关,回到 App,敲键盘 → 出声 🎵。

为什么要这个权限?macOS 对「全局捕获键盘事件」的 App 要求 Input Monitoring(输入监控) 权限,跟截屏录屏同级。 App 只监听「哪个键被按下」这个信号,不读取键的内容,也不联网。

5. 遇到「⚠ 权限失效」?

ad-hoc 签名的代码哈希(CDHash)每次更新都会变,老的权限记录会失效。App 会自动检测并在状态栏提示,点一下会打开修复面板,按步骤把「纸上键」从列表删掉再拖回来即可。

详见 INSTALL.md 的「权限失效怎么办」章节。


适合谁

不适合


常见问题

问题 解决
双击打不开 / 显示「来自身份不明的开发者」 右键 → 打开
按键没声音 看状态栏提示;或点「诊断」看是不是 Input Monitoring 没开
更新后权限失效 点状态栏「⚠ 权限失效」→ 按引导修复
声音太吵 / 太小 App 内音量条可调
想换音色 点任意一张卡片切换,选择会被记住
想加自己的音色 见下面「添加新音色」

更多排错:INSTALL.md


开发

# 1. 拉音色(首次必跑,从 mechvibes 上游克隆 18 款音色包到 src/assets/sounds/)
bash scripts/fetch-sounds.sh

# 2. 装依赖
npm install
rustup target add aarch64-apple-darwin  # M 系列 Mac

# 3. 开发模式
npm run tauri dev -- --target aarch64-apple-darwin

# 4. 一键打包(build + ad-hoc 签名 + 自定义 DMG)
bash scripts/release.sh 0.2.0
# 产物:dist/纸上键-v0.2.0.dmg(约 23 MB,含 /Applications 拖拽符号链接)

目录结构

paper-key/
├── src/                    # 前端(原生 HTML + JS,无框架)
│   ├── index.html          # 18 张音色卡 + 状态栏
│   ├── app.js              # 音色加载 + Web Audio 播放 + Tauri event 桥
│   ├── onboarding.js       # 三步引导 + 权限状态 + 诊断面板
│   ├── onboarding.css
│   ├── style.css           # 宣纸风 UI
│   └── assets/sounds/      # 18 款音色包(fetch-sounds.sh 拉)
├── src-tauri/
│   └── src/lib.rs          # CGEventTap 全局监听 + IOHID 权限 + 诊断命令
├── scripts/
│   ├── fetch-sounds.sh     # 拉音色
│   └── release.sh          # 一键打包
└── INSTALL.md              # 给 beta 用户的安装/排错指南

添加新音色

  1. src/assets/sounds/<id>/config.json + 音频文件(格式见 mechvibes 文档
  2. src/index.html 里复制一张 .card 加上 data-pack="<id>"

技术选型 & 踩过的坑

为什么不用 rdev?

rdev 是 Rust 社区最成熟的跨平台键盘监听库,最初用的就是它。但在 macOS 14+ 上会崩:它的 callback 线程里调 TSMGetInputSourceProperty,触发 dispatch_assert_queue_failSIGTRAP(macOS 14+ 对 queue assertion 收得更紧)。

最终放弃,直接用 core-graphics 的 CGEventTap + ListenOnly mode 自己写,约 150 行 Rust。

为什么走 Input Monitoring 而不是 Accessibility?

历史上 Mac 键盘音效类 App 基本都要「辅助功能(Accessibility)」权限,那个权限太重(可以模拟点击、修改其他 App 的状态),给全局键盘监听有点用力过猛。

macOS 10.15+ 引入了更细粒度的 Input Monitoring 权限,专门管「只读监听键盘事件」这件事。本 App 走这个权限,更符合最小权限原则。

代码里通过 IOHID API(IOHIDCheckAccess / IOHIDRequestAccess)检测和申请,不走 CGEventTap 的 prompt(那个会强制要 Accessibility)。

依赖

用途 作者
桌面 App 框架 Tauri 2 tauri-apps
macOS FFI core-foundation-rs Mozilla / Servo
CGEventTap 绑定 core-graphics Mozilla / Servo
JSON serde dtolnay et al.

致谢

本项目是站在巨人的肩膀上拼起来的。强烈建议先去给下面这些项目点个 Star。

核心 — mechvibes

hainguyents13/mechvibes by Hai Nguyen — 本项目所有 18 款音色包直接来自 mechvibes 仓库config.json 格式(defines 字段、sprite 偏移)也完全沿用。mechvibes 是 Electron 版本,跨平台支持 Windows / macOS / Linux。

如果你不在 Mac 上,或者想要上游的完整生态(键盘音效商店、自定义音色分享等),请直接用 mechvibes。

深度参与

Claude Code(Anthropic 的 CLI 编码工具)深度参与了这个项目的开发 — 从权限模型调研、CGEventTap 排错到 onboarding UI,都是人机协作的产物。


支持项目

纸上键完全免费开源。欢迎:


License

GPL-3.0-or-later — 因为引用了 mechvibes 的音色资产(GPL-3.0),本项目保持一致授权。

这意味着什么