Skip to content

Instantly share code, notes, and snippets.

@joerick
Created May 28, 2016 17:38
Show Gist options
  • Save joerick/76b18bc6568d7358e8e20914118becaa to your computer and use it in GitHub Desktop.
Save joerick/76b18bc6568d7358e8e20914118becaa to your computer and use it in GitHub Desktop.
Button state machine prototype
from collections import namedtuple
import Queue, unittest
ButtonEvent = namedtuple('ButtonEvent', ('state', 'timestamp',))
ButtonAction = namedtuple('ButtonAction', ('type', 'timestamp',))
class Button(object):
def __init__(self):
self.event_queue = Queue.Queue()
self.last_event = None
self.hold_time = 1.0
self.last_hold_check_time = 0
self.actions = []
def process_events(self, time):
while True:
try:
event = self.event_queue.get(block=False)
except Queue.Empty:
break
self.fire_hold_if_due(event.timestamp)
if event.state == 'down':
self.fire(ButtonAction('down', timestamp=event.timestamp))
elif event.state == 'up':
self.fire(ButtonAction('up', timestamp=event.timestamp))
# check to see if press should be fired
if self.last_event.state == 'down':
press_duration = event.timestamp - self.last_event.timestamp
if press_duration < self.hold_time:
self.fire(ButtonAction('press', timestamp=event.timestamp))
self.last_event = event
self.fire_hold_if_due(time)
def fire_hold_if_due(self, time):
''' check to see if the hold event needs to be fired '''
if self.last_event and self.last_event.state == 'down':
hold_trigger_time = self.last_event.timestamp + self.hold_time
if self.last_hold_check_time < hold_trigger_time <= time:
self.fire(ButtonAction('hold', timestamp=hold_trigger_time))
self.last_hold_check_time = time
def fire(self, action):
self.actions.append(action)
class ButtonTestCase(unittest.TestCase):
def setUp(self):
self.button = Button()
global fired_actions
fired_actions = []
def assertActions(self, action_types):
self.assertEqual(action_types, [a.type for a in self.button.actions])
def testPress(self):
self.button.event_queue.put(ButtonEvent(state='down', timestamp=1))
self.button.event_queue.put(ButtonEvent(state='up', timestamp=1.5))
self.button.process_events(time=2)
self.assertActions(['down', 'up', 'press'])
def testHold(self):
self.button.event_queue.put(ButtonEvent(state='down', timestamp=1))
self.button.event_queue.put(ButtonEvent(state='up', timestamp=3))
self.button.process_events(3.1)
self.assertActions(['down', 'hold', 'up'])
def testIncrementalHold(self):
self.button.event_queue.put(ButtonEvent(state='down', timestamp=1))
self.button.process_events(time=1.1)
self.assertActions(['down'])
self.button.process_events(time=2.1)
self.assertActions(['down', 'hold'])
self.button.event_queue.put(ButtonEvent(state='up', timestamp=3))
self.button.process_events(time=3.1)
self.assertActions(['down', 'hold', 'up'])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment