Mac 双显示器鼠标切换 Hammerspoon 配置
要解决什么问题
外接一块显示器之后,最消耗精力的操作是把鼠标从一块屏拖到另一块。屏幕尺寸大、两屏拼在一起横向距离将近一米,鼠标要划过整个屏幕宽度才过去,中途还容易在屏幕边缘卡住(两块屏的可用区域没完全对齐时,边界上有一段是过不去的)。
窗口挪动同理。把一个窗口从主屏搬到副屏,得按住标题栏一路拖过去,松手位置还不一定合适。macOS 自带的窗口管理只有全屏和左右分屏,跨屏移动没有快捷键。
Hammerspoon 能补上这块。它是 macOS 的自动化工具,用 Lua 脚本调用系统 API,屏幕、窗口、鼠标位置都能直接读写,几行代码就能实现「一个键把鼠标传送到另一块屏」。
配置步骤
1、下载 Hammerspoon https://download.csdn.net/download/weixin_40013817/88462061
也可以用 Homebrew 装:brew install --cask hammerspoon,或者去官网下最新版。
2、在【安全性与隐私】->【辅助功能】中开启控制权限
这一步不能跳过。Hammerspoon 要控制其他应用的窗口、移动鼠标,属于系统敏感操作,必须显式授权。没授权的话脚本能加载、快捷键能注册,但按下去没有任何反应也不报错——这是最容易卡住的地方,配置写对了却不生效,八成是权限没给。
新系统上路径是「系统设置 → 隐私与安全性 → 辅助功能」,把 Hammerspoon 的开关打开。如果之前授权过又重装了应用,需要先移除再重新添加,否则系统认的还是旧的签名。
3、在任务栏点击图标,选择 Open Config,也就是打开 /Users/gld/.hammerspoon/init.lua,填写以下代码并保存
配置文件路径是 ~/.hammerspoon/init.lua,上面那个 gld 是原作者的用户名,换成自己的。文件不存在的话点 Open Config 会自动创建。
-- 使用【command+esc】在不同屏幕之间移动鼠标
hs.hotkey.bind({'command'}, 'escape', function()
local screen = hs.mouse.getCurrentScreen()
local nextScreen = screen:next()
local rect = nextScreen:fullFrame()
local center = hs.geometry.rectMidPoint(rect)
hs.mouse.absolutePosition(center)
end)
-- 使用【Option+`】在不同屏幕之间移动窗口
hs.hotkey.bind({'option'}, '`', function()
-- get the focused window
local win = hs.window.focusedWindow()
-- get the screen where the focused window is displayed, a.k.a. current screen
local screen = win:screen()
-- compute the unitRect of the focused window relative to the current screen
-- and move the window to the next screen setting the same unitRect
win:move(win:frame():toUnitRect(screen:frame()), screen:next(), true, 0)
end)
4、在任务栏点击图标,选择 Reload Config,重载配置,使配置生效
代码在做什么
鼠标切换这段的逻辑很直接:hs.mouse.getCurrentScreen() 判断鼠标现在在哪块屏,screen:next() 取下一块(多屏时循环,两屏就是来回切),fullFrame() 拿到那块屏的矩形范围,hs.geometry.rectMidPoint 算中心点,hs.mouse.absolutePosition 把鼠标直接放过去。没有移动过程,是瞬移。
用 fullFrame() 而不是 frame() 是有讲究的:frame() 排除了菜单栏和 Dock 占的区域,fullFrame() 是屏幕的完整物理范围。算中心点用完整范围更符合直觉,落点就在屏幕正中间。
窗口切换这段的关键是 toUnitRect。它把窗口的绝对坐标换算成相对于所在屏幕的比例值——比如窗口占据屏幕左半边,就表示成 (0, 0, 0.5, 1)。然后用这组比例在新屏幕上重新定位,所以两块屏分辨率不一样也没问题,窗口在原屏占多大比例,到新屏还是占多大比例。如果直接搬绝对坐标,从 4K 屏挪到 1080p 屏窗口就会超出边界。
win:move(unitRect, screen, ensureInScreenBounds, duration) 的后两个参数:true 表示确保窗口落在屏幕可见范围内,0 是动画时长,设 0 是瞬间完成——加动画看着好看但有延迟,高频操作时反而累。
实用调整
键位可以按自己习惯改。command + escape 我用着还行,但左手要伸一下,改成 option + tab 之类更顺手的也可以。选键位的原则是避开系统占用的组合,option 加符号键(`、,、.)比较安全。
如果想让鼠标切过去之后落在屏幕的固定位置而不是中央(比如常用的窗口位置),把 rectMidPoint(rect) 换成手动算的坐标即可,hs.geometry.point(x, y) 接受绝对坐标。
多于两块屏的话 screen:next() 会按系统的屏幕顺序循环,想直接跳到指定屏幕用 hs.screen.find() 按名称查找。
改完配置一定要 Reload Config,Lua 文件保存了但不重载是不生效的。想省这一步可以在配置里加个文件监听,改动自动重载,Hammerspoon 官方文档里有现成的写法。
调试时打开菜单栏图标里的 Console,脚本报错会打印在那里。写 Lua 容易出低级语法错误(漏 end、变量名打错),Console 是唯一的排查入口。

还没有留言,来发表第一条吧~