🔗 GitHub:github.com/rational-stars/KeyboardLock · 📦 下载(Release):最新 DMG
一个轻量的 macOS 菜单栏工具:锁住电脑,防止别人动手操作。
- 锁定期间键盘、鼠标 / 触控板完全失效:任何 App 都收不到输入
- 解锁流程:按
Esc→ Touch ID 或密码 → 回车 - 提示内容两种写法:直接填文字,或自己写整屏 HTML 页面(懂 HTML 的人可自由发挥)
- 锁定期间屏幕可正常显示,也可整屏纯黑(防偷看,按 Esc 后浮现解锁界面)
- 访客沙箱:只放行你指定的网页,其他 App 与其他网页一律点不动、切不走 —— 把项目交给别人看 / 调试时最合适
- 锁定期间谁动过电脑、动了什么(不含密码输入),解锁后会给出一份操作记录
- 快捷键支持单个按键(如妙控键盘右上角的 Lock 键),且录好后再点保存才生效
- 支持在线更新(自动比对 GitHub Release 最新版本号并提示下载)
cd KeyboardLock
./build.sh # 编译 → 打包 .app → 生成 DMG 与 zip
open dist/KeyboardLock.app想长期用,建议装到「应用程序」文件夹:
./install.sh # 复制到 /Applications 并启动(不会覆盖同名的其他 App)或直接双击 dist/KeyboardLock-1.5.0.dmg,把 App 拖进 Applications。
需要 macOS 13 及以上。只用到系统自带的 Swift 编译器,不需要安装 Xcode。
首次启动时会自动弹出系统授权窗口,两项权限都必须打开:
- 系统设置 ▸ 隐私与安全性 ▸ 辅助功能 → 勾选 KeyboardLock
- 系统设置 ▸ 隐私与安全性 ▸ 输入监控 → 勾选 KeyboardLock
授权后退出并重新打开 App(菜单栏图标变成「打开的锁 🔓」就说明生效了)。权限状态可以在「设置…」页面随时查看和重新检测。
| 操作 | 说明 |
|---|---|
| 菜单栏图标 ▸ 立即锁定 | 手动锁定(默认快捷键 ⌘⌥L,可自定义) |
| 自定义单个按键(如妙控键盘 Lock 键) | 在「设置… ▸ 解锁方式」里点输入框后直接按该键即可(无需修饰键),录好后点「保存」生效 |
锁定后按 Esc 或自定义键 |
弹出解锁界面:优先 Touch ID,不支持则要求输入密码 |
Touch ID 验证 / 输入密码 + 回车 |
解锁成功(Esc 取消;Touch ID 界面下按任意键改用密码) |
| 菜单栏 ▸ 设置… / 检查更新… | 密码、Touch ID、快捷键、提示文案与位置、在线更新等 |
| 关于 KeyboardLock | 显示开源地址、作者、头像 |
锁定状态下的行为:
- 屏幕显示方式可选:正常显示(桌面、窗口、视频照常可见)或黑屏(整屏纯黑,防偷看)
- 顶部「已锁定 · 按 Esc 后解锁」提示在正常显示模式下会显示,2 秒后自动消失;黑屏模式下不显示,按 Esc 后才浮现解锁界面
- 键盘所有按键(含
⌘Tab、⌘Q、⌘空格、强制退出组合键、妙控键盘 Lock 键)全部被拦截 - 鼠标 / 触控板的点击被一张全屏置顶窗口吸收,不会落到任何 App 上
- 有人动键鼠时弹出自定义提示(文字模式)或显示自定义 HTML 页面
- 操作记录只记除密码外的键鼠操作,密码输入不会被记录,只统计尝试次数;解锁后若期间存在其它操作才弹出报告(可一键复制),否则不弹
- 可设置开始记录前的等待时间(立即 / 5 秒 / 自定义秒数),避免把自己锁定瞬间那一下误记进去
- 锁定期间菜单栏的「设置」「退出」被禁用,
⌘Q也无效,必须先解锁 - 默认锁定期间保持屏幕常亮(可在设置里关掉)
适合这个场景:你打开一个项目要让别人看 / 调试,只许他碰这个页面,别的都不许动。
和全屏锁定相反,沙箱是「默认全禁,只放行受控窗口」:
- 受控页面由 App 用独立浏览器配置启动(Chrome / Edge,
--app=或--kiosk),读不到你自己的书签、插件与登录态,解锁后一并关闭,不留痕迹 - 鼠标:只有落在受控窗口内的点击、滚动、拖拽才生效;落在别处一律吞掉,点不动任何东西
- 键盘:走白名单 —— 字符、方向、回车、退格、
⌘C/V/A/X/Z/R、⌘F、缩放、F5 刷新等正常放行(对方能在页面里正常输入和调试);而⌘Tab、⌘Q、⌘空格、调度台、Ctrl+←→、强制退出等一律拦截,跳不出去 - 受控窗口本身没有地址栏和标签栏,对方无法输入别的网址(可再叠加「顶部预留高度」彻底封死顶部区域)
- 越界操作(点白名单外、按被禁的键)会被记进解锁报告,谁偷偷试了什么一目了然
两种窗口形态:
| 形态 | 说明 |
|---|---|
| 单页全屏(kiosk) | 一个网址独占全屏,无地址栏无标签栏,几乎无法跳出。最严格 |
| 多页独立窗口 | 每个网址一个独立窗口(同样无地址栏标签栏),可同时放行多个页面。页面内点链接仍可能跳转,风险略高 |
开启路径:设置… ▸ 锁定范围 ▸ 选「访客沙箱」→ 填网址(一行一个)→ 选窗口形态 → 照常锁定即可。可选项:允许对方用开发者工具(F12 / ⌘⌥I)、把 Esc 交给页面(改由快捷键唤出解锁)。
沙箱是为「防误触 / 防顺手」设计的,不是防恶意:页面内的链接跳转、电源键与强制关机这类物理操作仍无法拦截。要按 URL 严格限制导航,需要再加一个浏览器扩展。
- 锁定范围:全屏锁定(键鼠全禁)或访客沙箱(只放行指定网页,详见上一节)
- 沙箱窗口形态:单页全屏(kiosk)/ 多页独立窗口;允许访问的网址(一行一个);浏览器程序路径(默认 Chrome)
- 沙箱可选:允许开发者工具(
F12/⌘⌥I);把Esc交给页面、改用快捷键唤出解锁 - 解锁密码:只保存
salt + SHA256哈希,不保存明文,支持字母、数字、符号 - 优先 Touch ID:支持指纹的机器按 Esc 直接刷指纹,失败或取消后退回密码;不支持则始终用密码
- 锁定快捷键:可开关;支持组合键或单个按键(如妙控键盘的 Lock 键)。点输入框 → 按下按键(显示录到的键)→ 点「保存」才生效,「恢复默认」直接生效并回到
⌘⌥L - 提示方式:二选一 —— 文字(直接填提示文案,纯文本渲染);或自定义 HTML 页面(整屏渲染你写的 HTML,密码 / Touch ID 解锁界面浮在其上)
- 有人动键鼠时显示提示:可开关,提示文案完全自定义;「测试效果」按钮会按当前提示方式(文字 / HTML 页面 / 黑屏)不锁屏全屏预览当前锁屏画面
- 锁定期间屏幕:正常显示或黑屏(整屏纯黑,防偷看,按 Esc 后浮现解锁界面)
- 提示位置:屏幕中央 / 顶部 / 底部 / 右下角;停留时长:2 / 3 / 5 / 10 秒
- 记录锁定期间的操作:可开关,解锁后弹出报告(无操作则不弹),报告可复制到剪贴板
- 开始记录等待:立即 / 5 秒 / 自定义秒数 —— 锁定后先等待一段时间再开始记录操作
- 在线更新:「检查更新」按钮 + 「启动时自动检查」开关;自动比对 GitHub Release 最新版本号并提示下载
- 锁定期间保持屏幕常亮:防止锁着锁着息屏
- 无操作自动锁定:1 / 5 / 15 / 30 分钟,或关闭
- 登录时自动启动:需要先把 App 放进「应用程序」文件夹
- 还没锁定:菜单栏 ▸ 设置… ▸ 「忘记密码…」→ 重置后重新设置。
- 已经锁死且忘了密码:
- 用另一台设备 SSH 登录,或在终端执行
pkill -9 KeyboardLock; - 然后执行
defaults delete com.xq.KeyboardLock清掉密码哈希; - 重新打开 App 重新设置密码。
- 用另一台设备 SSH 登录,或在终端执行
CGEventTap(HID 层)全局拦截键鼠事件:锁定期间键盘事件直接吞掉,鼠标事件放行但被顶层透明窗口吸收- 密码输入不依赖系统焦点:由事件流直接解析按键字符,所以键盘被"禁用"的同时仍能接收密码
- 每个屏幕一个全屏透明、置顶(
CGShieldingWindowLevel)窗口,屏幕内容照常显示,但点击无法穿透 - 解锁校验支持
LocalAuthentication(Touch ID),失败自动退回密码输入,密码始终是兜底 - 键鼠事件(不含密码输入)写入操作日志(鼠标移动节流 5 秒一条、滚轮 2 秒一条);锁定后有一个「开始记录等待时间」的宽限期,期间不记录;解锁后仅当存在除密码外的操作时才回调弹出报告,并附密码尝试次数
- 密码校验失败会有退避冷却(1 秒起递增),防止暴力试密码
- 在线更新:
GitHubUpdater查询 GitHub Release 最新版本号并与本地比对 - 提示文案渲染:文字模式按纯文本渲染;自定义 HTML 页面模式通过
WKWebView整屏渲染用户编写的 HTML。「测试效果」会创建同等层级的全屏预览窗口,不真正锁屏 - 访客沙箱:
SandboxManager用独立--user-data-dir启动受控 Chrome/Edge 实例(独立 PID,与用户自己的浏览器互不干扰),每 0.4 秒用CGWindowListCopyWindowInfo刷新该 PID 名下的窗口矩形作为「放行白名单」(bounds / PID / App 名无需屏幕录制权限,窗口标题才需要)。事件拦截从「全吞」改为「白名单放行」:鼠标按坐标判定,键盘按键位判定。沙箱下不铺全屏遮罩,只在屏幕上方挂一块ignoresMouseEvents的浮层承载状态与解锁界面,鼠标穿透到受控页面 - 版本号唯一来源是
Sources/AppInfo.swift,build.sh会自动同步进Info.plist和 DMG 文件名
- 签名与权限:「辅助功能 / 输入监控」授权是按代码签名身份记录的。
build.sh会自动挑选本机可用的签名证书并按以下优先级使用:Developer ID Application→Apple Development→ 其它自签代码签名证书。只要每次构建用同一个证书身份,更新替换 App 后就不必重新勾选权限。三者都没有时才回退 ad-hoc(此时更新后需重新授权一次)。 - 没有 Apple 付费证书也能解决:直接跑
./Tools/make-codesign-cert.sh,它会创建一张 20 年有效的自签代码签名证书(含根 CA)并导入钥匙串,再执行./build.sh即可。脚本可重复执行,已存在同名有效身份时会跳过。- 换机器时把
~/.keyboardlock-certs/KeyboardLock-CodeSign.p12拷过去双击导入(导出密码keyboardlock)。 - 想手动操作也可以:打开「钥匙串访问 ▸ 证书助理 ▸ 创建证书」,身份类型选「代码签名」,创建后在证书上右键 ▸ 显示简介 ▸ 信任 ▸ 代码签名 设为「始终信任」。
- 换机器时把
- 自签证书未经过公证,首次运行仍可能需要在「系统设置 ▸ 隐私与安全性」点「仍要打开」(有 Developer ID 后可再用
xcrun notarytool公证) - 访客沙箱的残留风险:页面内的链接跳转无法拦截(
--app模式下点链接会导航;单页 kiosk 模式已大幅缓解);受控窗口被关闭后白名单会变空、输入全部失效,需要重新锁定;电源键、强制关机等物理操作无解 - 进程被
pkill或崩溃时锁会解除(后续可加 launchd 守护 + 锁定状态持久化) - 登录窗口、系统关机界面等系统级安全界面不受本 App 控制
- 在线更新需联网;若为内网或离线环境,检查更新会自动失败(不影响锁定功能)
Sources/
main.swift 入口
AppDelegate.swift 菜单栏、设置窗口、权限引导、关于面板
LockManager.swift 事件拦截引擎、锁屏层、Touch ID、密码校验、提示预览
PasswordStore.swift 密码哈希存储
AppInfo.swift 版本号 / 仓库 / 作者信息唯一来源
GitHubUpdater.swift 在线更新检查(比对 GitHub Release 版本号)
Views.swift 锁屏界面、设置界面、快捷键录制控件、关于界面(SwiftUI)
Resources/Info.plist
Tools/make_icon.swift 图标绘制
Tools/make-codesign-cert.sh 创建自签代码签名证书(消除更新后的权限重授权)
build.sh 编译 → .app → 签名 → DMG/zip
install.sh 安装到「应用程序」(不会覆盖同名第三方 App)
gen_icon.sh 生成 AppIcon.icns