Single/double press detection

Single/double/multiple press detection with LogicMachine #

You can detect whether a single or double press was performed and implement different behaviors.

Create a resident script with 0 sleep time, modify the presstimeout and mapping variables as needed. Default press timeout is 0.5 seconds. When the timeout occurs a specific action that depends on the number of consecutive presses is executed. Each consecutive press resets the timer.

In this example there are two input objects - 0/0/1 and 0/0/2.

If 0/0/1 is pressed:

  • once (single): 0/0/3 value is set to 12
  • twice (double): 0/0/4 value is set to 55
  • multiple time: 0/0/4 value is set to 33

If 0/0/2 is pressed:

  • once (single): 0/0/5 value is set to true
  • two or more times: 0/0/6 value is set to false

Multiple (three or more) press address and value are optional. If it is not set then the double press action will be executed for any press count that is larger than one.

-- maximum time between presses
presstimeout = 0.5

mapping = {
  ['0/0/1'] = {
    -- single press
    single_address = '0/0/3',
    single_value = 12,
    -- double press
    double_address = '0/0/4',
    double_value = 55,
    -- multi (3+) press (optional)
    multi_address = '0/0/4',
    multi_value = 33,
  },
  ['0/0/2'] = {
    -- single press
    single_address = '0/0/5',
    single_value = true,
    -- double press
    double_address = '0/0/6',
    double_value = false,
  },
}

require('copas')

function write(map, key)
  local address = map[ key .. '_address']
  local value = map[ key .. '_value']

  if address and value ~= nil then
    grp.write(address, value)
    return true
  end
end

function timerthread(addr, map)
  local counter = 0
  local timeout = -1 -- suspend thread

  while true do
    copas.sleep(timeout)

    if map.counter == counter then
      if timeout == presstimeout then
        if counter == 1 then
          write(map, 'single')
        elseif counter == 2 or not write(map, 'multi') then
          write(map, 'double')
        end

        timeout = -1
        counter = 0
        map.counter = 0
      end
    else
      timeout = presstimeout
      counter = map.counter
    end
  end
end

for addr, map in pairs(mapping) do
  map.counter = 0
  map.thread = copas.addthread(timerthread, addr, map)
end

function eventhandler(event)
  local map = mapping[ event.dst ]

  if map then
    map.counter = map.counter + 1
    copas.wakeup(map.thread)
  end
end

lb = require('localbus').new(1)
lb:sethandler('groupwrite', eventhandler)

copas.addserver(lb.sock, function()
  lb.sock = copas.wrap(lb.sock)

  while true do
    lb:step()
  end
end, 1)

copas.loop()