如何让chrome变成arc风格

news/2025/11/8 12:33:09/文章来源:https://www.cnblogs.com/zetazero/p/19202031

macOS 终极折腾:将 Chrome 暴力改造为 Arc 浏览器

如何让Chrome浏览器变成Arc浏览器风格

声明:本项目仅适用于 macOS 环境,依赖 Hammerspoon 自动化脚本。

Arc 浏览器的更新步伐已经放缓,与其等待施舍,不如自己动手。本文旨在通过“扩展组合 + 自动化脚本”的方式,在 Chrome 上复刻 Arc 的核心交互体验。

核心目标功能矩阵:

  1. 动态侧边栏:鼠标滑向屏幕左侧边缘时自动唤出/隐藏标签栏(基于 Vertical Tabs + Hammerspoon 边缘监听)。
  2. MRU 标签切换:使用 Control+Tab 在最近使用的两个标签页间快速跳转(基于 QuicKey 实现了 Chrome 原生缺失的 MRU - Most Recently Used 功能)。
  3. 极简新标签页:摒弃冗余元素,还原纯净的新标签页体验。
  4. 自动化标签组:基于域名的自动分组管理(利用 Tabee 的正则匹配规则)。

0x01 技术栈准备 (Tech Stack)

要实现这一套“伪 Arc”体验,我们需要以下组件协同工作:

浏览器扩展 (Extensions)

  1. Vertical Tabs

    • 作用:提供垂直标签栏 UI,是视觉复刻的核心。
    • Vertical Tabs
  2. Tabee: Tab Modifier

    • 作用:强大的标签页管理工具,用于实现自动化的标签分组规则。
    • Tabee
  3. QuicKey - The quick tab

    • 作用:接管标签切换逻辑,实现类似 IDE 的 MRU (最近使用) 切换体验。
    • QuicKey
  4. New Tab (或其他类似极简插件)

    • 作用:覆盖 Chrome 默认臃肿的 NTP (New Tab Page)。
    • New Tab

自动化引擎

  • Hammerspoon: macOS 上的自动化神器,我们将用它来桥接鼠标事件和键盘映射。
    • 官方下载: hammerspoon.org

0x02 核心配置 (Configuration)

前置条件:为了获得最佳沉浸体验,建议在“全屏幕 (Full Screen)”模式下使用浏览器。
在这里插入图片描述

Phase 1: 扩展快捷键映射

我们需要将扩展的功能暴露给系统级的快捷键,以便 Hammerspoon 调用。

1. 配置 Vertical Tabs 侧边栏热键

