从 "thisisunsafe" 到 ComboKeys.js 组合键功能开发:一个隐藏指令引发的探索
🚀 突然记起的神秘的指令
在一个普通的工作日,我正测试一个新开发的 Web 应用,突然遇到了 Chrome 浏览器的 SSL 证书警告页面。
看着那个红色的"您的连接不是私密连接"警告,我像往常一样准备点击"高级"按钮,却发现没有"继续前往"按钮。
在这时,突然想起之前 twitter 上看到的一个小技巧:thisisunsafe 快速跳过指令。正巧在页面试了试,还真的有效!
🤔 好奇心在作祟
这个发现让我陷入了深深的思考:
- 这是怎么实现的? Chrome 是如何监听键盘输入的?
- 还有其他类似的隐藏指令吗? 比如
badidea用于绕过恶意软件警告 - 这种交互模式有什么特别之处? 为什么不用按钮而用键盘输入?
这可太好办了!开始考古!👀(准备抄作业了)
🔍 不辞辛苦翻找源码

通过查阅 Chromium 的源码,我发现了这个功能的实现原理,并构造了一个简化逻辑来复现:
// 简化版的实现逻辑
class SecurityInterstitial {
constructor() {
this.hiddenText = "";
this.targetPhrases = ["thisisunsafe", "badidea"];
document.addEventListener("keydown", this.handleKeyPress.bind(this));
}
handleKeyPress(event) {
// 只监听字母键,忽略修饰键
if (event.key.length === 1 && /[a-z]/i.test(event.key)) {
this.hiddenText += event.key.toLowerCase();
// 检查是否匹配目标短语
for (const phrase of this.targetPhrases) {
if (this.hiddenText.endsWith(phrase)) {
this.bypassWarning();
return;
}
}
// 保持合理的缓冲区长度
if (this.hiddenText.length > 20) {
this.hiddenText = this.hiddenText.slice(-10);
}
}
}
}
不错,这真是一个简单而巧妙的键盘序列检测系统。现在它是我的了!ctrl c ctrl v 启动!
💡 自己手搓一个实现吧
看到这个实现,我的 开发本能(摸鱼本能)被激发了:
"如果我能做一个更好玩又通用的前端组合键库、粘滞键库,岂不是很有趣?"
于是,ComboKeys 项目诞生了!
🛠️ 从想法到实现:ComboKeys 的发布
第一版:简单粗暴
最初的想法很简单,就是模仿 Chrome 的实现:
// 第一版的粗糙实现
class SimpleCombo {
constructor(targetKeys, callback) {
this.target = targetKeys.toLowerCase();
this.buffer = "";
this.callback = callback;
document.addEventListener("keydown", (e) => {
if (e.key.length === 1) {
this.buffer += e.key.toLowerCase();
if (this.buffer.endsWith(this.target)) {
this.callback();
}
}
});
}
}
// 使用示例
new SimpleCombo("hello", () => alert("Hello World!"));
这个版本虽能正常工作,但局限性也很多:
- 只能检测字母序列
- 没有超时机制
- 不支持组合键(Ctrl+C 这种)
- 无法停止监听
- 没有错误处理
第二版:功能升级
经过一番思考,我意识到需要继续开动脑筋 支持更复杂的场景 (填满我剩下的摸鱼时间):
比如,我们可以设计如下调用实现:
// 科乐美秘籍:↑↑↓↓←→←→BA
const konamiCode = new ComboKeys(["ArrowUp", "ArrowUp", "ArrowDown", "ArrowDown", "ArrowLeft", "ArrowRight", "ArrowLeft", "ArrowRight", "KeyB", "KeyA"]);
// Web应用快捷键:Ctrl+S保存
const saveShortcut = new ComboKeys(["ControlLeft", "KeyS"]);
// 隐藏功能激活:输入"admin"
const adminMode = new ComboKeys(["KeyA", "KeyD", "KeyM", "KeyI", "KeyN"]);
这就需要解决几个关键问题:
- 编码统一:键盘事件的
event.code提供了标准的按键标识 - 模式区分:组合键(同时按住)vs 序列键(依次按下)
- 超时处理:序列键需要在合理时间内完成
- 状态管理:跟踪当前匹配进度
于是掐指一算,不如封装一个可以链式设定的类来实现,也方便后续修改扩充更多功能~ 😊
最终版:ComboKeys 2.0
经过多次迭代,最终形成了现在的 ComboKeys 2.0 构造:
// 更合理高效的API链式设置
const combo = new ComboKeys(["KeyH", "KeyE", "KeyL", "KeyL", "KeyO"])
.timeout(2000) // 限定2秒内完成
.onTrigger(() => console.log("Hello!")) // 触发回调
.maxTriggers(3) // 限定最多触发3次
.debug(true) // 允许开启调试输出
.start(); // 开始监听
🎮 实战应用:迷宫逃脱游戏
为了测试 ComboKeys 的最终能力,我抽空也就顺便(其实因为还没摸到下班点儿呢)用AI再写了一个迷宫逃脱的demo游戏:

