Red Pill
Red Pill

Reputation: 541

macOS Sierra: Emulate Mouse Down and Up

after an update to Sierra I had to find that Karabiner is not working anymore, which could emulate pointer clicks really well.

Any chance to get that via Swift or Apple Script or Obj.C ?

Background: Using Karabiner(and seil) I could bind caps-lock + d down and up to mouse down and up and in between the trackpad movement was understood. My trackpad is not processing keypress anymore but works still fine for pointer moves.

Upvotes: 2

Views: 436

Answers (1)

Red Pill
Red Pill

Reputation: 541

Answering myself, hacked it in hammerspoon. Was quite tricky to get chrome select working, maybe it saves somebody an hour or two:

1 ~/.hammerspoon $ cat init.lua



--[[ Left Keyboard Mouse (alt-d)

The main problem was to get chrome based apps select text when we drag via
keyboard.

You MUST return true always in the handle_drag otherwise it fails to select.
FF works, terminal works, chrome apps (atom, ...) don't.

But true is preventing further processing of the drag coords,
hs.mouse.getAbsolutePosition remains constant while dragging (!)
=> i.e. we MUST calc them via DeltaX, DeltaY, see below.


--]]

hs.alert.show("Config loaded")

-- all mechanics stolen from here:
-- local vimouse = require('vimouse')
-- vimouse('cmd', 'm')

now = hs.timer.secondsSinceEpoch

evt = hs.eventtap
evte = evt.event
evtypes = evte.types
evp=evte.properties

drag_last = now(); drag_intv = 0.01 -- we only synth drags from time to time

mp = {['x']=0, ['y']=0} -- mouse point. coords and last posted event
l = hs.logger.new('keybmouse', 'debug')
dmp = hs.inspect

-- The event tap. Started with the keyboard click:
handled = {evtypes.mouseMoved, evtypes.keyUp }
handle_drag = evt.new(handled, function(e)

    if e:getType() == evtypes.keyUp then
        handle_drag:stop()
        post_evt(2)
        return nil -- otherwise the up seems not processed by the OS
    end

    mp['x']  = mp['x'] + e:getProperty(evp.mouseEventDeltaX)
    mp['y']  = mp['y'] + e:getProperty(evp.mouseEventDeltaY)

    -- giving the key up a chance:
    if now() - drag_last > drag_intv then
        -- l.d('pos', mp.x, 'dx', dx)
        post_evt(6) -- that sometimes makes dx negative in the log above
        drag_last = now()
    end
    return true -- important
end)

function post_evt(mode)
    -- 1: down, 2: up, 6: drag
    if mode == 1 or mode == 2 then
        local p = hs.mouse.getAbsolutePosition()
        mp['x'] = p.x
        mp['y'] = p.y
    end
    local e = evte.newMouseEvent(mode, mp)
    if mode == 6 then cs = 0 else cs=1 end
    e:setProperty(evte.properties.mouseEventClickState, cs)
    e:post()
end

hs.hotkey.bind({"alt"}, "d",
  function(event)
    post_evt(1)
    handle_drag:start()
  end
)

and alt I mapped to capslock via karabiner elements.

Upvotes: 2

Related Questions