🗂

Hammerspoonでウィンドウサイズ変更と移動

2024/11/27に公開

概要

もともと開発停止で非推奨になていたshiftitを利用していたものの、Mac環境を一新するついでにshiftitからhammerspoonに乗り換えた。

インストール

$ brew install --cask hammerspoon

設定

Open Configinit.luaを以下のように編集してReload Configをクリックする。

hs.window.animationDuration = 0

-- ウィンドウ位置・サイズのユニット
units = {
  right50  = { x = 0.50, y = 0.00, w = 0.50, h = 1.00 },
  left50   = { x = 0.00, y = 0.00, w = 0.50, h = 1.00 },
  maximize = { x = 0.00, y = 0.00, w = 1.00, h = 1.00 }
}

ctl_opt = { 'ctrl', 'option' }

-- ウィンドウが右端にいるかチェック
function isAtRightEdge(win)
  local screenFrame = win:screen():frame()
  local winFrame = win:frame()
  return math.abs((winFrame.x + winFrame.w) - (screenFrame.x + screenFrame.w)) < 5
end

-- ウィンドウが左端にいるかチェック
function isAtLeftEdge(win)
  local screenFrame = win:screen():frame()
  local winFrame = win:frame()
  return math.abs(winFrame.x - screenFrame.x) < 5
end

-- ウィンドウがスクリーンの幅の50%を占めているかチェック
function isHalfWidth(win)
  local screenFrame = win:screen():frame()
  local winFrame = win:frame()
  return math.abs(winFrame.w - screenFrame.w * 0.5) < 5
end

-- 次のスクリーンに移動し、左側に配置
function moveToNextScreenLeft(win)
  if not win then return end
  local nextScreen = win:screen():next()
  win:moveToScreen(nextScreen, false, true)
  win:move(units.left50, nextScreen, true)
end

-- 前のスクリーンに移動し、右側に配置
function moveToPrevScreenRight(win)
  if not win then return end
  local prevScreen = win:screen():previous()
  win:moveToScreen(prevScreen, false, true)
  win:move(units.right50, prevScreen, true)
end

-- ホットキーのバインディング
hs.hotkey.bind(ctl_opt, 'right', function()
  local win = hs.window.focusedWindow()
  if not win then return end
  if isAtRightEdge(win) and isHalfWidth(win) then
    if win:screen():next() then
      moveToNextScreenLeft(win)
    end
  elseif not isAtRightEdge(win) then
    win:move(units.right50, nil, true)
  end
end)

hs.hotkey.bind(ctl_opt, 'left', function()
  local win = hs.window.focusedWindow()
  if not win then return end
  if isAtLeftEdge(win) and isHalfWidth(win) then
    if win:screen():previous() then
      moveToPrevScreenRight(win)
    end
  elseif not isAtLeftEdge(win) then
    win:move(units.left50, nil, true)
  end
end)

hs.hotkey.bind(ctl_opt, 'up', function()
  local win = hs.window.focusedWindow()
  if win then
    win:move(units.maximize, nil, true)
  end
end)

Hammerspoon

動作

  • ctrl + →
    • ウィンドウサイズが半分でない場合は右半分にする
    • ウィンドウサイズが半分の場合は同一スクリーンの右、または隣のスクリーンの左側に移動する
  • ctrl + ←
    • ウィンドウサイズが半分でない場合は左半分にする
    • ウィンドウサイズが半分の場合は同一スクリーンの左、または隣のスクリーンの右側に移動する
  • ctrl + ↑
    • ウィンドウサイズを最大化する

Discussion