当前位置: 首页 > news >正文

Chrome垂直标签页快捷键设置

用 Hammerspoon 给 Chrome 侧边栏加一个快捷键

Chrome 有个内置的垂直标签页侧边栏(Vertical Tab Sidebar),体验不错,但有一个致命问题:没有键盘快捷键来切换它。每次想收起或展开侧边栏,都得用鼠标去点那个小按钮。

作为一个键盘流用户,这无法忍受。于是我写了一个 Hammerspoon 脚本来解决这个问题。

思路

macOS 有一个 Accessibility API(无障碍 API),可以遍历任何应用的 UI 元素树,找到按钮并模拟点击。Chrome 的侧边栏切换按钮在无障碍树中的标识是"Expand Tabs""Collapse Tabs"

所以核心逻辑很简单:

  1. 通过hs.axuielement.applicationElement()获取 Chrome 的 AX 根元素
  2. 递归遍历窗口的子元素,找到目标按钮
  3. 调用performAction("AXPress")模拟点击

这个方案参考了 ChromeSidebarToggleRaycast 的思路,但把它移植到了 Hammerspoon 上,并增加了鼠标触发的支持。

两种触发方式

脚本提供三个 scheme,通过顶部的SCHEME变量切换:

Scheme触发方式
仅键盘1Cmd+S切换侧边栏
仅鼠标2鼠标悬停屏幕左边缘展开,移出 380px 收起
键盘 + 鼠标3两种都生效(默认)

鼠标触发的原理是每 50ms 轮询一次鼠标位置。当鼠标进入屏幕左边缘 2px 范围内并停留超过 0.15 秒,触发展开;当鼠标移出 380px,触发收起。

关键实现细节

Grace Period 防误触

切换应用时,鼠标位置和按键事件可能被误判。脚本在 Chrome 获得/失去焦点、系统唤醒/休眠时都会设置一个 grace period(宽限期),期间所有触发都被忽略。

看门狗机制

鼠标轮询器偶尔会意外停止。键盘事件处理器中内置了一个看门狗:如果超过 5 秒没有收到鼠标轮询的心跳,自动重建所有服务。

生命周期管理

脚本监听了三个层面的事件:

  • 应用层:Chrome 激活/失焦/启动/退出
  • 系统层:系统休眠/唤醒
  • 初始化层:启动时检测当前是否在 Chrome 中

每个状态转换都会正确地启动或停止对应的监听器,避免资源浪费和误触发。

安装

# 安装 Hammerspoonbrewinstall--caskhammerspoon# 复制脚本cpinit.lua ~/.hammerspoon/init.lua# 授权辅助功能# 系统设置 → 隐私与安全性 → 辅助功能 → 添加 Hammerspoon

然后在 Hammerspoon 菜单栏图标点击 “Reload Config” 即可。

自定义快捷键

默认快捷键是Cmd+S。改这里就行:

-- Cmd+S -> toggle sidebarifflags.cmdandnotflags.ctrlandnotflags.altandnotflags.shiftandkeyCode==keycodes.map["s"]then

比如改成Ctrl+Shift+B

ifflags.ctrlandnotflags.cmdandflags.shiftandnotflags.altandkeyCode==keycodes.map["b"]then

调试

三个调试快捷键:

  • Cmd+Alt+D:显示服务状态(scheme、监听器运行状态、事件计数)
  • Cmd+Alt+B:dump Chrome 所有 AX 按钮到 Console
  • Cmd+Alt+R:强制重启所有服务

文件结构

项目只有两个 Lua 文件:

  • init.lua— 完整版,支持三种 scheme
  • init-keyboard-only.lua— 纯键盘版,没有鼠标检测,代码更简洁

如果你不需要鼠标边缘触发,用 keyboard-only 版本就好,少了一半代码,也少了轮询的开销。

写在最后

这个脚本解决了一个很小但很烦的问题。Hammerspoon + Accessibility API 的组合在 macOS 上非常强大,几乎可以给任何应用的任何 UI 元素绑定快捷键。

项目地址:Chrome-Vertical-Tab-Sidebar-Toggle

http://www.jsqmd.com/news/812946/

相关文章:

  • 技术人的职业倦怠:当你对代码失去热情时该怎么办?
  • 字节面试灵魂拷问:2-3个if else,用策略模式真的多余吗?
  • BG3模组管理器版本兼容性终极指南:告别游戏崩溃和模组失效
  • 软考高项备考重点考点23:组织通用管理
  • IC卡水表哪家好?2026智能水表厂家推荐:IC卡水表厂家+靠谱的预付费水表厂家+智能水表定制厂家推荐 - 栗子测评
  • AI智能体开发实战:从AwesomeClaw看开源框架与工具集成
  • 智能工厂能源监测管理平台解决方案
  • GenAIScript:用代码思维重构提示工程,实现AI应用工程化
  • 为什么现在请月嫂的人越来越多?
  • 碧蓝航线Live2D提取终极实战指南:从游戏资源到可编辑模型的完整流程
  • CentOS 7.9 Bind 主从 DNS 服务器-主从复制原理【20260513】003篇
  • 百战RHCE(第三十五战:Linux存储管理-LVM实战扩容与收缩)
  • 2026VOC废气处理设备厂家合集:玻璃烟气处理厂家+焦化烟气处理厂家盘点,附致远环境测评 - 栗子测评
  • Agent不再依赖API,而是“像人一样点击拖拽”:5个已商用的RPA+LLM融合架构,含源码级Hook注入细节
  • ComfyUI VLM Nodes:视觉语言模型集成与多模态AI工作流实战
  • 如何为Acode代码编辑器实现5种高效开发工作流
  • 基于Helm的picoclaw AI网关在Kubernetes中的部署与运维实践
  • 企业级Atlassian产品许可证管理解决方案:揭秘Atlassian Agent核心技术架构 [特殊字符]
  • 全网常见网络攻击大盘点:从溯源排查到防御落地全教程
  • 硬件工程师华强北采购实战:供应链生态、风险鉴别与避坑指南
  • iPhone数据迁移全攻略:从iCloud备份到5G换机避坑指南
  • MVP 模式在 Android 测试应用中的实践:以 Activity 与 Presenter 解耦为例
  • 开源大语言模型Baichuan-7B:从架构解析到微调部署全流程实践
  • Python工程实战进阶:从语法到高效编程的核心技巧与避坑指南
  • RPG Maker Decrypter终极指南:快速解密RPG游戏资源
  • FlowLens MCP Server:让AI透视浏览器操作,革新Web调试与测试
  • 开源项目健康度监控:基于GitHub API的轻量级仪表盘设计与实现
  • R语言新手避坑:解决Hmisc包因R版本过低导致的连环依赖报错(附R版本升级与RStudio链接指南)
  • VS Code本地代码评审插件:AI协作与团队异步Review的轻量解决方案
  • 如何快速掌握QQ音乐解析工具:新手完整入门指南