我们需要一个“触发器”来开关侧边栏。这里我们将其绑定为 Cmd+S

  • 进入 Chrome 扩展程序管理页面 (chrome://extensions/shortcuts)。
  • 找到 Vertical Tabs,设置“切换侧边栏”的快捷键。
image-20251107213526941 image-20251107213502217
  • Vertical Tabs 内部推荐配置(兼顾美观与功能):
    在这里插入图片描述

2. 配置 MRU 切换热键 (QuicKey)

Arc 的精髓之一是 Ctrl+Tab 在两个最近页面间横跳。Chrome 默认是线性切换,我们利用 QuicKey 修正它。

  • 将 QuicKey 的 "Switch to the previous tab" 快捷键设置为 Control+Q
  • (注:稍后我们将用 Hammerspoon 拦截 Control+Tab 并重定向为 Control+Q)
image-20251107213627334

Phase 2: 注入 Hammerspoon 脚本

这是灵魂所在。我们将通过 Lua 脚本实现两个核心逻辑:

  1. Key Remap: 拦截 Ctrl+Tab,发送 Ctrl+Q
  2. Mouse Watcher: 监听鼠标位置,当光标停留在屏幕左边缘(< 2px)时,自动发送 Cmd+S 唤出侧边栏;离开特定区域(> 380px)时自动关闭。

部署步骤:

  1. 点击菜单栏 Hammerspoon 图标 -> Open Config
    image-20251107220414955

  2. 粘贴以下经过调试的 init.lua 脚本(v29.1 最终版):

-- ⚙️ Hammerspoon 合并脚本 (v29.1 - "逻辑确认" 最终版)
-- 1. Google Chrome: Ctrl+Tab → Ctrl+Q
-- 2. Google Chrome: 左边缘悬停 → Cmd+S
-- 3. Google Chrome: 离开左边缘 > 380px → 再次 Cmd+S
-- 4. 增强的自动恢复机制 (eventtap 监控 timer)-- ----------------------------------------------------------
-- 🧩 模块加载
-- ----------------------------------------------------------
local eventtap = hs.eventtap
local keycodes = hs.keycodes
local appWatcher = hs.application.watcher
local caffeinate = hs.caffeinate
local timer = hs.timer
local mouse = hs.mouse
local app = hs.application
local screen = hs.screen
local alert = hs.alert
local console = hs.console-- ----------------------------------------------------------
-- 🧩 全局配置
-- ----------------------------------------------------------
local APP_NAME = "Google Chrome"
local keyTap = nil
local mousePoller = nil
local totalEventCount = 0
_G.inSwitchingGracePeriod = false
_G.mouseLastHeartbeat = timer.secondsSinceEpoch()
local DEBUG = true-- ----------------------------------------------------------
-- 🧩 v29: 核心函数 - 提前声明
-- ----------------------------------------------------------
-- 必须提前声明所有互相调用的函数
local log, areServicesRunning, startServices, stopServices, restartServices
local createKeyTap, createMousePoller, resetEdgeState, triggerSave
local mousePollCallback, setGracePeriod-- ----------------------------------------------------------
-- 🧩 v29: 核心函数 - 定义
-- ----------------------------------------------------------log = function(message)if DEBUG thenprint("[HS Debug] " .. message)end
endareServicesRunning = function()local keyTapRunning = keyTap and keyTap:isEnabled()local mousePollerRunning = mousePoller and mousePoller:isRunning()return keyTapRunning, mousePollerRunning
endstartServices = function()local keyTapRunning, mousePollerRunning = areServicesRunning()if not keyTapRunning thencreateKeyTap()if keyTap thenkeyTap:start()log("KeyTap service started")endendif not mousePollerRunning thencreateMousePoller()if mousePoller thenmousePoller:start()log("MousePoller service started")endend
endstopServices = function()if keyTap and keyTap:isEnabled() then keyTap:stop() log("KeyTap service stopped")endif mousePoller and mousePoller:isRunning() then mousePoller:stop() log("MousePoller service stopped")endif resetEdgeState thenresetEdgeState()end
endrestartServices = function()log("Restarting all services...")stopServices()timer.doAfter(0.5, function()startServices()log("Services restarted")_G.mouseLastHeartbeat = timer.secondsSinceEpoch()end)
end-- ----------------------------------------------------------
-- 🧩 脚本 1: Ctrl+Tab -> Ctrl+Q (和 v29 看门狗)
-- ----------------------------------------------------------
createKeyTap = function()if keyTap thenkeyTap:stop()keyTap = nilendkeyTap = eventtap.new({eventtap.event.types.keyDown}, function(event)totalEventCount = totalEventCount + 1-- v29: "看门狗" 逻辑local frontApp = app.frontmostApplication()if frontApp and frontApp:name() == APP_NAME and not _G.inSwitchingGracePeriod thenlocal now = timer.secondsSinceEpoch()if (now - _G.mouseLastHeartbeat) > 5 thenlog("[Watchdog v29] keyTap detected mousePoller is DEAD. Rebuilding...")restartServices()endendif not frontApp or frontApp:name() ~= APP_NAME or _G.inSwitchingGracePeriod thenreturn falseendlocal flags = event:getFlags()local keyCode = event:getKeyCode()if flags.ctrl and not flags.cmd and not flags.alt and not flags.shift and keyCode == keycodes.map["tab"] thenlog("Ctrl+Tab detected, sending Ctrl+Q")eventtap.keyStroke({"ctrl"}, "q", 0)return trueendreturn falseend)return keyTap
end-- ----------------------------------------------------------
-- 🧩 脚本 2: 左边缘触发保存 (v29 多屏幕修复)
-- ----------------------------------------------------------
local edgeTimer = nil
local isEdgeActive = false
local EDGE_THRESHOLD = 2    
local EXIT_THRESHOLD = 380  -- 【v29.1 修复】: 已按你的要求修改为 380
local WAIT_TIME = 0.15      
local MOUSE_POLL_INTERVAL = 0.05 triggerSave = function()totalEventCount = totalEventCount + 1local frontApp = app.frontmostApplication()if not frontApp or frontApp:name() ~= APP_NAME or _G.inSwitchingGracePeriod thenreturnendlog("Left edge trigger activated, sending Cmd+S")eventtap.keyStroke({"cmd"}, "s", 0)
endresetEdgeState = function()if edgeTimer then edgeTimer:stop() edgeTimer = nil endisEdgeActive = false
endmousePollCallback = function()_G.mouseLastHeartbeat = timer.secondsSinceEpoch()local frontApp = app.frontmostApplication()if not frontApp or frontApp:name() ~= APP_NAME or _G.inSwitchingGracePeriod thenresetEdgeState()returnendlocal pos = mouse.absolutePosition()local currentScreen = mouse.getCurrentScreen()if not currentScreen then return endlocal screenFrame = currentScreen:frame()local relativeX = pos.x - screenFrame.x if relativeX <= EDGE_THRESHOLD and not isEdgeActive then-- 刚进入边缘isEdgeActive = truelog("Mouse entered left edge, waiting for trigger")edgeTimer = timer.doAfter(WAIT_TIME, function()-- 停留时间到,检查是否还在local currentPos = mouse.absolutePosition()local currentScreenNow = mouse.getCurrentScreen()if not currentScreenNow then isEdgeActive = falsereturn endlocal currentRelativeX = currentPos.x - currentScreenNow:frame().xlocal currentApp = app.frontmostApplication()if currentRelativeX <= EDGE_THRESHOLD and currentApp and currentApp:name() == APP_NAME then-- 【触发 1】: 悬停触发triggerSave()elseisEdgeActive = falseendend)elseif isEdgeActive and relativeX >= EXIT_THRESHOLD then-- 【触发 2】: 离开边缘并超过阈值时触发log("Mouse exited left edge zone ( > 380px)")resetEdgeState()triggerSave()end
endcreateMousePoller = function()if mousePoller thenmousePoller:stop()mousePoller = nilendmousePoller = timer.doEvery(MOUSE_POLL_INTERVAL, mousePollCallback)return mousePoller
end-- ----------------------------------------------------------
-- 🧩 统一的控制逻辑
-- ----------------------------------------------------------
-- 宽限期管理
local graceTimer = nil
setGracePeriod = function(seconds)_G.inSwitchingGracePeriod = trueif graceTimer then graceTimer:stop() endgraceTimer = timer.doAfter(seconds, function() _G.inSwitchingGracePeriod = falselog("Grace period ended")end)log("Grace period started: " .. seconds .. "s")
end-- 立即启动服务 (v29: 现在所有函数都已定义)
startServices()-- Chrome 应用监听
appWatcher.new(function(appName, eventType, appObject)if appName ~= APP_NAME then return endif eventType == appWatcher.activated thenlog("Chrome activated")setGracePeriod(1.5)timer.doAfter(0.5, function()startServices()end)elseif eventType == appWatcher.deactivated thenlog("Chrome deactivated")setGracePeriod(1)timer.doAfter(0.3, function()stopServices()end)elseif eventType == appWatcher.launched thenlog("Chrome launched")setGracePeriod(2)elseif eventType == appWatcher.terminated thenlog("Chrome terminated")stopServices()end
end):start()-- 睡眠唤醒时恢复服务
caffeinate.watcher.new(function(event)if event == caffeinate.watcher.systemDidWake thenlog("System woke up")setGracePeriod(3)timer.doAfter(2, function()restartServices()if app.frontmostApplication():name() == APP_NAME thenlog("Woke into Chrome, services restored")endend)elseif event == caffeinate.watcher.systemWillSleep thenlog("System going to sleep")stopServices()end
end):start()-- ----------------------------------------------------------
-- 🧩 启动时初始化
-- ----------------------------------------------------------
timer.doAfter(2, function()local frontApp = app.frontmostApplication()if frontApp and frontApp:name() == APP_NAME thenlog("Initialized in Chrome")startServices()elselog("Initialized (not in Chrome)")endsetGracePeriod(2)
end)-- ----------------------------------------------------------
-- 🧩 调试命令
-- ----------------------------------------------------------
hs.hotkey.bind({"cmd", "alt"}, "D", function()local keyTapRunning, mousePollerRunning = areServicesRunning()local frontApp = app.frontmostApplication()local status = string.format("[Hammerspoon] 服务状态 (v29.1):\n" .."前端应用: %s\n" .."KeyTap: %s\n" .."MousePoller: %s\n" .."事件计数: %d\n" .."宽限期: %s\n" .."心跳: %s (%.1fs ago)",frontApp and frontApp:name() or "None",keyTapRunning and "运行中" or "已停止",mousePollerRunning and "运行中" or "已停止",totalEventCount,_G.inSwitchingGracePeriod and "是" or "否",os.date("%H:%M:%S", _G.mouseLastHeartbeat),timer.secondsSinceEpoch() - _G.mouseLastHeartbeat)alert.show(status, 5)log("状态检查: " .. status:gsub("\n", ", "))
end)hs.hotkey.bind({"cmd", "alt"}, "R", function()alert.show("强制重启所有服务...", 2)restartServices()
end)log("Hammerspoon Chrome 快捷键服务已加载 (v29.1)")
  1. 重载配置:Reload Config,让脚本生效。
    image-20251107220455516

0x03 进阶:Tabee 自动化分组

Tabee 不仅仅是一个标签管理器,它的强大之处在于“规则”。建议自行探索其 Rules 功能,实现类似 Arc 的自动归档体验。

  • Geek Tip: 你可以设置正则匹配规则,例如将所有 .*github\.com.* 的页面自动合并到一个名为 "Dev" 的标签组中,保持工作区的井然有序。

Happy Hacking! Enjoy your "Arc-ified" Chrome.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/959655.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2025年可靠的机械修复冷焊机厂家推荐及采购参考

2025年可靠的机械修复冷焊机厂家推荐及采购参考 在工业制造和设备维护领域,冷焊机作为一种高效、低热影响的焊接设备,广泛应用于模具修复、精密零件焊接等领域。随着技术的进步,市场对冷焊机的性能、稳定性和售后服…

2025年口碑好的北京悬挂式母线槽厂家最新权威实力榜

2025年口碑好的北京悬挂式母线槽厂家最新权威实力榜 随着城市化进程加快和电力需求持续增长,母线槽作为高效、安全的电力传输设备,在建筑、工业、数据中心等领域的应用日益广泛。北京作为全国电力设备产业的重要基地…

2025年专业的医养家具厂家最新TOP排行榜

2025年专业的医养家具厂家最新TOP排行榜 随着人口老龄化趋势加剧,医养家具市场需求持续增长。专业的医养家具不仅需要满足功能性需求,还需兼顾安全性、舒适性和环保性。2025年,哪些医养家具厂家在行业中脱颖而出?…

2025年口碑好的五星酒店家具厂家推荐及选购参考榜

2025年口碑好的五星酒店家具厂家推荐及选购参考榜 在五星级酒店的设计与运营中,家具的品质直接影响客户体验和酒店整体形象。优质的酒店家具不仅需要具备高端的设计感,还需满足耐用性、环保性、舒适性等多重要求。因…

2025年靠谱的屏蔽电缆TOP品牌厂家排行榜

2025年靠谱的屏蔽电缆TOP品牌厂家排行榜 在工业自动化、电力传输、通信网络等领域,屏蔽电缆因其优异的抗干扰性能和信号传输稳定性,成为关键基础设施的重要组成部分。随着2025年智能制造和新能源产业的快速发展,市…

2025年靠谱的宿舍铁床款式高评价厂家推荐榜

2025年靠谱的宿舍铁床款式高评价厂家推荐榜 宿舍铁床作为学生宿舍、企业员工宿舍、公寓等场所的必备家具,其质量、安全性和耐用性至关重要。2025年,市场上涌现出众多宿舍铁床生产厂家,但并非所有品牌都能提供高品质…

2025年靠谱的扇形淋浴房配件厂家最新推荐权威榜

2025年靠谱的扇形淋浴房配件厂家最新推荐权威榜 扇形淋浴房凭借其优雅的设计和空间利用率高的特点,成为现代卫浴装修的热门选择。而优质的淋浴房配件则是确保产品耐用性、顺滑度和安全性的关键。为帮助用户快速找到可…

2025年优秀的糙面防渗土工膜行业质量信誉排行榜

2025年优秀的糙面防渗土工膜行业质量信誉排行榜 随着环保工程、水利设施、垃圾填埋场等领域的快速发展,糙面防渗土工膜作为关键防渗材料,其市场需求持续增长。优秀的土工膜企业不仅需要具备先进的生产技术、严格的质…

2025年正规的单栋薄膜温室大棚行业内口碑厂家排行榜

2025年正规的单栋薄膜温室大棚行业内口碑厂家排行榜随着现代农业技术的快速发展,温室大棚已成为现代农业生产中不可或缺的基础设施。单栋薄膜温室大棚因其成本适中、建设周期短、适应性强等特点,在农业生产中占据重要…

2025年优质的特材板式换热器厂家实力及用户口碑排行榜

2025年优质的特材板式换热器厂家实力及用户口碑排行榜在工业制造和化工生产领域,板式换热器作为关键的热交换设备,其性能和质量直接影响生产效率和能源消耗。随着2025年制造业升级的推进,市场对特材板式换热器的需求…

C++ 手写 List 容器实战:从双向链表原理到完整功能落地,附源码与测试验证 - 详解

C++ 手写 List 容器实战:从双向链表原理到完整功能落地,附源码与测试验证 - 详解pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; fon…

2025年热门的蛋鸡养鸡设备厂家实力及用户口碑排行榜

2025年热门的蛋鸡养鸡设备厂家实力及用户口碑排行榜 随着蛋鸡养殖业的快速发展,自动化、智能化的养殖设备成为行业主流。2025年,蛋鸡养殖设备市场竞争激烈,众多厂家凭借技术创新、产品质量和优质服务脱颖而出。本文…

2025年优质的等温正火式网带炉厂家推荐及采购参考

2025年优质的等温正火式网带炉厂家推荐及采购参考 行业概述 等温正火式网带炉作为热处理行业的关键设备,广泛应用于金属加工、汽车零部件、航空航天等领域。其通过精确控温与均匀加热,显著提升材料的机械性能和加工…

2025年口碑好的电缆桥架厂家最新推荐排行榜

2025年口碑好的电缆桥架厂家最新推荐排行榜在建筑、工业和基础设施领域,电缆桥架作为电缆敷设的重要支撑系统,其质量直接关系到电力传输的安全性和稳定性。随着2025年建筑行业的持续发展,市场对高品质电缆桥架的需求…

2025年诚信的迷你便携式烟灰缸厂家最新权威推荐排行榜

2025年诚信的迷你便携式烟灰缸厂家最新权威推荐排行榜 随着现代生活节奏的加快,便携式烟灰缸因其小巧实用、环保卫生的特点,逐渐成为烟民日常出行的必备品。无论是车载使用、户外旅行还是商务场合,一款设计精良的迷…

2025年热门的模压TPE颗粒厂家推荐及选择指南

2025年热门的模压TPE颗粒厂家推荐及选择指南 随着汽车、电子、医疗等行业对高性能弹性体材料需求的持续增长,模压TPE颗粒因其优异的可塑性、环保性和耐用性成为市场热门选择。2025年,模压TPE颗粒的应用领域将进一步…

2025年质量好的别墅电梯厂家最新TOP排行榜

2025年质量好的别墅电梯厂家最新TOP排行榜随着人们生活水平的提高和老龄化社会的到来,别墅电梯已成为高端住宅的标配产品。2025年,别墅电梯市场迎来了新一轮的技术革新和品质升级,各大厂商纷纷推出更具智能化、安全…

2025年知名的盐场晒盐池hdpe土工膜批发销售

2025年知名的盐场晒盐池HDPE土工膜批发销售指南 随着盐业生产技术的不断升级,HDPE土工膜因其优异的防渗性能、耐腐蚀性和长寿命,已成为盐场晒盐池建设的核心材料。2025年,市场对高品质HDPE土工膜的需求将持续增长,…

2025年评价高的不锈钢门工程门厂家推荐及选择指南

2025年评价高的不锈钢门工程门厂家推荐及选择指南 不锈钢门因其耐用性、安全性和美观性,成为现代建筑中不可或缺的一部分。无论是家庭入户门、商业场所还是工程项目,选择一家可靠的不锈钢门厂家至关重要。本文根据市…

2025年靠谱的轧辊橡胶辊用户好评厂家排行

2025年靠谱的轧辊橡胶辊用户好评厂家排行行业概述橡胶辊作为工业生产中不可或缺的关键部件,广泛应用于印刷、纺织、包装、塑料等多个行业领域。随着中国制造业的持续升级,对高品质橡胶辊的需求也在不断增长。优秀的橡…