|
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']) |