キーリマップの機能をHammerspoonに移植しましたので貼っておきます。![]()
機能
- メニューバー上でのホイール操作で音量UP/Down
- Option+タイトルバークリックでウィンドウを最背面に移動(Zオーダー変更)
- Option+クライアント領域ドラッグでウィンドウの移動
作ったもの
Hammerspoonのメニューアイコンで「Open Config」を選択し、以下をコピペしてください。
-- Spoonの読み込み
local spoonList = {
"ReloadConfiguration",
"MiddleClickDragScroll",
-- "VolumeScroll",
}
for _, name in ipairs(spoonList) do
hs.loadSpoon(name)
end
-- 各Spoonの設定と起動
if spoon.ReloadConfiguration then
spoon.ReloadConfiguration:start()
end
if spoon.MiddleClickDragScroll then
spoon.MiddleClickDragScroll:start()
end
-- if spoon.VolumeScroll then
-- spoon.VolumeScroll:start()
-- end
-- 自作処理
myConfig = myConfig or {}
--[[---------------------------------------------------------------------
VolumeScrollの代替処理
-----------------------------------------------------------------------]]
local MENU_BAR_HEIGHT = 25
myConfig.volWheelTap = hs.eventtap.new({hs.eventtap.event.types.scrollWheel}, function(event)
local mousePos = hs.mouse.absolutePosition()
if mousePos.y <= MENU_BAR_HEIGHT then
local scroll = event:getProperty(hs.eventtap.event.properties.scrollWheelEventDeltaAxis1)
if scroll ~= 0 then
local key = (scroll > 0) and "SOUND_UP" or "SOUND_DOWN"
hs.eventtap.event.newSystemKeyEvent(key, true):post()
hs.eventtap.event.newSystemKeyEvent(key, false):post()
return true
end
end
return false
end)
myConfig.volWheelTap:start()
--[[---------------------------------------------------------------------
ウィンドウのドラッグ処理
-----------------------------------------------------------------------]]
-- 設定定数
local TITLE_BAR_HEIGHT = 40
local THRESHOLD_H = 15
local THRESHOLD_V = 15
local DRAG_DEADZONE = 0
hs.window.animationDuration = 0
-- 座標が矩形内にあるか判定
function isPointInRect(rect, point)
if not rect or not point then return false end
return point.x >= rect.x and
point.x <= (rect.x + rect.w) and
point.y >= rect.y and
point.y <= (rect.y + rect.h)
end
-- マウスの下にあるウィンドウを取得
function getWindowUnderMouse()
local pos = hs.mouse.absolutePosition()
-- Zオーダー順(手前にある順)に全ウィンドウを取得
local allWindows = hs.window.orderedWindows()
for _, win in ipairs(allWindows) do
local frame = win:frame()
-- マウス座標がウィンドウの枠内に入っているか判定
if pos.x >= frame.x and pos.x <= (frame.x + frame.w) and
pos.y >= frame.y and pos.y <= (frame.y + frame.h) then
return win
end
end
return nil
end
myConfig.windowActionTap = hs.eventtap.new({
hs.eventtap.event.types.leftMouseDown,
hs.eventtap.event.types.leftMouseDragged
}, function(event)
local flags = event:getFlags()
--NOTE:masOS標準アプリで以下の機能と競合する場合がある
--Option+クリック: 現在アクティブなアプリ以外をすべて非表示
if not flags.alt then return false end -- Optionキー必須
local eventType = event:getType()
local mousePos = hs.mouse.absolutePosition()
-- A. クリック開始
if eventType == hs.eventtap.event.types.leftMouseDown then
local targetWin = getWindowUnderMouse() -- 作成した関数を再利用
if not targetWin or targetWin:isFullScreen() then return false end
local frame = targetWin:frame()
if not isPointInRect(frame, mousePos) then return false end
-- タイトルバー領域のクリックか判定
if mousePos.y <= (frame.y + TITLE_BAR_HEIGHT) then
-- 背面送り
local allWindows = hs.window.orderedWindows()
if #allWindows > 1 then
targetWin:sendToBack()
-- 送った瞬間に一瞬フォーカスが浮くのを防ぐため、
-- 0.01秒待ってから「今マウスの下にある別の窓」をアクティブにする
hs.timer.doAfter(0.01, function()
local nextWin = getWindowUnderMouse()
nextWin:focus()
end)
end
return true -- クリックを消費して終了
else
-- ドラッグ移動準備
myConfig.drag = {
win = targetWin,
startMouse = mousePos,
startWinOrigin = {x = frame.x, y = frame.y}
}
return true
end
end
-- B. ドラッグ中
if eventType == hs.eventtap.event.types.leftMouseDragged and myConfig.drag then
local drag = myConfig.drag
local mousePos = event:location()
-- 移動量を計算
local dx = mousePos.x - drag.startMouse.x
local dy = mousePos.y - drag.startMouse.y
local distance = math.sqrt(dx^2 + dy^2)
local nextPos = {x = drag.startWinOrigin.x + dx, y = drag.startWinOrigin.y + dy}
-- 指定距離(DEADZONE)以上動いた場合のみ、角度補正(スナップ)を適用
if distance > DRAG_DEADZONE then
local angleRad = math.atan2(-dy, dx)
local angleDeg = math.abs(math.deg(angleRad))
if angleDeg <= THRESHOLD_H or angleDeg >= (180 - THRESHOLD_H) then
-- 水平ロック
nextPos.y = drag.startWinOrigin.y
elseif math.abs(angleDeg - 90) <= THRESHOLD_V then
-- 垂直ロック
nextPos.x = drag.startWinOrigin.x
end
end
-- ウィンドウを移動
drag.win:move({nextPos.x - drag.win:frame().x, nextPos.y - drag.win:frame().y}, nil, false, 0)
return true
end
return false
end):start()
-- マウスアップでリセット
myConfig.dragUpTap = hs.eventtap.new({hs.eventtap.event.types.leftMouseUp}, function(event)
myConfig.drag = nil
return false
end):start()利用ライブラリ(任意)
ReloadConfiguration:init.luaファイルの自動リロード
MiddleClickDragScroll:マウスホイールのドラッグでスクロール
ダウンロードしたZipファイルを展開してReloadConfiguration.spoon、MiddleClickDragScroll.spoonをダブルクリックすると 配下にインストールされます。
~/.hammerspoon/Spoons
※利用ライブラリをインストールしない場合は以下の処理を削除して、メニューアイコンの「Reload Config」で反映してください。
-- Spoonの読み込み
local spoonList = {
"ReloadConfiguration",
"MiddleClickDragScroll",
-- "VolumeScroll",
}
for _, name in ipairs(spoonList) do
hs.loadSpoon(name)
end
-- 各Spoonの設定と起動
if spoon.ReloadConfiguration then
spoon.ReloadConfiguration:start()
end
if spoon.MiddleClickDragScroll then
spoon.MiddleClickDragScroll:start()
end
-- if spoon.VolumeScroll then
-- spoon.VolumeScroll:start()
-- end既知の不具合
- Zオーダー変更時に画面がチラつく
- ウィンドウのドラッグ時に移動にもたつくアプリがある
コメントを残す