General Slowness of hs.eventtap.keyStroke()

1,165 views
Skip to first unread message

Sean Mackesey

unread,
Nov 17, 2016, 2:02:20 AM11/17/16
to Hammerspoon
I've noticed that hs.eventtap.keyStroke is just plain slow. If I do:

hs.hotkey.bind({},'a', nil, function () hs.eventtap.keyStroke({}, 'b') end)

Then there is a noticeable lag between the time that I strike "a", and the time that "b" is emitted. I have observed this in other contexts as well. For example, I use Hammerspoon to implement multiple-modifier bindings in Vim (which does not support them). I do this by binding the multiple-modifier chord in Hammerspoon to the default keys for the target vim command. It is noticeably faster to send the keys to Vim via the shell with:

hs.hotkey.bind({},'MULTIPLE_MODIFIER_CHORD', nil, function () os.execute('/usr/local/bin/mvim --remote-send VIM_KEYS end)


Than it is to send the keys with hs.eventtap.keyStroke.

Is this normal? I used to use both Keymando and Karabiner, and they were both much snappier with key-to-key mappings than Hammerspoon. Any tweaks I can make to address this problem?

asmagill

unread,
Nov 17, 2016, 4:02:45 PM11/17/16
to Hammerspoon
There was a delay introduced between the key-down and the key-up events being sent.  This will become user adjustable at some point when eventtap can get some other modifications to handle system event generation better, but in the mean time you can use the example at https://github.com/Hammerspoon/hammerspoon/issues/1011#issuecomment-261114434 to see if this fixes it for you.

Sean Mackesey

unread,
Nov 17, 2016, 4:20:13 PM11/17/16
to Hammerspoon
Thanks, that does indeed fix it. However, I still don't understand. I wouldn't expect a delay between key-down and key-up events to produce the effects I described above, because it is only the key-down event that triggers, say, the insertion of a character at the cursor. The fact that I was experiencing these delays suggests that the emission of the key-down event was being delayed.

asmagill

unread,
Nov 17, 2016, 5:42:15 PM11/17/16
to Hammerspoon
I can't speak to the Vim application specifically, but generally it is *not* the key-down that an application acts upon, but the key-up... one reason for this is to support the pop-ups that occur in some applications when you hold down certain keys, like "a", for example, and then get a list of various diacritical marks that can be applied to the "a"... until the key-up, the system can't be 100% certain that you are done with tapping that key.

A more "proper" way to generate keystrokes from a bound hotkey would be something like:

h = hs.hotkey.bind({trigger-modifiers}, "trigger-key", function()

    hs.eventtap.event.newKeyEvent({desired-modifiers}, "desired-key", true):post()

end, function()

    hs.eventtap.event.newKeyEvent({desired-modifiers}, "desired-key", false):post()

end, function()

    hs.eventtap.event.newKeyEvent({desired-modifiers}, "desired-key", true):setProperty(hs.eventtap.event.properties.keyboardEventAutorepeat, 1):post()

end)


This works by generating an appropriate message to your actual status of the trigger key -- a down, when you hit the trigger key, an up when you release it, and a repeat if you hold it down long enough.

Haven't used this beyond an initial test, though, so I can't say if there might be some unexpected interactions because of timing or context switching between the frontmost application and the Hammerspoon application, but... it seems to work in my initial testing.

Sean Mackesey

unread,
Nov 17, 2016, 7:12:50 PM11/17/16
to Hammerspoon
Hmm, your example looks like a good idea. Thanks for providing that. But I'm still confused about the key-down/key-up thing. In every application I use (including Hammerspoon!), when I depress the key, a character is inserted-- *not* when I release it. If I hold the key down, then the diacritic selector appears. Even if there is some kind of listener running waiting for the key up, there is still an immediate response to the key down. So a delay between keyDown and keyUp still doesn't seem to explain the observed character insertion delay I see with Hammerspoon's hs.eventtap.keyStroke().

asmagill

unread,
Nov 18, 2016, 4:07:22 PM11/18/16
to Hammerspoon
I cannot say.  If I had to hazard a guess it would be because the keyDown, the delay, and the keyUp all occur in one operation of the Hammerspoon dispatch queue, so the other application doesn't truly get focus back until all three have completed.  But that's just a guess.  The modified form that I gave in a previous reply will have the three operations occur as separate queued events, so it may be more responsive to behind-the-scenes things like that.  Usually, however, the difference is trivial or even unwanted, so... the question really has never come up before.
Reply all
Reply to author
Forward
0 new messages