以 Lua 腳本自動化 macOS 操作,此處用於視窗管理快捷鍵。取代原本的 BetterTouchTool。
為什麼從 BetterTouchTool 換過來
| BetterTouchTool | Hammerspoon | |
|---|---|---|
| 授權 | 只涵蓋兩年,過期需重購或降版 | MIT 開源,無授權問題 |
| 廣告 | 有 | 無 |
| 設定 | 二進位匯出檔,不易版控 | 純文字 init.lua,直接進 Git |
| 開機自啟 | GUI 勾選 | 寫在設定檔內,換機即生效 |
原 BetterTouchTool 筆記保留於
backup/07-bettertouchtool.md。
安裝步驟
- 官網 - https://www.hammerspoon.org/
- 安裝:
brew install --cask hammerspoon - 開啟 Hammerspoon(首次啟動會要求輔助使用權限,見下節)
授權輔助使用權限
- 開啟系統設定(
option + F10)❯ 隱私權與安全性 ❯ 輔助使用 - 找到 Hammerspoon - 打開開關
- 也可用指令直接開啟該頁:
open "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility"
❗️ 沒有此權限,快捷鍵按下去不會有任何反應(不會報錯,只是沒動作)。任何能操作視窗的工具都需要它。
設定檔
設定檔版控於本專案,~/.hammerspoon/init.lua 以 symlink 指向它:
mkdir -p ~/.hammerspoon
ln -sfn ~/Workspace/00_MacOS/02-setup/hammerspoon/init.lua ~/.hammerspoon/init.lua- 設定檔位置 -
hammerspoon/init.lua - 修改後自動重新載入 -
hs.pathwatcher監看的是專案目錄,不是~/.hammerspoon/(symlink 的變更偵測不到) - 開機自動啟動 - 由設定檔內的
hs.autoLaunch(true)處理,不必去 GUI 勾選 require("hs.ipc")- 讓終端機的hs指令能與 Hammerspoon 通訊,用於驗證與除錯
快捷鍵
| 快捷鍵 | 功能 |
|---|---|
command + option + ↑ | 將目前視窗移到下一個螢幕並填滿;只有一個螢幕時,原地填滿 |
實作重點
- 不需要條件判斷 -
hs.screen:next()是封閉循環(A→B→A),單螢幕時回傳自己,自動退化為原地最大化 - 不用
maximize()-screen:frame()已扣除選單列與 Dock,直接setFrame()即可 - 綠燈全螢幕要先退出 - 全螢幕視窗自成一個 Space,無法跨螢幕移動,故先
setFullScreen(false)再延遲重試 - 關閉動畫 -
hs.window.animationDuration = 0,避免動畫與setFrame的時序競爭
Finder 的快捷鍵衝突
command + option + ↑ 在 Finder 原本是「前往上層資料夾並關閉目前視窗」,會被本設定蓋掉。
但單純的「前往上層資料夾」是 command + ↑,不受影響,代價很小,因此不做讓行 - 讓此快捷鍵在所有 app 中行為一致。
若日後想讓 Finder 保留原行為,可用
hs.application.watcher在切換到 Finder 時hotkey:disable(),離開時enable()。此法已驗證可行(切到 Finder 時getHotkeys()會歸零),僅因代價不划算而未採用。
驗證
hs -c "print(hs.accessibilityState())" # 輔助使用權限,應為 true
hs -c "print(hs.autoLaunch())" # 開機自啟,應為 true
hs -c "print(#hs.hotkey.getHotkeys())" # 已註冊的快捷鍵數,應為 1列出所有螢幕與其可用區(可用區已扣掉選單列,故高度會比實際解析度少):
hs -c "for i,s in ipairs(hs.screen.allScreens()) do local f=s:frame(); print(i, s:name(), f.w..'x'..f.h, f.x..','..f.y) end"踩雷
- 有些視窗的尺寸是固定的 - macOS 的「系統設定」(Ventura 後的 SwiftUI 版)寬度鎖死不可調整,套用後只有高度會變。這不是設定的問題,驗證時要換一個可自由縮放的視窗
hs.eventtap.keyStroke無法觸發自己註冊的快捷鍵 - 模擬按鍵測不出來,驗證要用實體按鍵hs.reload()期間 IPC 會短暫斷線 -hs指令 timeout 屬正常,稍候再試;若持續無回應則重啟 Hammerspoon- 首次啟動時
hs指令不通 -require("hs.ipc")是後來才加進設定檔的,需重啟 Hammerspoon 一次才會生效 - 部分 app 跨螢幕移動後視窗會消失 - 實測時 Docker Desktop 的視窗在移到另一螢幕並填滿後不見了(daemon 與容器不受影響,從選單列圖示可重開)。僅觀察到一次,未重現驗證
相關參考
- 官方文件 - https://www.hammerspoon.org/docs/
- API 索引 - https://www.hammerspoon.org/docs/index.html
- 入門教學 - https://www.hammerspoon.org/go/
- 原 BetterTouchTool 筆記 -
backup/07-bettertouchtool.md