Hammerspoon / hammerspoon

Staggeringly powerful macOS desktop automation with Lua

Home Page:http://www.hammerspoon.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to simulate a mouse drag operation?

JazysYu opened this issue · comments

commented

I want to press a keyboard key, which is equivalent to pressing the left mouse button.

But when I trigger hs.eventtap...leftMouseDown on the desktop and then move the mouse, it doesn't show the drag box like a real mouse left button down, or can drag to move the window below the mouse position, I tried leftMouseDown, mouseMoved, leftMouseDragged none of these combinations work. I noticed if the focusedWindow is not Finder's desktop, like "VSCode", it can have drag effect.

Is this action possible? Thanks.

commented

Mouse drags are annoying... they require multiple events and "time" between each event to allow the receiving app to accept them... e.g.

local event       = require("hs.eventtap").event
local screen      = require("hs.screen")
local mouse       = require("hs.mouse")
local application = require("hs.application")

finderSelectAll = function()

    -- do your prep stuff here
    local finder = application("Finder")
    finder:activate()
    
    local curPos = mouse.absolutePosition()
    
    -- determine start, end, and delta of drag
    local frame     = screen.mainScreen():frame()
    local fullFrame = screen.mainScreen():fullFrame()
    
    local startPoint = {
        x = frame.x,
        y = frame.y
    }

    -- main screen may not be only one and may not start at 0, 0 so we use fullFrame
    local endPoint = {
        x = fullFrame.x + fullFrame.w,
        y = fullFrame.y + fullFrame.h
    }

    local xDelta = endPoint.x - startPoint.x
    local yDelta = endPoint.y - startPoint.y
    
    -- perform drag in a coroutine so each step has a chance to be processed
    local cr -- predeclare because we reference it from within the coroutine
             -- to prevent premature garbage collection
    cr = coroutine.wrap(function()
        
        -- mouseDown
        coroutine.applicationYield()
        event.newMouseEvent(event.types.leftMouseDown, startPoint):post()

        -- startDrag
        coroutine.applicationYield()
        event.newMouseEvent(event.types.leftMouseDragged, startPoint):post()

        -- endDrag
        coroutine.applicationYield()
        event.newMouseEvent(event.types.leftMouseDragged, endPoint)
            :setProperty(event.properties.mouseEventDeltaX, xDelta)
            :setProperty(event.properties.mouseEventDeltaY, yDelta)
            :post()
        
        -- mouseUp
        coroutine.applicationYield()
        event.newMouseEvent(event.types.leftMouseUp, endPoint):post()
            
        cr = nil -- clear coroutine since we're done
        
        -- now do what follows the drag
        mouse.absolutePosition(curPos)
    end)
    
    cr() -- start coroutine
end

Now, in the HS console, and in a relatively clear screen (I've found this doesn't work if there is another applications window near the starting or ending point), type finderSelectAll() and it should select everything on your desktop.

Hope this gets you started in the right direction!

commented

It worked. I tried leftMouseDown and then leftMouseDragged to endPoint with a delay of one second, it seems that one leftMouseDragged with startPoint is missing :)
Anyway this is a great code example, thanks a lot for your help!