title: 如何管理桌面窗口 date: 2020-12-23 20:49:53 tags: [MacOS,WindowManager,Workflow]
想向同事分享窗口切换的一点心得,不小心写成一篇没什么营养的方法论。虽然主要还是讲窗口切换。
<!--more-->图片未加速
如果你不知道什么是窗口管理,在开启话题之前,不妨先来确认一下窗口管理器和桌面环境的概念。
首先说桌面环境,翻译自 Desktop Environment,它负责为用户提供完整的操作界面,而不仅仅是狭义的“桌面部件”,还包括图标、窗口、工具栏、壁纸等等。
再说窗口管理器,Window Manager,它是上述桌面环境的一部分,关乎图形化应用的窗口的基本操作,主要为如何进行排列和切换。窗口管理器是桌面环境的一部分,甚至可以完全独立于桌面环境,只运行窗口管理器,从而节省硬件资源。它包含以下类型:
不同类型的窗口管理器提供了不同的窗口摆放方式,还提供了各自的窗口切换逻辑,其中“平铺”更倾向于使用键盘操作,如何选择,主要看个人口味。
虽然着重介绍了窗口管理器,但它不是今天的主角,我们应该跳出所有的运行环境,去发现真正的“窗口管理器”其实是使用者自己。
窗口排列是一个答案无足轻重选择题,需要结合显示器的使用习惯作答。如果仅从思路上讲,相比手动排列,自动排列无疑是更好的选择,此时平铺类窗口管理器的优势就体现出来了。
然而,Linux 可以非常轻松地调换窗口管理器,在 MacOS 下可供的选择就不多了。yabai 要求关闭 SIP,提高了安全风险,Amethyst 功能较弱,好在轻量可控。如果放弃一点点平铺的功能性,可以选择 moom 这类辅助布局软件。考虑到本文不是工具推荐,也就不再介绍更多。
对使用小屏幕和习惯全屏的用户而言,绝大多数的使用场景是全屏,则没必要安装辅助工具。
按以下特征对号入座,目的是想让大家思考不同使用习惯之间的异同点。现在你的窗口管理习惯,是否适用于其他的用户呢?
窗口模式:
桌面分布:
它们的区别:
肌肉记忆≈闭眼操作
虽然存在很大的误差,但不难发现,桌面越复杂,操作复杂度的差距就越明显。
两个代表性工具,MacOS Hammerspoon,Linux wmctrl。同事 MacOS 开发较多,因此以 Hammerspoon 为例。
local hyper = {"cmd", "shift"}
-- 示例:打开或切换到浏览器
hs.hotkey.bind(hyper, "C", function()
hs.application.launchOrFocus("/Applications/Google Chrome.app")
end)
-- 示例:打开或切换到终端
hs.hotkey.bind(hyper, "Return", function()
hs.application.launchOrFocus("/Applications/Alacritty.app")
end)
假如一个应用开启了多个窗口,也可以通过窗口标题、序号进行精准切换。
--- 根据标题切换应用窗口
-- @param appTitle 系统 menu bar 左上角的标题
-- @param appName 安装目录的名称或绝对路径
-- @param winTitle 模糊匹配项目名,注意 .()[]+- 等字符需要转义
function launchOrFocusWindow(appTitle, appName, winTitle)
return function()
local app = hs.application(appTitle)
if app == nil then
hs.application.open(appName)
else
local windows = app:allWindows()
for _, win in pairs(windows) do
local found = string.match(win:title(), winTitle)
if found ~= nil then
win:focus()
return
end
end
app:activate()
end
end
end
-- 示例:VSCode 多开窗口的切换,给名为 "my-project" 的项目定制快捷键
hs.hotkey.bind(hyper, "1", launchOrFocusWindow("Code", "Visual Studio Code", "my%-project"))
launchOrFocusWindow 参数有些奇葩,因为 hs.application.get 和 hs.application.open 分别需要 title、path,互不兼容(可能是 bug)。 不过 get 和 open 还同时支持 bundleID,我认为名称对普通用户更友好,但如果你知道怎么获取 bundleID,自然可以用它来统一此处的入参。
利用丰富的 API,你还可以设计更多复杂的功能。
全局快捷键极易引起冲突,譬如某狗输入法(别用)。为了避免这种烦恼,我们可以在 Hammerspoon 设置组合键。
local hyper = {"cmd", "alt", "ctrl"}
可惜,并不是所有人的手都能成长为“八爪鱼”,腱鞘炎了解一下?我们尽可能把多个按键合并,同时注意减少小拇指的使用。
以 MacOS 为例,使用 Karabiner-Elements,将大拇指附近不需要的按键设置为 hyper,配置示例如下
{
"title": "Change option key",
"rules": [
{
"description": "Change right_option to left_option + left_control + left_command if pressed with other keys, to escape if pressed alone.",
"manipulators": [
{
"type": "basic",
"from": {
"key_code": "right_option",
"modifiers": {
"optional": [
"any"
]
}
},
"to": [
{
"key_code": "left_option",
"modifiers": [
"left_control",
"left_command"
]
}
],
"to_if_alone": [
{
"key_code": "escape"
}
]
}
]
}
]
}
按住右 option,等于同时按住了 option+control+command,还可以随手实现轻按一下等于 ESC 的效果。
别忘了,组合键可不止这三个,还可以再从键盘上选几个键,设为 option+control+command+shift 等等,从此再也不用担心自定义的键位不够用了。
排列窗口的方式很大程度取决于个人口味,自由度也非常高。窗口切换的操作具备更强的逻辑性,需要付出一定的成本。两者都可以提高工作效益,值得思考改进。但也必须承认,改进 Workflow 的边际效应明显,希望读完这篇文章的你,宁可什么都不做,也不要反复抉择。
最后,分享一下我目前的 MBP 使用习惯吧:极端的全屏使用者,彻底禁用 Dock,隐藏 Menu Bar,将通知和时间放在了 Touch Bar,每天享受沉浸式的屏幕体验。