import time import threading class WhisplayInterface: def __init__(self, board=None, long_press_threshold=0.5, double_press_threshold=0.3): self._board = board self._long_press_threshold = long_press_threshold self._double_press_threshold = double_press_threshold self._button_is_double_pressed_set = False self._button_press_start = None self._button_press_end = None self._button_is_pressed = False self._button_was_pressed = False self._button_is_long_pressed = False self._button_was_long_pressed = False self._button_is_double_pressed = False self._button_was_double_pressed = False self._press_callbacks = [] self._release_callbacks = [] self._running = False self._gesture_thread = None if board is not None: self.attach(board) @property def long_press_threshold(self): return self._long_press_threshold @property def double_press_threshold(self): return self._double_press_threshold @property def is_pressed(self): return self._button_is_pressed @property def was_pressed(self): return self._button_was_pressed @property def is_long_pressed(self): return self._button_is_long_pressed @property def was_long_pressed(self): return self._button_was_long_pressed @property def is_double_pressed(self): return self._button_is_double_pressed @property def was_double_pressed(self): return self._button_was_double_pressed @property def press_duration(self): if self._button_press_start is None: return 0.0 end = self._button_press_end if self._button_press_end is not None else time.time() return end - self._button_press_start def attach(self, board): self._board = board self._board.on_button_press(self._on_button_press) self._board.on_button_release(self._on_button_release) self.start() def start(self): if self._gesture_thread is not None: return self._running = True self._gesture_thread = threading.Thread(daemon=True, target=self._gesture_loop) self._gesture_thread.start() def stop(self): self._running = False def on_press(self, callback): self._press_callbacks.append(callback) def on_release(self, callback): self._release_callbacks.append(callback) def acknowledge_press(self): self._button_was_pressed = False def acknowledge_long_press(self): self._button_was_long_pressed = False def acknowledge_double_press(self): self._button_was_double_pressed = False def _on_button_press(self): self._button_is_pressed = True self._button_press_start = time.time() if self._button_press_end is not None: gap = self._button_press_start - self._button_press_end if gap < self._double_press_threshold: self._button_is_double_pressed = True self._button_is_double_pressed_set = True for cb in self._press_callbacks: cb() def _on_button_release(self): self._button_was_pressed = self._button_is_pressed self._button_press_end = time.time() self._button_was_long_pressed = self._button_is_long_pressed self._button_was_double_pressed = self._button_is_double_pressed self._button_is_pressed = False self._button_is_double_pressed = False self._button_is_long_pressed = False self._button_is_double_pressed_set = False for cb in self._release_callbacks: cb() def _gesture_loop(self): while self._running: try: current_time = time.time() if self._button_is_pressed: if not self._button_is_double_pressed_set: self._button_is_double_pressed = ( self._button_was_pressed and self._button_press_end is not None and current_time - self._button_press_end < self._double_press_threshold ) if self._button_is_double_pressed: self._button_is_double_pressed_set = True self._button_is_long_pressed = ( current_time - self._button_press_start > self._long_press_threshold ) except Exception: pass time.sleep(0.05)