-
-
Save kizzx2/e542fa74b80b7563045a to your computer and use it in GitHub Desktop.
-- Inspired by Linux alt-drag or Better Touch Tools move/resize functionality | |
function get_window_under_mouse() | |
-- Invoke `hs.application` because `hs.window.orderedWindows()` doesn't do it | |
-- and breaks itself | |
local _ = hs.application | |
local my_pos = hs.geometry.new(hs.mouse.getAbsolutePosition()) | |
local my_screen = hs.mouse.getCurrentScreen() | |
return hs.fnutils.find(hs.window.orderedWindows(), function(w) | |
return my_screen == w:screen() and my_pos:inside(w:frame()) | |
end) | |
end | |
dragging_win = nil | |
dragging_mode = 1 | |
drag_event = hs.eventtap.new({ hs.eventtap.event.types.mouseMoved }, function(e) | |
if dragging_win then | |
local dx = e:getProperty(hs.eventtap.event.properties.mouseEventDeltaX) | |
local dy = e:getProperty(hs.eventtap.event.properties.mouseEventDeltaY) | |
local mods = hs.eventtap.checkKeyboardModifiers() | |
-- Ctrl + Shift to move the window under cursor | |
if dragging_mode == 1 and mods.ctrl and mods.shift then | |
dragging_win:move({dx, dy}, nil, false, 0) | |
-- Alt + Shift to resize the window under cursor | |
elseif mods.alt and mods.shift then | |
local sz = dragging_win:size() | |
local w1 = sz.w + dx | |
local h1 = sz.h + dy | |
dragging_win:setSize(w1, h1) | |
end | |
end | |
return nil | |
end) | |
flags_event = hs.eventtap.new({ hs.eventtap.event.types.flagsChanged }, function(e) | |
local flags = e:getFlags() | |
if flags.ctrl and flags.shift and dragging_win == nil then | |
dragging_win = get_window_under_mouse() | |
dragging_mode = 1 | |
drag_event:start() | |
elseif flags.alt and flags.shift and dragging_win == nil then | |
dragging_win = get_window_under_mouse() | |
dragging_mode = 2 | |
drag_event:start() | |
else | |
drag_event:stop() | |
dragging_win = nil | |
end | |
return nil | |
end) | |
flags_event:start() |
Great work here. I've just tweaked @jdtsmith's to use cmd + shift (drag) and alt + shift (resize) as I'm used to zooom2 keybindings.
-- Inspired by Linux alt-drag or Better Touch Tools move/resize functionality
-- from https://gist.github.com/kizzx2/e542fa74b80b7563045a
-- Command-shift-move: move window under mouse
-- Alt-Shift-move: resize window under mouse
function get_window_under_mouse()
local my_pos = hs.geometry.new(hs.mouse.getAbsolutePosition())
local my_screen = hs.mouse.getCurrentScreen()
return hs.fnutils.find(hs.window.orderedWindows(), function(w)
return my_screen == w:screen() and
w:isStandard() and
(not w:isFullScreen()) and
my_pos:inside(w:frame())
end)
end
dragging = {} -- global variable to hold the dragging/resizing state
drag_event = hs.eventtap.new({ hs.eventtap.event.types.mouseMoved }, function(e)
if not dragging then return nil end
if dragging.mode==3 then -- just move
local dx = e:getProperty(hs.eventtap.event.properties.mouseEventDeltaX)
local dy = e:getProperty(hs.eventtap.event.properties.mouseEventDeltaY)
dragging.win:move({dx, dy}, nil, false, 0)
else -- resize
local pos=hs.mouse.getAbsolutePosition()
local w1 = dragging.size.w + (pos.x-dragging.off.x)
local h1 = dragging.size.h + (pos.y-dragging.off.y)
dragging.win:setSize(w1, h1)
end
end)
flags_event = hs.eventtap.new({ hs.eventtap.event.types.flagsChanged }, function(e)
local flags = e:getFlags()
local mode=(flags.shift and 1 or 0) + (flags.cmd and 2 or 0) + (flags.alt and 4 or 0)
if mode==3 or mode==5 then -- valid modes
if dragging then
if dragging.mode == mode then return nil end -- already working
else
-- only update window if we hadn't started dragging/resizing already
dragging={win = get_window_under_mouse()}
if not dragging.win then -- no good window
dragging=nil
return nil
end
end
dragging.mode = mode -- 3=drag, 5=resize
if mode==5 then
dragging.off=hs.mouse.getAbsolutePosition()
dragging.size=dragging.win:size()
end
drag_event:start()
else -- not a valid mode
if dragging then
drag_event:stop()
dragging = nil
end
end
return nil
end)
flags_event:start()
Thank you all — this is exactly what I've been looking for!
I've been happily using this for years, but now that I've upgraded to OSX Catalina it's extremely laggy. The window moves with delay relative to cursor movement, and the modifier keys seem to stay activated for a few seconds after unpressing them. Has anyone else encountered this or found a fix?
Hi guys, I just found out about hammerspoon. After spending a weekend on linux I found myself trying to alt+leftClick to drag and alt+rightClick to resize, so I went looked for a solution and here I am :)
Here's what I did based on the script I found here. This implements cmd + leftClick
for moving and cmd + rightClick
for resizing.
function get_window_under_mouse()
local pos = hs.geometry.new(hs.mouse.getAbsolutePosition())
local screen = hs.mouse.getCurrentScreen()
return hs.fnutils.find(hs.window.orderedWindows(), function(w)
return screen == w:screen() and pos:inside(w:frame())
end)
end
dragging_window = nil
drag_event = hs.eventtap.new(
{
hs.eventtap.event.types.leftMouseDragged,
hs.eventtap.event.types.rightMouseDragged,
}, function(e)
if not dragging_win then return nil end
local dx = e:getProperty(hs.eventtap.event.properties.mouseEventDeltaX)
local dy = e:getProperty(hs.eventtap.event.properties.mouseEventDeltaY)
local mouse = hs.mouse:getButtons()
if mouse.left then
dragging_win:move({dx, dy}, nil, false, 0)
elseif mouse.right then
local sz = dragging_win:size()
local w1 = sz.w + dx
local h1 = sz.h + dy
dragging_win:setSize(w1, h1)
end
end)
flag_event = hs.eventtap.new({ hs.eventtap.event.types.flagsChanged }, function(e)
local flags = e:getFlags()
if flags.cmd then
dragging_win = get_window_under_mouse()
drag_event:start()
else
draggin_win = nil
drag_event:stop()
end
end)
flag_event:start()
As @harob has said, hammerspoon is getting a little still, I don't know why. If one of you finds a solution, share it with us! :)
Regarding slow FPS when resizing, check out this (closed) issue. Sounds like it needs to be fixed internally somehow: Hammerspoon/hammerspoon#923
Hey all,
I created a spoon that combines some of the techniques here and fixes the slow framerate while resizing:
https://github.com/dbalatero/SkyRocket.spoon
Instead of resizing the window in realtime, I draw an transparent preview box on the screen with hs.canvas
, resize that as you drag, then commit the actual resize to the window when you let go of the mouse. It's a compromise for sure, but it's way better than dealing with the laggy framerate when naively trying to resize the window in realtime.
@dbalatero Thanks for the workaround - works like a charm!
Thanks for this. I altered it somewhat to use Command+Ctrl (since that's my default key binding in HS). I also weed out non-standard and maximized windows, which avoids various issues, and use a different resize method that is more reliable for me. You can also switch mid-action between move or resize and the action isn't interrupted. Works great for me! Thanks again.