mac mini 3面モニター環境整備
前提:
mac mini m4 24GBメモリ
モニタ: https://gyazo.com/4ab01305fe7df3473f016a27d5266328
課題:
window管理ができてない。
以前のubuntuのときは、シンプルにshortcutでアプリをwindow rotationさせていたが、、macではうまくできてない。
macだと hammerspoon ?
目標:
入口摩擦の低減: ウィンドウ移動、サイズ調整、配置の再現、この摩擦を低減させる
code: init.lua
-- ~/.hammerspoon/init.lua
hs.window.animationDuration = 0
-- 左→右(同xなら上→下)でスクリーン順を固定
local function screensLR()
local screens = hs.screen.allScreens()
table.sort(screens, function(a, b)
local fa, fb = a:frame(), b:frame()
if fa.x == fb.x then return fa.y < fb.y end
return fa.x < fb.x
end)
return screens
end
local function indexOfScreen(screens, cur)
for i, s in ipairs(screens) do
if s == cur then return i end
end
return nil
end
local function targetScreenFor(win, dir)
local screens = screensLR()
if n < 2 then return nil end
local i = indexOfScreen(screens, win:screen())
if not i then return nil end
local j
if dir == "next" then
j = (i % n) + 1
else
j = ((i - 2 + n) % n) + 1
end
end
-- 相対位置・相対サイズを維持して移動(最大化しない)
local function moveKeepRelative(win, target)
local f = win:frame()
local cur = win:screen():frame()
local dst = target:frame()
local rx = (f.x - cur.x) / cur.w
local ry = (f.y - cur.y) / cur.h
local rw = f.w / cur.w
local rh = f.h / cur.h
win:moveToScreen(target, false, true)
local nf = hs.geometry.rect(
dst.x + rx * dst.w,
dst.y + ry * dst.h,
rw * dst.w,
rh * dst.h
)
win:setFrameInScreenBounds(nf)
end
-- フルスクを解除してから実行(フルスク中はmoveToScreenが効かないことが多い)
local function runWithUnfullscreened(win, fn)
if not win then return end
if win:isFullScreen() then
win:setFullScreen(false)
hs.timer.doAfter(0.30, fn) -- 環境によっては0.3だと足りないので少し長め
else
fn()
end
end
-- 移動(+必要なら最大化)
local function moveToDisplay(dir, maximize)
local win = hs.window.frontmostWindow() or hs.window.focusedWindow()
if not win then
hs.alert.show("No active window")
return
end
local function action()
local w = hs.window.frontmostWindow() or hs.window.focusedWindow() or win
if not w then return end
local target = targetScreenFor(w, dir)
if not target then
hs.alert.show("Target screen not found")
return
end
if maximize then
w:moveToScreen(target, false, true)
w:maximize()
else
moveKeepRelative(w, target)
end
end
runWithUnfullscreened(win, action)
end
-- キーバインド
-- Alt + ←/→ : 移動だけ(サイズ維持)
hs.hotkey.bind({"alt"}, "Right", function() moveToDisplay("next", false) end)
hs.hotkey.bind({"alt"}, "Left", function() moveToDisplay("prev", false) end)
-- Alt + Shift + ←/→ : 移動して最大化
hs.hotkey.bind({"alt", "shift"}, "Right", function() moveToDisplay("next", true) end)
hs.hotkey.bind({"alt", "shift"}, "Left", function() moveToDisplay("prev", true) end)
-- 自動リロード
hs.pathwatcher.new(os.getenv("HOME") .. "/.hammerspoon/", hs.reload):start()
hs.alert.show("Hammerspoon loaded")