基础操作
// 移动控制
new ComboKeys(["ArrowUp"]).onTrigger(() => movePlayer(0, -1));
new ComboKeys(["Space"]).onTrigger(() => attack());
隐藏指令
// 调试模式:显示钥匙位置
new ComboKeys(["KeyT", "KeyI", "KeyP", "KeyS"]).onTrigger(() => showKeyLocation());
// 简单模式:显示最佳路径
new ComboKeys(["KeyE", "KeyA", "KeyS", "KeyY"]).onTrigger(() => showBestPath());
更多隐藏指令,不如来看看源码怎么写的吧!😄
🧠 设计哲学:从 Chrome 快捷指令开始
在开发 ComboKeys 的过程中,我从 Chrome 的 thisisunsafe 实现中学到了很多:
1. 用户体验至上
- 无感知输入:不需要焦点,不需要输入框,直接在页面上输入
- 即时反馈:输入完成立即响应,无需额外确认
- 容错设计:输入错误会自动重置,不会卡住
2. 安全性考虑
- 故意隐藏:这些指令不会出现在界面上,避免误触
- 有意设计:
thisisunsafe这个短语明确表达了"我知道这不安全但我要继续" - 适度门槛:需要完整输入,有一定的使用门槛
3. 技术实现的合理改进
- 事件驱动:基于标准的 DOM 事件
- 状态管理:维护简单但有效的状态
- 性能友好:轻量级实现,不影响页面性能
🚀 最终成果:不只是一次摸鱼
ComboKeys 最终不仅仅是一次摸鱼产生的组合键库,它代表了一种发现问题、追究问题、开发问题、收纳问题的思路。
功能特性
- 🎯 直观易用:清晰的 API 设计,方法名语义明确
- ⏱️ 超时控制:可设置按键间的最大时间间隔
- 👂 精确监听:支持指定 DOM 元素监听范围
- 🔄 链式调用:流畅的链式设定方式 API 设计
- 🐛 调试友好:内置调试功能,详细的日志输出
应用场景
- 游戏开发:复杂的按键组合和按键响应系统
- Web 应用:快捷键和隐藏功能、事件处理
- 创意交互:特殊的用户交互体验
- 开发工具:调试和测试功能的快速触发
🎯 经验总结:从模仿到创新
摸鱼过程中一些体会:
1. 好的灵感来源于日常观察
一个简单的浏览器功能,背后可能隐藏着有趣的技术实现。保持好奇心,多问几个“为什么”和“如何实现”,可以常给自己布置支线任务“要不我也来写一个”。
2. 从模仿开始,但不止于造轮子
最初我只是想复现 Chrome 的快捷绕过功能,但在实现过程中迸发出更多的想法与可能性,最终创造出了一些有意思的小玩具。
话不多说放地址:
项目地址: ComboKeys on GitHub
在线演示: 迷宫逃脱游戏
P.S. 还记得那个年少时的无敌指令吗?在迷宫中试试 ↑↑↓↓←→←→BA,然后输入 AUTO 看看效果呗!兄弟萌记得来个Star啊⭐

浙公网安备 33010602011771号