- 本来刚做系统的时候挑好了 finder 的窗口样式, 能保证每次打开都是相同的样式的窗口;
- 但是后续觉得太宽了, 又重新调了一下
- 问题就出现了: 直接打开的样式是我要的, 但是通过其他软件点击"在 finder 中显示"出现的窗口又会变回原来的
- 乱七八糟的,强迫症根本忍不了
- 该试过的办法都试了, 全盘删除
.DS_store、删除~/Library/Preferences/com.apple.finder.plist 都没有作用;
- 直接用 hammerspoon 解决了, 每次打开 finder 强制设置, 舒服了
-- 自定义日志包装方法, 支持传入多个参数
function debugLog(...)
if ENABLE_DEBUG_LOG then
print(...)
end
end
-- 2 、finder 窗口拦截修改宽高脚本
-- 动态获取系统 Finder 的本地化名称 (中文系统下返回 "访达", 英文返回 "Finder")
-- 这样写可以彻底避免硬编码字符串带来的匹配失败问题
-- 动态获取系统中当前正在运行的 Finder 进程对象
local finderApp = hs.application.get("com.apple.finder")
-- 从运行的进程中提取它在当前系统语言下实际显示的名称
-- 如果是中文系统, finderApp:name() 将 100% 准确地返回 "访达"
local finderAppName = finderApp and finderApp:name() or "Finder"
-- 初始化窗口过滤器: 传入 false 表示默认拒绝系统中的所有窗口事件, 节约性能
FinderFilter = hs.window.filter.new(false)
-- 使用 setAppFilter 专门针对 Finder 设定规则:
-- 1. allowRoles = 'AXStandardWindow': 底层直接屏蔽偏好设置, 进度条等非标准面板.
-- 2. 故意不写 visible 参数: 默认为 nil (忽略), 这意味着即使是刚创建还未渲染显示出来的底层窗口也能被捕获.
-- 使用 setAppFilter 专门针对 Finder 设定规则
FinderFilter:setAppFilter(finderAppName, {
allowRoles = 'AXStandardWindow',
rejectTitles = {
-- 精准匹配设置面板
"^" .. finderAppName .. "设置$",
"^" .. finderAppName .. "偏好设置$",
"^" .. finderAppName .. " Settings$",
"^" .. finderAppName .. " Preferences$",
-- 新增: 利用 Lua 模式匹配 (以特定字符串结尾的正则 $ 锚点)
-- 拦截所有标题以 "简介" 或 " Info" 结尾的窗口
"简介$",
" Info$"
}
})
-- 订阅窗口创建事件
FinderFilter:subscribe(hs.window.filter.windowCreated, function(win)
-- 此时能触发该函数的, 必定是 Finder 的标准窗口
debugLog("检测到新建标准窗口:" .. win:title())
-- 安全与类型检查:
-- 1. 确保 win 对象及其底层的窗口 ID 真实存在
-- 2. isStandard() 确保这是一个标准窗口, 而非偏好设置或进度条面板
if win and win:id() and win:isStandard() then
debugLog("确定这是一个标准窗口")
-- 引入 0.05 秒延迟, 等待 macOS 彻底赋予窗口宽高坐标数据
hs.timer.doAfter(0.05, function()
-- 安全校验: 确保句柄存在
if win and win:id() then
debugLog("确定句柄存在")
-- 使用 Hammerspoon 的 hs.osascript 模块向 Finder 发起底层查询
local ok, windowClass = hs.osascript.applescript('tell application "Finder" to get class of front window as string')
-- 严格过滤: 如果底层类名不是 "Finder window", 则绝对不是普通的文件夹浏览窗口, 直接跳过
if not ok or windowClass ~= "Finder window" then
debugLog("非文件浏览窗口, 真实内部类型为:" .. tostring(windowClass) .. "-> 跳过调整")
return
end
debugLog("确认是文件浏览窗口, 准备调整尺寸, 真实内部类型为:" .. tostring(windowClass))
local currentSize = win:size()
local targetW = 803
local targetH = 625
local tolerance = 5
-- 模糊宽高校验
if math.abs(currentSize.w - targetW) <= tolerance and math.abs(currentSize.h - targetH) <= tolerance then
debugLog("窗口尺寸已符合要求, 跳过调整")
return
end
if currentSize.w < targetW and (targetW - currentSize.w) > 300 then
debugLog("当前窗口尺寸很小, 认为不是文件浏览窗口, 跳过调整")
return
end
-- 记录当前动画时间并强制设为 0 (实现无缝缩放)
local defaultAnimationDuration = hs.window.animationDuration
hs.window.animationDuration = 0
debugLog("校验完毕, 开始执行尺寸修改")
win:setSize({ w = targetW, h = targetH })
-- 恢复系统动画时间
hs.window.animationDuration = defaultAnimationDuration
debugLog("窗口尺寸调整完毕")
end
end)
end
end)