有一天在打字的时候我突然想到一件很小的事情我每天敲这么多键盘那我到底更常用的是哪些键这个问题本身其实没什么用但它有一点点“可能和直觉不一样”的感觉。比如我一直觉得自己主要在用字母区但如果真的统计出来会不会空格才是第一或者回车这种事情如果只是靠感觉其实永远不会有答案。但一旦把它变成数据就完全是另一种东西了。想着想着就干脆把这件事做出来了。代码跟软件都已经开源了地址放在最后感兴趣可以去看看它一开始其实只是个脚本最初的想法很简单监听键盘 → 做计数 → 输出结果。按这个思路一个脚本就能搞定甚至都不需要什么界面。但写到一半就发现这种形态不太成立。因为它太容易“断掉”了。只要我关了终端或者哪天忘记开它那一段时间的数据就直接没了。而键盘使用这种行为本来就不是你会刻意去“开始”和“结束”的东西。如果记录本身需要你去记得它就有点违背这个事情的初衷。后来就慢慢变成另一种方向了让它自己待着一直在那儿不需要你管。于是最后的形态就是一个托盘应用。为什么会走到客户端这一步其实我一开始是想避免写客户端的。不是功能做不到而是开发体验的问题。传统 GUI 那一套我不太熟也不太想花时间在那上面。但“监听键盘”这件事本身就决定了它不可能是一个网页。由于边界问题浏览器拿不到这些数据所以要么放弃要么就认真做一个本地应用。后来是因为看到 Wails V3才觉得这件事变得顺手了不少。之前用过 Wails V2它更像是一个“把网站封装成桌面应用”的壳。单窗口、靠前端路由模拟多页面、菜单和托盘能力很弱。而 V3 原生支持了多窗口、系统菜单、托盘、Dock Taskbar 交互之后整个应用终于有了“骨架”从“套壳网页”真正变成了一款原生应用。完美的符合了我的需求。真正麻烦的不是展示而是“你按了什么键”一开始我以为最麻烦的会是热力图这种展示层的东西。结果完全相反。最绕的地方其实是怎么知道用户按了哪个键。监听事件我选择了 robotn/gohook他本身不提供“监听能力”它只是把各平台的系统级输入监听 API 做了一层统一封装。在 Windows 中他封装的是 SetWindowsHookEx在 Mac 中封装的是 Quartz Event Tap因此它可以在系统层面上监听原始输入事件比应用级监听更底层得到按压情况与虚拟键码。问题在于这个“原始事件”不是你直觉里的 A、B、C而是一串虚拟键码。虚拟键码就是操作系统为了方便程序开发给键盘上每个“功能”分配的一个固定的数字编号。它像是按键的身份证号而不是座位号。以 Windows 为例当我们按下键盘上 A 键的那一刻键盘电路只知道按下去的是物理位置第 0x1E 号的键它会把 0x1E 这个扫描码发给电脑。操作系统收到 0x1E 后会根据当前激活的键盘布局比如美式键盘来查表比如查询到这个物理位置对应的是字母 A。于是它把这个位置信号转换成虚拟键码 0x41即 VK_A。基于这套机制我们开发者完全不用关心用户用的是哪种键盘硬件、按键的物理位置在哪。只要在程序里看到 0x41就可以确信用户按下的是 A 键。但问题同样也出现在这里键盘的位置信号传递给系统而系统把他们转换成虚拟码这个过程是系统进行的因此 Windows 跟 Mac 之间并不统一需要额外进行处理。微软官网中有针对 Windows 虚拟键码的说明Virtual-Key Codes而 Mac 则来自 Carbon.framework 中的 Events.h记录在《Inside Mac Volume V》第 V-191 页这件事没有什么优雅解法只能分开处理。最后就是用 Go 的//go:build把不同平台的映射拆开各自维护。逻辑上统一但实现上不强行合并。数据怎么存反而是一个需要控制的点监听拿到了接下来就是存。一想到这个脑子里的第一反应肯定是按一次写一次数据库。但稍微再一琢磨就会明显感觉到问题。键盘输入是一个非常高频的行为如果每次都落盘SQLite 的压力会有点大而且写入冲突也比较频繁。后来就换成了一种更“松一点”的方式先放在内存里攒着到一定数量或者过一段时间再统一写进去。严格来说这会有一点点数据丢失的可能比如程序突然退出但换来的是整体的稳定性和更低的开销。对这种工具来说我更倾向于后者。热力图反而没那么复杂真正开始做展示的时候反而是最顺的一段。键盘布局其实是有现成逻辑的用机械键盘里常说的 Unitu就能很好地描述普通按键是 1u空格是 6.25u一些功能键是 2u、2.75u 这种。把它当成一个网格去排然后再把每个键的使用次数映射成颜色深浅一张热力图就自然出来了。没有太多技巧更多是一个“把东西摆对”的过程。后来补了一点“实时感”最早版本其实只是统计 展示。但用的时候会觉得它有点“太安静了”。所以后面加了一点很轻的反馈比如按键的时候会有一点变化。实现上也不复杂用 Wails 自带的事件机制把后端的事件往前端推Vue 那边监听一下就可以了。这一块写起来反而最像在写前端项目。写到这里反而会有点疑问这东西到底有什么用项目做完之后我其实想过这个问题。它不会帮你提高效率也不会改变你怎么打字。你大概率也不会因为某个键用得特别多就去刻意优化它。但它提供了一种很微妙的东西你可以“看到”自己平时完全不会注意到的行为。有些结果是符合预期的有些会有一点点偏差。这种偏差不大但挺有意思的。更像是一种观察而不是一个工具。Key Heat最后把这个东西整理了一下做成了一个完整的应用叫 ​Key Heat。它会一直待在托盘里做的事情其实很克制只统计每个键被按了多少次不记录具体输入内容没有网络请求数据只在本地。如果你也对这种东西有点好奇可以自己跑一下看看文档点击查看GitHub点击查看