使用方法
- 打开页面就能看到一整块 104 键的屏幕键盘,按 US ANSI 布局排布:F 区 16 键、主键区 61 键、编辑区 6 键、方向键 4 键、小键盘 17 键,每颗键帽都带自己的
code值。 - 在浏览器窗口里按下一个键,屏幕上对应的键帽立刻亮蓝,松手熄灭。右侧「本次事件」面板同步刷新出这次按键的
code、key、keyCode、location、repeat与锁定键状态。 - 同时按住多个键不松手,观察「峰值同时按下」这张卡片。它是判断键盘无冲档位的唯一依据,默认阈值 6 来自 USB 引导协议一次最多报告 6 个非修饰键。
- 峰值超过阈值时,下方判定行会给出「大概率 NKRO」的结论。想调严或放松,改「无冲判定阈值」(1~20 的整数,默认 6),在输入框里直接按 Enter 立刻重新判定。
- 事件记录表默认只渲染前 12 条,点「加载更多」展开全部;「复制记录」按 TSV 复制,「导出记录 CSV」下载带 BOM 的文件,粘进 Excel 不会乱码。
- 页面预置的 14 条示例只是排版演示,你第一次按下真实按键时它们会被自动清空;想手动重来点「清空记录并开始实测」。
键盘测试能解决什么问题
一是定位「这个键到底坏没坏」。同一颗键可能被吃掉三次:键盘固件没发、操作系统驱动拦截、浏览器或输入法提前 preventDefault。本工具只看浏览器最终收到的 keydown:按住某颗键屏幕键盘毫无反应而其他键正常,问题基本在驱动或固件层;只有某个网页里没反应,那多半是那个页面自己拦掉了。
二是判断键盘是几键无冲。游戏里「按三个键就有一个失灵」几乎都是 6KRO 或 2KRO 的键位冲突。峰值同时按下数一旦超过 6,就说明键盘实打实地超出了 USB 引导协议上限,走的是 NKRO 报文。
三是查出「卡键」。「当前按下」如果在松手后没回到 0,说明浏览器少收到了一次 keyup。常见诱因是按了系统级组合键、切窗口时松手、或录入途中弹出了输入法候选框,实测中这类漏事件比想象中多。
四是给前端快捷键选对字段。写「WASD 移动」「按 E 交互」必须用 code,否则德语键盘的 Z 会跑到 Y 的位置、法语 AZERTY 上 WASD 直接错位;判断「用户输入了哪个字符」则必须用 key。选错的典型症状是「本地好用、海外用户说方向不对」。
五是区分左右修饰键。ShiftLeft 与 ShiftRight 的 key 都是 "Shift"、keyCode 都是 16,只有 code 和 location 能把它们分开,做游戏键位映射必须处理。
这个键盘测试不做这些事:不测键盘回报率、不测按键延迟(那是反应时间测试的活)、不读固件与型号、不评估手感与噪音。
原理和变量:物理位置、字符与三套编码
这个键盘测试监听两个最基础的事件 keydown 与 keyup,字段定义跟的是 W3C UI Events 规范里的 KeyboardEvent 接口。下面七条是它真正在用的机制。
① code 是物理位置,key 是当前字符。code 按「US 布局下的那颗键」命名,与你的系统键盘布局无关;key 则经过布局表和修饰键换算,是这次按键实际产生的字符。按住 A 键,code 恒为 "KeyA"、key 是 "a";再按住左 Shift 敲同一个键,code 依然是 "KeyA"、key 已变成 "A"。把键盘切成 AZERTY 之后,物理上同一颗键的 code 还是 "KeyA",key 会变成 "q"——这就是「物理位置」与「字符」的分界线。
② 小键盘与主键盘的分歧。小键盘 1 的 code 是 "Numpad1",主键盘 1 的 code 是 "Digit1",但两者的 key 都是 "1";同理 NumpadEnter 与 Enter 的 key 都是 "Enter"。只用 key 时这两组键完全不可分辨。
③ keyCode 已废弃但值仍在。按 UI Events 规范它是 legacy 属性,规范只要求兼容不保证取值。实测规律:A–Z 等于大写字母 ASCII(65~90),数字行 0–9 等于 48~57,小键盘 0–9 等于 96~105,两套编号不重叠。注意小写 a 的 keyCode 也是 65 而不是 97,绝不能拿它反推字符。
④ location 把位置拆成四档。0 是标准位(字母键),1 是左侧(ShiftLeft、ControlLeft、AltLeft、MetaLeft),2 是右侧,3 是小键盘。它是 code 之外唯一能说明「在哪一边」的字段。
⑤ repeat 与系统重复。按住不放时第二个及以后的 keydown 会带 event.repeat === true,且不再产生新的 keyup。节奏由操作系统决定而非浏览器:Windows 的重复延迟分 0~3 四档,约 250 / 500 / 750 / 1000 ms,默认档对应约 500 ms;重复速率分 0~31 档,约合 2.5~30 次/秒,默认约 30 次/秒即每 33 ms 一次。所以本页「不同按键」按 code 去重,「事件总数」按事件累加,长按会让后者飞涨而前者不动。
⑥ preventDefault 抑制默认行为。空格与上下左右方向键默认会滚动页面,Tab 会移动焦点,Firefox 里斜杠会打开「快速查找」、单引号会打开「仅链接快速查找」,Alt 会把焦点抢到菜单栏。不拦的话按一下空格整页就跳走,键盘图根本看不清。本工具对空格、方向键、Tab、F1、F3、F7、斜杠、单引号、退格、翻页键与 Home/End 一律调用 preventDefault()。
⑦ 无冲档位怎么得出的。USB HID 键盘的引导协议报文固定 8 字节:第 0 字节是修饰键位图,第 1 字节保留,第 2~7 字节是 6 个键码槽。也就是标准引导协议一次最多报告 6 个同时按下的非修饰键,这就是 6KRO 的由来;修饰键另走 8 位位图,能表达 2^8 = 256 种组合,不受 6 键限制。要报告更多键就得改用厂商自定义的 NKRO 字段。本页把「峰值同时按下 > 阈值 6」判为「大概率 NKRO」;反过来峰值不超过 6 并不能证明它是 6KRO,也可能只是你还没按够键。
⑧ 什么时候拿不到有效 code。手机与平板的虚拟键盘会把 code 报成空字符串;输入法组字期间事件带 isComposing === true、key 常为 "Process";法语、西班牙语键盘上的重音死键 key 是 "Dead";笔记本的 Fn 键、音量与亮度键由固件直接处理,多数根本不产生 KeyboardEvent,页面自然测不到。
完整示例(数值仅作演示)
页面打开时的默认状态与正文完全咬合:屏幕键盘画出 104 颗键、阈值输入框预填 6、记录表预置 14 条示例事件(涉及 6 个不同 code,峰值同时按下 2 键,所以判定行显示「峰值 2 键 ≤ 阈值 6」)。按这套默认值走一遍:
- 按一下 A 键:面板显示
keydown、code为"KeyA"、key为"a"、keyCode为65、location为 0 标准;松手后多出一条keyup。这就是示例表第 1~2 行。 - 按住左 Shift 再敲同一个键:
code仍为"KeyA",key变"A",keyCode依然是65,location变 1 左(第 3~6 行)。 - 敲主键盘 1 再敲小键盘 1:两条记录
key都是"1",code却是"Digit1"与"Numpad1",keyCode分别是49与97,location分别是 0 与 3 小键盘(第 7~10 行)。 - 把左手五指压在同一排字母键上:峰值会依次爬到 7。7 > 6,判定行随即变成「已超出 USB 引导协议上限,基本可判定走 NKRO 报文」。
- 此时「当前按下」显示 7;逐根手指抬起,数字逐一回落,全部松开后回到 0,说明没有丢
keyup。
把这次实测导成 CSV,前几行形如(列顺序 # / 事件 / code / key / keyCode / location / repeat):
1,keydown,KeyA,a,65,0 标准,false 2,keyup,KeyA,a,65,0 标准,false 3,keydown,ShiftLeft,Shift,16,1 左,false 4,keydown,KeyA,A,65,0 标准,false
输入范围与按键对照表
本页只有一个可填的输入框「无冲判定阈值」,允许 1~20 的整数,默认 6,步长 1。低于 1、高于 20、小数、字母、留空都会被拒绝,并给出指名字段与范围的具体提示,不会静默改成默认值。下面的按键对照表列出 24 组最常见的 code,默认显示 12 行,「加载更多」展开到全部,「复制对照表」可整表按 TSV 粘进表格软件。
| code | key | keyCode | location | 含义 |
|---|---|---|---|---|
| KeyA | a | 65 | 0 标准 | 字母键,code 与字符完全解耦 |
| Digit1 | 1 | 49 | 0 标准 | 主键盘数字,受 Shift 影响 |
| Numpad1 | 1 | 97 | 3 小键盘 | 与 Digit1 的 key 相同、code 不同 |
| NumpadEnter | Enter | 13 | 3 小键盘 | 与 Enter 的 key 相同、code 不同 |
| ShiftLeft | Shift | 16 | 1 左 | 只能靠 code / location 区分左右 |
| ControlLeft | Control | 17 | 1 左 | 修饰键,走报文第 0 字节位图 |
| AltLeft | Alt | 18 | 1 左 | Windows 上默认会抢菜单焦点 |
| MetaLeft | Meta | 91 | 1 左 | Win 键 / macOS 的 Command |
| Space | (空格) | 32 | 0 标准 | 必须 preventDefault,否则滚动 |
| Enter | Enter | 13 | 0 标准 | 与 NumpadEnter 的 keyCode 相同 |
| Tab | Tab | 9 | 0 标准 | 默认移动焦点,本页已拦截 |
| Escape | Escape | 27 | 0 标准 | 不受 Shift 影响,可做复位键 |
看这张表要注意两点。第一,左右修饰键的区别只在 code 与 location:ShiftLeft、ShiftRight 的 key 与 keyCode 完全相同。第二,只有 keyCode 是「不保证」的字段,同一颗物理键在不同浏览器或系统语言下可能给出不同数字,正式项目里可以拿它做兼容兜底,但不该当唯一判据,更不该拿它反推字符。
边界与精度说明
- 只有窗口处于焦点时才能收到事件。切到别的标签页或程序,键不会进来,键盘也不会亮;「当前按下」若在切窗口后停在非零,说明你去别处松手了,本工具在窗口失焦时会主动清空按下集合。
- 在输入框里打字不会触发高亮,这是刻意设计:阈值输入框要能正常输入、选中、删改,所以本页跳过所有
input与textarea上的键盘事件。 - 峰值不超过 6 不等于 6KRO。6 是引导协议保证的上限,不是键盘的能力上限。要确认是否 NKRO 至少要压到 7 键以上;两根手指压同一颗键不会重复计数,因为峰值按
code去重。 - 长按只算一个键。按住 A 十秒,事件总数会因系统重复增加上百条(约每 33 ms 一条),但「不同按键」始终是 1,峰值也不会因重复事件上涨。
- 拦截键是有代价的。被
preventDefault拦下的空格与方向键在本页不会滚动、Tab 不会切焦点。要测「Tab 到底能不能换焦点」,请到空白页面上试。 - 测不到固件层。主控芯片内部丢掉的扫描事件、无线键盘丢包、USB 集线器供电不足导致的重连,都不会体现在浏览器事件里。本工具看到的是「到达浏览器之后」的世界。
- 事件记录最多保留最近 200 条,超出后最早的记录会被丢弃;需要完整留档请在测试结束后立刻导出 CSV 或复制记录。
常见问题
为什么我按 A,显示的是 code = KeyA、key = a,两者为什么要不一样?
因为这两个字段回答的是两个不同问题。code 回答「你按的是哪一颗物理键」,用 US 布局命名、不随系统布局变化;key 回答「这次按键产生了什么字符」,会跟着布局和 Shift 一起变。做游戏方向键、快捷键注册时你要的是前者,做输入内容判断时你要的是后者。
小键盘的 1 和主键盘的 1 为什么 code 不一样?
Numpad1 与 Digit1 是两颗彼此独立的物理键,所以 code 不同;但它们的 key 都是 "1",location 分别是 3 小键盘与 0 标准。银行录入、POS 结算这类场景常要求两个数字键区互不干扰,此时必须用 code 判断。
怎么确认键盘是不是全键无冲?
把「无冲判定阈值」保持默认 6,然后同时按住 7 颗以上字母键不要松手。峰值超过 6 时判定行会给出「大概率 NKRO」;如果按住 8 颗却只显示 6,说明键盘确实走引导协议,多出来的键被丢掉了。这项结果与操作系统无关,只反映键盘与 USB 主机之间的报文能力。
按住一个键不放,为什么事件总数一直在涨?
那是操作系统的按键重复。长按超过重复延迟(Windows 默认约 500 ms)后,系统会按重复速率(默认约 30 次/秒,即每 33 ms 一次)持续发出带 event.repeat === true 的 keydown。这些重复事件只累加「事件总数」,不增加「不同按键」,也不改变峰值。
为什么在这个页面上按空格,页面不往下滚了?
因为本工具对空格调用了 preventDefault()。不拦截的话一次空格会把页面滚走一整屏,键盘图就看不见了。同理被拦下的还有方向键、Tab、F1、F3、F7、斜杠、单引号、退格与翻页键。
我在输入框里打数字,为什么屏幕键盘没有高亮?
这是刻意跳过的:阈值输入框需要正常的输入光标、选区和删除行为,拦下来就没法编辑了。所以本页对所有 input 与 textarea 上的键盘事件直接放行,不做高亮、不计数、不拦截。
左右两个 Shift 能分开吗?
能。它们的 key 都是 "Shift"、keyCode 都是 16,光看这两个字段完全不可分;但 code 是 "ShiftLeft" 与 "ShiftRight",location 是 1 左与 2 右。左侧的 Ctrl、Alt、Meta 同理。
Fn 键、音量键、亮度键为什么按了没反应?
这些键通常由键盘固件直接处理:Fn 在多数键盘上根本不通过 USB 上报,音量与亮度键则以消费类控制设备的形式出现在系统里,而不是标准键盘报文。它们大多不产生带 code 的 KeyboardEvent,所以任何网页都测不到。