使用多個顯示器可以避免在任務窗口或應用之間來回切換,從而提高效率。然而隨著工作空間的擴大,同時也帶來了其它問題,包括:
- 使用鼠標的效率進一步降低;
- 活動窗口過多容易失去焦點;
- 更多時候是以上兩點同時發生:找半天不知道鼠標指針在哪,多屏幕之間拖動、管理窗口變得更加困難。
不管你是不是 VIM 黨,不停地在鼠標與鍵盤之間切換絕對是一件分心且低效的事,很多“懶人”寧可花時間記住數量龐大的組合快捷鍵(當然如果記不住也沒關系,有一款作弊神器可以幫助你快速查看當前應用的快捷鍵:Cheatsheet),也不愿讓自己的右手離開鍵盤。
雖然為了避免使用鼠標你甚至可以給 Chrome 裝上 VIM 映射的插件,但總有些時候不得不依賴鼠標完成一些精確的點擊、拖動等操作,然而根據心理物理學中著名的費茨定律(Fitt's law),鼠標移動時間與目標距離成正比,與目標大小成反比:
也就是說隨著工作空間的擴大,使用鼠標的效率將會越來越低。除了鼠標的問題之外,當同時有多個應用窗口在你面前打開的時候,即使想要通過組合快捷鍵操作,也容易搞混當前捕獲焦點的應用是哪個。當然就算有多個窗口重疊出現,你可以通過查看左上角工具欄所顯示的應用名稱來確定當前焦點,不過費茨定律對于視覺搜索也是同樣適用的,對于連眼睛都懶得抬起來的人來說寧可通過 Command+Tab 嘗試切換來找到當前焦點的應用。
不過這個問題可以通過另外一款作弊神器來解決:HazeOver
它可以讓當前出于焦點的窗口正常顯示,而其它所有窗口都蒙上一層半透明的黑紗:
macOS 提供了一個有趣的小功能,只要快速晃動鼠標就可以讓指針放大,從而讓你快速定位自己的鼠標。然而這點微小的工作遠遠無法彌補它在窗口管理上的不足。與 Windows 上貼邊停靠、甩一甩甩掉其它窗口的功能相比,macOS 窗口左上角紅黃綠的三個小圓點幾乎毫無存在感,拋開面積太小不易點擊不說,綠色的放大按鈕只能進入或退出全屏模式,雖然后來加入了長按進入雙全屏模式,也基本上是個雞肋:在小屏幕筆記本上沒什么用,有擴展屏的時候更沒必要用。于是乎在蘋果強大的生態號召力之下出現了許多第三方解決方案,但是我的需求很簡單,我覺得將一塊屏幕劃分成皿、田之類的格局沒有任何必要,我只需要最簡單的功能:
- 可以最大化但不是全屏;
- 可以占據左半邊或右半邊;
- 可以在不同顯示器之間快速移動。
前兩條根本就是 Windows 的基本功能,我嘗試了一些窗口管理應用之后,最終選擇可以通過代碼精確配置的 Hammerspoon,與一般的工具不同,首先它是開源的,其次使用 Lua 腳本作為配置文件。
我的配置文件在 這里 Gist-hammerspoon.init.lua,保存到本地~/.hammerspoon/init.lua
,然后 Reload Config
即可。Hammerspoon 還提供一個 Console 界面,可以方便調試:
配置文件說明
-- 一般組合鍵為 Shift + Command + ?
local hyper = {'shift', 'cmd'}
-- 最大化窗口
-- 快捷鍵為 Shift + Command + ↑
hs.hotkey.bind(hyper, 'up', function()
hs.grid.maximizeWindow()
end)
-- 讓窗口占據左半邊(Windows 下面的向左貼邊停靠)
-- 快捷鍵為 Shift + Command + ←
hs.hotkey.bind(hyper, "Left", function()
local win = hs.window.focusedWindow()
local f = win:frame()
local screen = win:screen()
local max = screen:frame()
f.x = max.x
f.y = max.y
f.w = max.w / 2
f.h = max.h
win:setFrame(f)
end)
-- 向右停靠類似
-- 將當前窗口移動到第 n 個屏幕
-- 并最大化窗口
-- 快捷鍵為 Ctrl + Command + 屏幕數字
local hyper2 = {'ctrl', 'cmd'}
moveto = function(win, n)
local screens = hs.screen.allScreens()
if n > #screens then
hs.alert.show("No enough screens " .. #screens)
else
local toWin = hs.screen.allScreens()[n]:name()
hs.alert.show("Move " .. win:application():name() .. " to " .. toWin)
hs.layout.apply({{nil, win:title(), toWin, hs.layout.maximized, nil, nil}})
end
end
hs.hotkey.bind(hyper2, "1", function()
local win = hs.window.focusedWindow()
moveto(win, 1)
end)
hs.hotkey.bind(hyper2, "2", function()
local win = hs.window.focusedWindow()
moveto(win, 2)
end)
hs.hotkey.bind(hyper2, "3", function()
local win = hs.window.focusedWindow()
moveto(win, 3)
end)