switches from tap_key to set_key in order to reduce tick jitters due to hardcoded sleeps

This commit is contained in:
Harald Albrecht 2019-02-16 19:01:52 +01:00
parent aaa533161a
commit 8d41590d09
2 changed files with 72 additions and 19 deletions

View File

@ -61,18 +61,30 @@ function mb.tap_times(key, times, ...)
-- Tick mappers execute a series of tick'ered function calls, passing in each
-- one of a sequence of things with each tick until done. So, this is like
-- array mappers, but this time they're broken into discrete ticks.
-- array mappers, but this time they're broken into discrete ticks. And since
-- we sometimes need to do multiple ticked steps per element, our tick mappers
-- can also work on sequences of functions to be called for each element.
local TickMapper = {}
TickMapper.__index = TickMapper
mb.TickMapper = TickMapper
-- Creates a new tick mapper that calls a function on every element of an
-- array, but only one call per tick.
-- Creates a new tick mapper that calls a function (or a sequence of
-- functions) on every element of an array, but only one call per tick.
--
-- luacheck: ignore 212/self
function TickMapper:new(func, ...)
-- Since we allow for sequences of functions, simply turn a single
-- function given to us into a single-element sequence. Additionally, we
-- need to handle the special test case where someone is giving us a
-- function which in fact is a table (as "busted" does with spies and
-- stubs).
if type(func) == "function" or (type(func) == "table" and #func == 0) then
func = {func}
end
local slf = {
func=func, -- the function to call for each element.
func=func, -- the function(s) to call for each element.
fidx=1,
flen=#func,
elements={...}, -- the elements to map onto function calls.
idx=1,
len=#{...}
@ -80,18 +92,27 @@ function TickMapper:new(func, ...)
return setmetatable(slf, TickMapper)
end
-- For each tick, process only the next element in our list until all elements
-- have been processed. Then indicate finish.
-- For each tick, process only the next element and next function in our list
-- until all functions for this element, and then all elements have been
-- processed. Only then indicate finish.
function TickMapper:process()
-- Don't wonder why we shield this, but this way we also correctly handle
-- the border case of an empty list of elements to map without crashing.
if self.idx <= self.len then
self.func(self.elements[self.idx])
self.func[self.fidx](self.elements[self.idx])
end
-- Update index to next element and indicate back whether we'll need a
-- further round in the future.
self.idx = self.idx + 1
return self.idx <= self.len
-- Update function index to next function in sequence, and only when we
-- have run all functions, then proceed with the next element.
self.fidx = self.fidx + 1
if self.fidx > self.flen then
self.fidx = 1
-- Update index to next element and indicate back whether we'll need a
-- further round in the future.
self.idx = self.idx + 1
return self.idx <= self.len
end
-- There's always more to do, since there are more functions waiting to be called.
return true
end
-- Adds a set of modifiers to be either pressed or released to the queue of
@ -126,10 +147,15 @@ function mb.addkeys(after, keys, ...)
end
keys = keysarr
end
-- Queue the keys to tap in a sequence of ticks.
-- Queue the keys to tap in a sequence of ticks. Please note that we
-- expect things to be already broken up at this point, as the tick mapper
-- will dutyfully tap each element on each tick.
mb.addkeyticker(
TickMapper:new(
function(key) keybow.tap_key(key) end,
{
function(key) keybow.set_key(key, true) end,
function(key) keybow.set_key(key, false) end
},
table.unpack(keys)
),
after)

View File

@ -103,6 +103,14 @@ describe("asynchronous keys", function()
assert.stub(t).was.called.With(42)
end)
it("map two functions on ticking sequence", function()
local s = stub.new()
local tm = mb.TickMapper:new({s, s}, 1, 2, 3)
mb.addkeyticker(tm)
tt.ticktock(100)
assert.stub(s).was.called(2*3)
end)
it("tick modifiers", function()
local s = spy.on(keybow, "set_modifier")
mb.addmodifiers(0, keybow.KEY_DOWN, keybow.LEFT_CTRL, keybow.LEFT_SHIFT)
@ -113,9 +121,9 @@ describe("asynchronous keys", function()
assert.spy(s).was.called.With(keybow.LEFT_SHIFT, keybow.KEY_DOWN)
end)
it("ticks keys", function()
it("ticks keys in a string", function()
local sm = spy.on(keybow, "set_modifier")
local sk = spy.on(keybow, "tap_key")
local sk = spy.on(keybow, "set_key")
mb.addkeys(0, "abc", keybow.LEFT_CTRL, keybow.LEFT_SHIFT)
tt.ticktock(100)
@ -126,10 +134,29 @@ describe("asynchronous keys", function()
assert.spy(sm).was.called.With(keybow.LEFT_CTRL, keybow.KEY_UP)
assert.spy(sm).was.called.With(keybow.LEFT_SHIFT, keybow.KEY_UP)
assert.spy(sk).was.called(3)
assert.spy(sk).was.called.With("a")
assert.spy(sk).was.called.With("b")
assert.spy(sk).was.called.With("c")
-- note that set_key needs to be called twice for each key tap.
assert.spy(sk).was.called(2*3)
assert.spy(sk).was.called.With("a", true)
assert.spy(sk).was.called.With("a", false)
assert.spy(sk).was.called.With("b", true)
assert.spy(sk).was.called.With("b", false)
assert.spy(sk).was.called.With("c", true)
assert.spy(sk).was.called.With("c", false)
end)
it("ticks keys in a table", function()
local sk = spy.on(keybow, "set_key")
mb.addkeys(0, {"a", keybow.ENTER, "c"})
tt.ticktock(100)
assert.spy(sk).was.called(2*3)
assert.spy(sk).was.called.With("a", true)
assert.spy(sk).was.called.With("a", false)
assert.spy(sk).was.called.With(keybow.ENTER, true)
assert.spy(sk).was.called.With(keybow.ENTER, false)
assert.spy(sk).was.called.With("c", true)
assert.spy(sk).was.called.With("c", false)
end)
end)