Key repeats are delayed in my Hammerspoon script
Asked Answered
I

1

6

I have my CAPSLOCK bound to F18 (karabiner) to act as a modifier key. I'm trying to simulate CAPSLOCK+h, j, k, l to act as VIM movement keys. Everything works but there's an issue with delay when repeating. That is, it's very slow when I press down the CAPSLOCK+h which should simulate pressing the "<-" key repeatedly but it's very delayed and only sends one per second. Any ideas on why that's happening? My init.lua is below:

-- A global variable for the Hyper Mode
k = hs.hotkey.modal.new({}, "F17")

-- Enter Hyper Mode when F18 (Hyper/Capslock) is pressed
pressedF18 = function()
  k.triggered = false
  k.modifier = false
  k:enter()

  trigger_modifier = function()
    k.modifier = true
  end

  -- Only trigger as modifier if held longer than thisj
  hs.timer.doAfter(0.35, trigger_modifier)
end

-- Arrow keys
k:bind({}, 'h', function()
  hs.eventtap.keyStroke({}, 'Left')
  k.triggered = true
end)

k:bind({}, 'j', function()
  hs.eventtap.keyStroke({}, 'Down')
  k.triggered = true
end)

k:bind({}, 'k', function()
  hs.eventtap.keyStroke({}, 'Up')
  k.triggered = true
end)

k:bind({}, 'l', function()
  hs.eventtap.keyStroke({}, 'Right')
  k.triggered = true
end)

-- Leave Hyper Mode when F18 (Hyper/Capslock) is pressed,
--   send ESCAPE if no other keys are pressed.
releasedF18 = function()
  k:exit()

  if not k.triggered then
    -- If hotkey held longer than this amount of time
    -- let it remain as modifier and don't send ESCAPE
    if not k.modifier then
      hs.eventtap.keyStroke({}, 'ESCAPE')
    else
      print("Modifier detected")
    end
  end
end

-- Bind the Hyper key
f18 = hs.hotkey.bind({}, 'F18', pressedF18, releasedF18)
Itin answered 6/12, 2016 at 1:18 Comment(0)
A
8

I had some similar slowness. It looks like there was some slowness introduced in one of the latest versions. You can call the lower level function using the fastKeyStroke function below. I've included my hjkl implementation so you can see it used. Also note that I'm passing 5 parameters into hs.hotkey.bind as specified in the docs for key repeating.

local hyper = {"shift", "cmd", "alt", "ctrl"}

local fastKeyStroke = function(modifiers, character)
  local event = require("hs.eventtap").event
  event.newKeyEvent(modifiers, string.lower(character), true):post()
  event.newKeyEvent(modifiers, string.lower(character), false):post()
end

hs.fnutils.each({
  -- Movement
  { key='h', mod={}, direction='left'},
  { key='j', mod={}, direction='down'},
  { key='k', mod={}, direction='up'},
  { key='l', mod={}, direction='right'},
  { key='n', mod={'cmd'}, direction='left'},  -- beginning of line
  { key='p', mod={'cmd'}, direction='right'}, -- end of line
  { key='m', mod={'alt'}, direction='left'},  -- back word
  { key='.', mod={'alt'}, direction='right'}, -- forward word
}, function(hotkey)
  hs.hotkey.bind(hyper, hotkey.key, 
      function() fastKeyStroke(hotkey.mod, hotkey.direction) end,
      nil,
      function() fastKeyStroke(hotkey.mod, hotkey.direction) end
    )
  end
)

Source about the slowness

Ayn answered 6/12, 2016 at 3:9 Comment(2)
Yep, this is the right answer for now - hs.eventtap.keyStroke() is really just the same newKeyEvent() pair, with an hs.timer.usleep() inbetween. We added the brief sleep to try and avoid the key events arriving out of order. The next release will add a configurable delay, so you can turn it off if you want to :)Energumen
The delay option has been added soon after in Hammerspoon version 0.9.51 (25 Dec 2016).Kirby

© 2022 - 2024 — McMap. All rights reserved.