tap.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. import time
  2. from threading import Thread
  3. from ..tracker import GestureTracker
  4. from ..geometry import Positionable
  5. from utils import PointGesture
  6. class TapTracker(GestureTracker):
  7. __gesture_types__ = ['tap', 'single_tap', 'double_tap']
  8. __configurable__ = ['tap_distance', 'tap_time', 'double_tap_time',
  9. 'double_tap_distance', 'update_rate']
  10. def __init__(self, window=None):
  11. super(TapTracker, self).__init__(window)
  12. # Map of TUIO session id to tuple (timestamp, position) of point down
  13. self.reg = {}
  14. # Maximum radius in which a touch point can move in order to be a tap
  15. # event in pixels
  16. self.tap_distance = 20
  17. # Maximum time between 'down' and 'up' of a tap event in seconds
  18. self.tap_time = .2
  19. # Maximum time in seconds and distance in pixels between two taps to
  20. # count as double tap
  21. self.double_tap_time = .3
  22. self.double_tap_distance = 30
  23. # Times per second to detect single taps
  24. self.update_rate = 30
  25. self.reset_last_tap()
  26. self.single_tap_thread = Thread(target=self.detect_single_tap)
  27. self.single_tap_thread.daemon = True
  28. self.single_tap_thread.start()
  29. def detect_single_tap(self):
  30. """
  31. Iteration function for single-tap detection thread.
  32. """
  33. while True:
  34. time_diff = time.time() - self.last_tap_time
  35. if self.last_tap and time_diff > self.double_tap_time:
  36. # Last tap is too long ago to be a double tap, so trigger a
  37. # single tap
  38. self.trigger(SingleTapGesture(self.last_tap))
  39. self.reset_last_tap()
  40. time.sleep(1. / self.update_rate)
  41. def reset_last_tap(self):
  42. self.last_tap_time = 0
  43. self.last_tap = None
  44. def on_point_down(self, point):
  45. x, y = point.get_position()
  46. self.reg[point.sid] = time.time(), Positionable(x, y)
  47. def on_point_move(self, point):
  48. if point.sid not in self.reg:
  49. return
  50. # If a stationary point moves beyond a threshold, delete it so that the
  51. # 'up' event will not trigger a 'tap'
  52. t, initial_position = self.reg[point.sid]
  53. if point.distance_to(initial_position) > self.tap_distance:
  54. del self.reg[point.sid]
  55. def on_point_up(self, point):
  56. # Assert that the point has not been deleted by a 'move' event yet
  57. if point.sid not in self.reg:
  58. return
  59. down_time = self.reg[point.sid][0]
  60. del self.reg[point.sid]
  61. # Only trigger a tap event if the 'up' is triggered within a certain
  62. # time afer the 'down'
  63. current_time = time.time()
  64. if current_time - down_time > self.tap_time:
  65. return
  66. tap = TapGesture(point)
  67. self.trigger(tap)
  68. # Trigger double tap if the threshold has not not expired yet
  69. if self.last_tap:
  70. if self.last_tap.distance_to(tap) <= self.double_tap_distance:
  71. # Close enough to be a double tap
  72. self.trigger(DoubleTapGesture(self.last_tap))
  73. self.reset_last_tap()
  74. return
  75. # Generate a seperate single tap gesture for the last tap,
  76. # because the lat tap variable is overwritten now
  77. self.trigger(SingleTapGesture(self.last_tap))
  78. self.last_tap_time = current_time
  79. self.last_tap = tap
  80. class TapGesture(PointGesture):
  81. """
  82. A tap gesture is triggered
  83. """
  84. __type__ = 'tap'
  85. class SingleTapGesture(TapGesture):
  86. """
  87. A single tap gesture is triggered after a regular tap gesture, if no double
  88. tap is triggered for that gesture.
  89. """
  90. __type__ = 'single_tap'
  91. class DoubleTapGesture(TapGesture):
  92. """
  93. A double tap gesture is triggered if two sequential taps are triggered
  94. within a certain time and distance of eachother.
  95. """
  96. __type__ = 'double_tap'