Lugdunum  0.1.0
gestureDetector.cpp
Go to the documentation of this file.
3 
4 //--------------------------------------------------------------------------------
5 // gestureDetector.cpp
6 //--------------------------------------------------------------------------------
7 namespace ndk_helper {
8 
9 //--------------------------------------------------------------------------------
10 // includes
11 //--------------------------------------------------------------------------------
12 
13 //--------------------------------------------------------------------------------
14 // GestureDetector
15 //--------------------------------------------------------------------------------
17 
18 void GestureDetector::SetConfiguration(AConfiguration* config) {
19  dp_factor_ = 160.f / AConfiguration_getDensity(config);
20 }
21 
22 //--------------------------------------------------------------------------------
23 // TapDetector
24 //--------------------------------------------------------------------------------
25 TapDetector::TapDetector() : down_x_(0), down_y_(0) {}
26 
27 GESTURE_STATE TapDetector::Detect(const AInputEvent* motion_event) {
28  if (AMotionEvent_getPointerCount(motion_event) > 1) {
29  // Only support single touch
30  return false;
31  }
32 
33  int32_t action = AMotionEvent_getAction(motion_event);
34  unsigned int flags = action & AMOTION_EVENT_ACTION_MASK;
35  switch (flags) {
36  case AMOTION_EVENT_ACTION_DOWN:
37  down_pointer_id_ = AMotionEvent_getPointerId(motion_event, 0);
38  down_x_ = AMotionEvent_getX(motion_event, 0);
39  down_y_ = AMotionEvent_getY(motion_event, 0);
40  break;
41  case AMOTION_EVENT_ACTION_UP: {
42  int64_t eventTime = AMotionEvent_getEventTime(motion_event);
43  int64_t downTime = AMotionEvent_getDownTime(motion_event);
44  if (eventTime - downTime <= TAP_TIMEOUT) {
45  if (down_pointer_id_ == AMotionEvent_getPointerId(motion_event, 0)) {
46  float x = AMotionEvent_getX(motion_event, 0) - down_x_;
47  float y = AMotionEvent_getY(motion_event, 0) - down_y_;
48  if (x * x + y * y < TOUCH_SLOP * TOUCH_SLOP * dp_factor_) {
49  return GESTURE_STATE_ACTION;
50  }
51  }
52  }
53  break;
54  }
55  }
56  return GESTURE_STATE_NONE;
57 }
58 
59 //--------------------------------------------------------------------------------
60 // DoubletapDetector
61 //--------------------------------------------------------------------------------
63 // : last_tap_x_(0), last_tap_y_(0), last_tap_time_(0) {}
64 
65 GESTURE_STATE DoubletapDetector::Detect(const AInputEvent* motion_event) {
66  if (AMotionEvent_getPointerCount(motion_event) > 1) {
67  // Only support single double tap
68  return false;
69  }
70 
71  bool tap_detected = tap_detector_.Detect(motion_event);
72 
73  int32_t action = AMotionEvent_getAction(motion_event);
74  unsigned int flags = action & AMOTION_EVENT_ACTION_MASK;
75  switch (flags) {
76  case AMOTION_EVENT_ACTION_DOWN: {
77  int64_t eventTime = AMotionEvent_getEventTime(motion_event);
78  if (eventTime - last_tap_time_ <= DOUBLE_TAP_TIMEOUT) {
79  float x = AMotionEvent_getX(motion_event, 0) - last_tap_x_;
80  float y = AMotionEvent_getY(motion_event, 0) - last_tap_y_;
81  if (x * x + y * y < DOUBLE_TAP_SLOP * DOUBLE_TAP_SLOP * dp_factor_) {
82  return GESTURE_STATE_ACTION;
83  }
84  }
85  break;
86  }
87  case AMOTION_EVENT_ACTION_UP:
88  if (tap_detected) {
89  last_tap_time_ = AMotionEvent_getEventTime(motion_event);
90  last_tap_x_ = AMotionEvent_getX(motion_event, 0);
91  last_tap_y_ = AMotionEvent_getY(motion_event, 0);
92  }
93  break;
94  }
95  return GESTURE_STATE_NONE;
96 }
97 
98 void DoubletapDetector::SetConfiguration(AConfiguration* config) {
99  dp_factor_ = 160.f / AConfiguration_getDensity(config);
100  tap_detector_.SetConfiguration(config);
101 }
102 
103 //--------------------------------------------------------------------------------
104 // PinchDetector
105 //--------------------------------------------------------------------------------
106 
107 int32_t PinchDetector::FindIndex(const AInputEvent* event, int32_t id) {
108  int32_t count = AMotionEvent_getPointerCount(event);
109  for (auto i = 0; i < count; ++i) {
110  if (id == AMotionEvent_getPointerId(event, i)) return i;
111  }
112  return -1;
113 }
114 
115 GESTURE_STATE PinchDetector::Detect(const AInputEvent* event) {
117  int32_t action = AMotionEvent_getAction(event);
118  uint32_t flags = action & AMOTION_EVENT_ACTION_MASK;
119  event_ = event;
120 
121  int32_t count = AMotionEvent_getPointerCount(event);
122  switch (flags) {
123  case AMOTION_EVENT_ACTION_DOWN:
124  vec_pointers_.push_back(AMotionEvent_getPointerId(event, 0));
125  break;
126  case AMOTION_EVENT_ACTION_POINTER_DOWN: {
127  int32_t iIndex = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >>
128  AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
129  vec_pointers_.push_back(AMotionEvent_getPointerId(event, iIndex));
130  if (count == 2) {
131  // Start new pinch
132  ret = GESTURE_STATE_START;
133  }
134  } break;
135  case AMOTION_EVENT_ACTION_UP:
136  vec_pointers_.pop_back();
137  break;
138  case AMOTION_EVENT_ACTION_POINTER_UP: {
139  int32_t index = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >>
140  AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
141  int32_t released_pointer_id = AMotionEvent_getPointerId(event, index);
142 
143  std::vector<int32_t>::iterator it = vec_pointers_.begin();
144  std::vector<int32_t>::iterator it_end = vec_pointers_.end();
145  int32_t i = 0;
146  for (; it != it_end; ++it, ++i) {
147  if (*it == released_pointer_id) {
148  vec_pointers_.erase(it);
149  break;
150  }
151  }
152 
153  if (i <= 1) {
154  // Reset pinch or drag
155  if (count != 2) {
156  // Start new pinch
158  }
159  }
160  } break;
161  case AMOTION_EVENT_ACTION_MOVE:
162  switch (count) {
163  case 1:
164  break;
165  default:
166  // Multi touch
167  ret = GESTURE_STATE_MOVE;
168  break;
169  }
170  break;
171  case AMOTION_EVENT_ACTION_CANCEL:
172  break;
173  }
174 
175  return ret;
176 }
177 
178 bool PinchDetector::GetPointers(lug::Math::Vec2f&v1, lug::Math::Vec2f& v2) {
179  if (vec_pointers_.size() < 2) return false;
180 
181  int32_t index = FindIndex(event_, vec_pointers_[0]);
182  if (index == -1) return false;
183 
184  float x = AMotionEvent_getX(event_, index);
185  float y = AMotionEvent_getY(event_, index);
186 
187  index = FindIndex(event_, vec_pointers_[1]);
188  if (index == -1) return false;
189 
190  float x2 = AMotionEvent_getX(event_, index);
191  float y2 = AMotionEvent_getY(event_, index);
192 
193  v1 = lug::Math::Vec2f{x, y};
194  v2 = lug::Math::Vec2f{x2, y2};
195 
196  return true;
197 }
198 
199 //--------------------------------------------------------------------------------
200 // DragDetector
201 //--------------------------------------------------------------------------------
202 
203 int32_t DragDetector::FindIndex(const AInputEvent* event, int32_t id) {
204  int32_t count = AMotionEvent_getPointerCount(event);
205  for (auto i = 0; i < count; ++i) {
206  if (id == AMotionEvent_getPointerId(event, i)) return i;
207  }
208  return -1;
209 }
210 
211 GESTURE_STATE DragDetector::Detect(const AInputEvent* event) {
213  int32_t action = AMotionEvent_getAction(event);
214  int32_t index = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >>
215  AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
216  uint32_t flags = action & AMOTION_EVENT_ACTION_MASK;
217  event_ = event;
218 
219  int32_t count = AMotionEvent_getPointerCount(event);
220  switch (flags) {
221  case AMOTION_EVENT_ACTION_DOWN:
222  vec_pointers_.push_back(AMotionEvent_getPointerId(event, 0));
223  ret = GESTURE_STATE_START;
224  break;
225  case AMOTION_EVENT_ACTION_POINTER_DOWN:
226  vec_pointers_.push_back(AMotionEvent_getPointerId(event, index));
227  break;
228  case AMOTION_EVENT_ACTION_UP:
229  vec_pointers_.pop_back();
230  ret = GESTURE_STATE_END;
231  break;
232  case AMOTION_EVENT_ACTION_POINTER_UP: {
233  int32_t released_pointer_id = AMotionEvent_getPointerId(event, index);
234 
235  auto it = vec_pointers_.begin();
236  auto it_end = vec_pointers_.end();
237  int32_t i = 0;
238  for (; it != it_end; ++it, ++i) {
239  if (*it == released_pointer_id) {
240  vec_pointers_.erase(it);
241  break;
242  }
243  }
244 
245  if (i <= 1) {
246  // Reset pinch or drag
247  if (count == 2) {
248  ret = GESTURE_STATE_START;
249  }
250  }
251  break;
252  }
253  case AMOTION_EVENT_ACTION_MOVE:
254  switch (count) {
255  case 1:
256  // Drag
257  ret = GESTURE_STATE_MOVE;
258  break;
259  default:
260  break;
261  }
262  break;
263  case AMOTION_EVENT_ACTION_CANCEL:
264  break;
265  }
266 
267  return ret;
268 }
269 
270 bool DragDetector::GetPointer(lug::Math::Vec2f& v) {
271  if (vec_pointers_.size() < 1) return false;
272 
273  int32_t iIndex = FindIndex(event_, vec_pointers_[0]);
274  if (iIndex == -1) return false;
275 
276  float x = AMotionEvent_getX(event_, iIndex);
277  float y = AMotionEvent_getY(event_, iIndex);
278 
279  v = lug::Math::Vec2f{x, y};
280 
281  return true;
282 }
283 
284 } // namespace ndkHelper
const int32_t TAP_TIMEOUT
virtual GESTURE_STATE Detect(const AInputEvent *event)
const int32_t DOUBLE_TAP_SLOP
virtual GESTURE_STATE Detect(const AInputEvent *motion_event)
const int32_t TOUCH_SLOP
bool GetPointers(lug::Math::Vec2f &v1, lug::Math::Vec2f &v2)
virtual GESTURE_STATE Detect(const AInputEvent *event)
int32_t GESTURE_STATE
virtual GESTURE_STATE Detect(const AInputEvent *motion_event)
int32_t FindIndex(const AInputEvent *event, int32_t id)
virtual void SetConfiguration(AConfiguration *config)
virtual void SetConfiguration(AConfiguration *config)
bool GetPointer(lug::Math::Vec2f &v)
int32_t FindIndex(const AInputEvent *event, int32_t id)
const int32_t DOUBLE_TAP_TIMEOUT