Mac 多螢幕視窗管理神器

雨神姥爺發表於2016-12-16

使用多個顯示器可以避免在任務視窗或應用之間來回切換,從而提高效率。然而隨著工作空間的擴大,同時也帶來了其它問題,包括:

  1. 使用滑鼠的效率進一步降低;
  2. 活動視窗過多容易失去焦點;
  3. 更多時候是以上兩點同時發生:找半天不知道滑鼠指標在哪,多螢幕之間拖動、管理視窗變得更加困難。

不管你是不是 VIM 黨,不停地在滑鼠與鍵盤之間切換絕對是一件分心且低效的事,很多“懶人”寧可花時間記住數量龐大的組合快捷鍵(當然如果記不住也沒關係,有一款作弊神器可以幫助你快速檢視當前應用的快捷鍵:Cheatsheet),也不願讓自己的右手離開鍵盤。

Mac 多螢幕視窗管理神器

雖然為了避免使用滑鼠你甚至可以給 Chrome 裝上 VIM 對映的外掛,但總有些時候不得不依賴滑鼠完成一些精確的點選、拖動等操作,然而根據心理物理學中著名的費茨定律(Fitt's law),滑鼠移動時間與目標距離成正比,與目標大小成反比:

Mac 多螢幕視窗管理神器

也就是說隨著工作空間的擴大,使用滑鼠的效率將會越來越低。除了滑鼠的問題之外,當同時有多個應用視窗在你面前開啟的時候,即使想要通過組合快捷鍵操作,也容易搞混當前捕獲焦點的應用是哪個。當然就算有多個視窗重疊出現,你可以通過檢視左上角工具欄所顯示的應用名稱來確定當前焦點,不過費茨定律對於視覺搜尋也是同樣適用的,對於連眼睛都懶得抬起來的人來說寧可通過 Command+Tab 嘗試切換來找到當前焦點的應用。

不過這個問題可以通過另外一款作弊神器來解決:HazeOver

Mac 多螢幕視窗管理神器

它可以讓當前出於焦點的視窗正常顯示,而其它所有視窗都蒙上一層半透明的黑紗:

Mac 多螢幕視窗管理神器

macOS 提供了一個有趣的小功能,只要快速晃動滑鼠就可以讓指標放大,從而讓你快速定位自己的滑鼠。然而這點微小的工作遠遠無法彌補它在視窗管理上的不足。與 Windows 上貼邊停靠、甩一甩甩掉其它視窗的功能相比,macOS 視窗左上角紅黃綠的三個小圓點幾乎毫無存在感,拋開面積太小不易點選不說,綠色的放大按鈕只能進入或退出全屏模式,雖然後來加入了長按進入雙全屏模式,也基本上是個雞肋:在小螢幕筆記本上沒什麼用,有擴充套件屏的時候更沒必要用。於是乎在蘋果強大的生態號召力之下出現了許多第三方解決方案,但是我的需求很簡單,我覺得將一塊螢幕劃分成皿、田之類的格局沒有任何必要,我只需要最簡單的功能:

  1. 可以最大化但不是全屏;
  2. 可以佔據左半邊或右半邊;
  3. 可以在不同顯示器之間快速移動。

前兩條根本就是 Windows 的基本功能,我嘗試了一些視窗管理應用之後,最終選擇可以通過程式碼精確配置的 Hammerspoon,與一般的工具不同,首先它是開源的,其次使用 Lua 指令碼作為配置檔案。

Mac 多螢幕視窗管理神器

我的配置檔案在 這裡 Gist-hammerspoon.init.lua,儲存到本地~/.hammerspoon/init.lua,然後 Reload Config 即可。Hammerspoon 還提供一個 Console 介面,可以方便除錯:

Mac 多螢幕視窗管理神器

配置檔案說明

-- 一般組合鍵為 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)複製程式碼

檢視錄屏效果

相關文章