Merge lp:~dandrader/grail/lp949916 into lp:grail
- lp949916
- Merge into trunk
Status: | Merged |
---|---|
Merge reported by: | Daniel d'Andrada |
Merged at revision: | not available |
Proposed branch: | lp:~dandrader/grail/lp949916 |
Merge into: | lp:grail |
Diff against target: |
2681 lines (+1881/-475) 17 files modified
src/Makefile.am (+4/-0) src/v3/atomic-recognizer.cpp (+308/-0) src/v3/atomic-recognizer.h (+52/-0) src/v3/forward.h (+14/-1) src/v3/gesture.cpp (+39/-1) src/v3/gesture.h (+5/-0) src/v3/handle.cpp (+29/-5) src/v3/handle.h (+1/-0) src/v3/log.cpp (+4/-0) src/v3/log.h (+4/-0) src/v3/recognizer.cpp (+11/-453) src/v3/recognizer.h (+33/-15) src/v3/regular-recognizer.cpp (+396/-0) src/v3/regular-recognizer.h (+52/-0) test/Makefile.am (+1/-0) test/recordings/apple-wtrackpad-synced-4-drag.event (+713/-0) test/x11/no-premature-gestures.cpp (+215/-0) |
To merge this branch: | bzr merge lp:~dandrader/grail/lp949916 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Chase Douglas (community) | Approve | ||
Review via email: mp+97408@code.launchpad.net |
This proposal supersedes a proposal from 2012-03-13.
Commit message
Description of the change
Don't emit Touch slices prematurely with atomic rules (LP #949916)
With atomic gesture rules being used, even when, say, 4 touches were coming with the very same timestamp, gestures for 2 and then 3 touches were being created and ended before the fourth touch finally got processed.
This branch first splits Recognizer into AtomicRecognizer and RegularRecognizer. Then it fixes the bug by wainting kCompositionTime before accepting a gesture in the AtomicRecognizer.
It also doesn't send slices from a gesture until it gets accepted. This ensures that Grail clients using subscriptions with atomic gestures rules won't get noise from gestures that won't be accepted in the end.
Chase Douglas (chasedouglas) wrote : Posted in a previous version of this proposal | # |
Daniel d'Andrada (dandrader) wrote : | # |
Updated according to review comments.
- 196. By Daniel d'Andrada
-
Merged "Erase ended touches from start_times_ map"
Chase Douglas (chasedouglas) wrote : | # |
* I'm confused about what the correct Unity guidelines are for C++ code, which we use for utouch-grail and utouch-frame. It appears the style has changed without notification. For now, I'm going to overlook any style issues.
* I'm not crazy about the name SetKeepSlicesEn
Everything else looks good! If you change the keep slices method name as suggested, feel free to merge :).
- 197. By Daniel d'Andrada
-
Refactoring v3/Recognizer. Split into Regular and Atomic recognizers
Instead of having many "if (atomic_)" sprinkled throughout the code, have
two recognizers: of for atomic gesture rules and another for regular rules.That will also make the atomic gestures code flow easier to understand and
tune. Likewise for regular rules. - 198. By Daniel d'Andrada
-
Atomic rules: Don't send slices from premature gestures. (lp:949916)
Wait a bit until accepting a gesture to avoid premature gestures that
will immediately get cancelled due to the apparition of a new touch
point on the following events.
e.g. like when a user puts four fingers on a touch screen but
the corresponding touch points come in separate events (because fingers
don't land precisely in sync and/or UTouch frame doesn't process their
arrivals in the very same event). We should generate only the "final"
4-touches' gesture and not the intermediates 2-touches and 3-touches
gestures. - 199. By Daniel d'Andrada
-
Regression test for lp:949916
Check that, when using atomic gestures, we don't get
premature slices of 2 or 3 touches when a roughly synced 4-fingers'
gesture is performed.
Preview Diff
1 | === modified file 'src/Makefile.am' |
2 | --- src/Makefile.am 2012-02-01 16:24:12 +0000 |
3 | +++ src/Makefile.am 2012-03-14 19:17:21 +0000 |
4 | @@ -38,6 +38,8 @@ |
5 | if HAVE_XI |
6 | v3dir = v3 |
7 | libutouch_grail_la_SOURCES += \ |
8 | + v3/atomic-recognizer.cpp \ |
9 | + v3/atomic-recognizer.h \ |
10 | v3/event.cpp \ |
11 | v3/event.h \ |
12 | v3/forward.h \ |
13 | @@ -49,6 +51,8 @@ |
14 | v3/log.h \ |
15 | v3/recognizer.cpp \ |
16 | v3/recognizer.h \ |
17 | + v3/regular-recognizer.cpp \ |
18 | + v3/regular-recognizer.h \ |
19 | v3/slice.cpp \ |
20 | v3/slice.h \ |
21 | v3/subscription.cpp \ |
22 | |
23 | === added file 'src/v3/atomic-recognizer.cpp' |
24 | --- src/v3/atomic-recognizer.cpp 1970-01-01 00:00:00 +0000 |
25 | +++ src/v3/atomic-recognizer.cpp 2012-03-14 19:17:21 +0000 |
26 | @@ -0,0 +1,308 @@ |
27 | +/***************************************************************************** |
28 | + * |
29 | + * grail - Gesture Recognition And Instantiation Library |
30 | + * |
31 | + * Copyright (C) 2012 Canonical Ltd. |
32 | + * |
33 | + * This program is free software: you can redistribute it and/or modify it |
34 | + * under the terms of the GNU General Public License as published by the |
35 | + * Free Software Foundation, either version 3 of the License, or (at your |
36 | + * option) any later version. |
37 | + * |
38 | + * This program is distributed in the hope that it will be useful, but |
39 | + * WITHOUT ANY WARRANTY; without even the implied warranty of |
40 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
41 | + * General Public License for more details. |
42 | + * |
43 | + * You should have received a copy of the GNU General Public License along |
44 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
45 | + * |
46 | + ****************************************************************************/ |
47 | + |
48 | +#include "v3/atomic-recognizer.h" |
49 | + |
50 | +#include <algorithm> |
51 | +#include <cassert> |
52 | +#include <cstdint> |
53 | +#include <cstdio> |
54 | +#include <limits> |
55 | + |
56 | +#include <utouch/frame.h> |
57 | +#include <utouch/frame_x11.h> |
58 | + |
59 | +#include "v3/handle.h" |
60 | +#include "v3/gesture.h" |
61 | +#include "v3/log.h" |
62 | + |
63 | +namespace { |
64 | +const uint64_t MAX_TOUCHES_FOR_GESTURES = 5; |
65 | +} // namespace |
66 | + |
67 | +namespace utouch { |
68 | +namespace grail { |
69 | + |
70 | +/** |
71 | + * @internal |
72 | + * Create a new atomic recognizer for a given device and window |
73 | + */ |
74 | +AtomicRecognizer::AtomicRecognizer(UGHandle* handle, const UFDevice device, UFWindowId window) |
75 | + : Recognizer(handle, device, window) { |
76 | +} |
77 | + |
78 | +/** |
79 | + * @internal |
80 | + * Process a uTouch-Frame event |
81 | + */ |
82 | +void AtomicRecognizer::ProcessFrameEvent(const UFEvent event) { |
83 | + LOG(Dbg) << "new event " << event << " with time " |
84 | + << frame_event_get_time(event) << "\n"; |
85 | + |
86 | + uint64_t event_time = frame_event_get_time(event); |
87 | + |
88 | + UpdateTime(event_time); |
89 | + CollectNewTouches(event); |
90 | + if (new_touches_.size() > 0) { |
91 | + /* process all new touches at once to avoid the premature initiation of |
92 | + gestures for less touches than what the event brings */ |
93 | + MatchSubscriptionsForNewTouches(); |
94 | + } |
95 | + ProcessEvent(event); |
96 | + FindGestureToAccept(event_time); |
97 | +} |
98 | + |
99 | +/** |
100 | + * @internal |
101 | + * Perform tasks necessary for when new touches occur and there is an existing |
102 | + * accepted gesture |
103 | + * |
104 | + * If a gesture may add touches without crossing the maximum for the |
105 | + * subscription, add the touches to the gesture and accept them. Otherwise, end |
106 | + * the gesture and add the current gesture touches to the free touches list. |
107 | + */ |
108 | +void AtomicRecognizer::HandleNewTouchesForAcceptedGesture(const SharedGesture& gesture) { |
109 | + UGSubscription* subscription = gesture->subscription(); |
110 | + if (gesture->touches().size() + new_touches_.size() <= subscription->touches_max()) { |
111 | + gesture->AddTouches(new_touches_); |
112 | + LOG(Dbg) << "new_touches_ have been added to atomic gesture " |
113 | + << gesture->id() << "\n"; |
114 | + |
115 | + for (UFTouchId touch_id : new_touches_) { |
116 | + if (frame_x11_accept_touch(device_, window_id_, touch_id) != |
117 | + UFStatusSuccess) |
118 | + LOG(Err) << "touch " << touch_id << " failed to be accepted\n"; |
119 | + |
120 | + LOG(Dbg) << "touch " << touch_id |
121 | + << " has been accepted because it has been added to an atomic gesture\n"; |
122 | + |
123 | + INSERT_TOUCH(touch_id, accepted_touches_); |
124 | + ERASE_TOUCH(touch_id, unaccepted_touches_); |
125 | + ERASE_TOUCH(touch_id, free_touches_); |
126 | + } |
127 | + CLEAR_TOUCHES(new_touches_); |
128 | + } else { |
129 | + for (UFTouchId touch : gesture->touches()) |
130 | + INSERT_TOUCH(touch, free_touches_); |
131 | + gesture->End(); |
132 | + LOG(Dbg) << "ended active atomic gesture " << gesture->id() |
133 | + << " because " << new_touches_.size() << " new touch(es) began and the " |
134 | + "max touches has been reached\n"; |
135 | + accepted_gestures_.erase(gesture); |
136 | + } |
137 | +} |
138 | + |
139 | +/** |
140 | + * @internal |
141 | + * Perform tasks necessary for when new touches occur and there is an existing |
142 | + * unaccepted gesture |
143 | + * |
144 | + * If a gesture may receive the new touches without crossing the maximum for |
145 | + * the subscription, add the touches to the gesture. Otherwise, cancel the |
146 | + * gesture and add the current gesture touches to the free touches list. |
147 | + */ |
148 | +void AtomicRecognizer::HandleNewTouchesForUnacceptedGesture( |
149 | + const SharedGesture& gesture) { |
150 | + UGSubscription* subscription = gesture->subscription(); |
151 | + if (gesture->touches().size() + new_touches_.size() <= subscription->touches_max()) { |
152 | + for (UFTouchId touch_id : new_touches_) { |
153 | + gesture->AddTouch(touch_id); |
154 | + LOG(Dbg) << "touch " << touch_id << " has been added to atomic gesture " |
155 | + << gesture->id() << "\n"; |
156 | + } |
157 | + } else { |
158 | + for (UFTouchId touch_id : gesture->touches()) |
159 | + INSERT_TOUCH(touch_id, free_touches_); |
160 | + gesture->Cancel(); |
161 | + LOG(Dbg) << "canceled inactive atomic gesture " << gesture->id() |
162 | + << " because a new touch began and the max touches has been " |
163 | + << "reached\n"; |
164 | + unaccepted_gestures_.erase(gesture); |
165 | + } |
166 | +} |
167 | + |
168 | +/** |
169 | + * @internal |
170 | + * Register all new touches present in the given uTouch-Frame event. |
171 | + */ |
172 | +void AtomicRecognizer::CollectNewTouches(const UFEvent event) { |
173 | + /* Check if any subscriptions are active before doing any processing */ |
174 | + if (num_subscriptions_ == 0) |
175 | + return; |
176 | + |
177 | + UFFrame frame; |
178 | + UFStatus status = frame_event_get_property(event, UFEventPropertyFrame, |
179 | + &frame); |
180 | + if (status != UFStatusSuccess) { |
181 | + LOG(Warn) << "failed to get frame from event\n"; |
182 | + return; |
183 | + } |
184 | + |
185 | + unsigned int num_touches = frame_frame_get_num_touches(frame); |
186 | + uint64_t touch_start_time; |
187 | + UFTouchId touch_id; |
188 | + for (unsigned int i = 0; i < num_touches; ++i) { |
189 | + UFTouch touch; |
190 | + status = frame_frame_get_touch_by_index(frame, i, &touch); |
191 | + if (status != UFStatusSuccess) { |
192 | + LOG(Warn) << "failed to get touch from frame\n"; |
193 | + continue; |
194 | + } |
195 | + |
196 | + touch_id = frame_touch_get_id(touch); |
197 | + |
198 | + switch (frame_touch_get_state(touch)) { |
199 | + case UFTouchStateBegin: |
200 | + touch_start_time = frame_touch_get_start_time(touch); |
201 | + |
202 | + /* Note touch start time and add to initial touch lists */ |
203 | + start_times_[touch_id] = touch_start_time; |
204 | + LOG(Dbg) << "touch " << touch_id << " began with start time " |
205 | + << start_times_[touch_id] << "\n"; |
206 | + |
207 | + INSERT_TOUCH(touch_id, new_touches_); |
208 | + break; |
209 | + |
210 | + case UFTouchStateEnd: |
211 | + ERASE_TOUCH(touch_id, new_touches_); |
212 | + break; |
213 | + |
214 | + default: |
215 | + break; |
216 | + } |
217 | + } |
218 | +} |
219 | + |
220 | +/** |
221 | + * @internal |
222 | + * Consume the new touches. |
223 | + * Check if any new atomic gestures should begin because of the new touches |
224 | + * that came. |
225 | + */ |
226 | +void AtomicRecognizer::MatchSubscriptionsForNewTouches() { |
227 | + /* Check if any subscriptions are active before doing any processing */ |
228 | + if (num_subscriptions_ == 0) |
229 | + return; |
230 | + |
231 | + // The new touches can now be used |
232 | + for (UFTouchId touch_id : new_touches_) { |
233 | + INSERT_TOUCH(touch_id, unaccepted_touches_); |
234 | + INSERT_TOUCH(touch_id, free_touches_); |
235 | + } |
236 | + |
237 | + // Under atomic gestures rules there can be only one accepted gesture |
238 | + assert(accepted_gestures_.size() <= 1); |
239 | + if (accepted_gestures_.size() != 0) { |
240 | + const SharedGesture& gesture = *accepted_gestures_.begin(); |
241 | + HandleNewTouchesForAcceptedGesture(gesture); |
242 | + } |
243 | + |
244 | + if (new_touches_.size() == 0) { |
245 | + // they've all been consumed by the accepted gesture. |
246 | + return; |
247 | + } |
248 | + |
249 | + /* HandleNewTouchForUnacceptedGesture may erase the gesture from |
250 | + * accepted_gestures_, so we can't use range-based for loops */ |
251 | + for (auto it = unaccepted_gestures_.begin(); |
252 | + it != unaccepted_gestures_.end(); |
253 | + ) { |
254 | + const SharedGesture& gesture = *it++; |
255 | + HandleNewTouchesForUnacceptedGesture(gesture); |
256 | + } |
257 | + |
258 | + MatchGestures(); |
259 | + CLEAR_TOUCHES(new_touches_); |
260 | +} |
261 | + |
262 | +void AtomicRecognizer::MatchGestures() { |
263 | + if (free_touches_.size() == 0 |
264 | + || free_touches_.size() > MAX_TOUCHES_FOR_GESTURES) |
265 | + return; |
266 | + |
267 | + uint64_t min_start_time = std::numeric_limits<uint64_t>::max(); |
268 | + uint64_t max_start_time = 0; |
269 | + for (UFTouchId touch_id : free_touches_) { |
270 | + if (unaccepted_touches_.find(touch_id) == unaccepted_touches_.end()) |
271 | + continue; |
272 | + |
273 | + if (start_times_[touch_id] < min_start_time) |
274 | + min_start_time = start_times_[touch_id]; |
275 | + |
276 | + if (start_times_[touch_id] > max_start_time) |
277 | + max_start_time = start_times_[touch_id]; |
278 | + } |
279 | + |
280 | + /* All touches in a gesture must begin within a composition timeframe */ |
281 | + if ((max_start_time - min_start_time) >= kCompositionTime) |
282 | + return; |
283 | + |
284 | + for (UGSubscription* subscription : subscriptions_[free_touches_.size()-1]) { |
285 | + Gesture* gesture = new Gesture(this, subscription, free_touches_, |
286 | + max_start_time); |
287 | + |
288 | + /* hold slice events until we accept the gesture */ |
289 | + gesture->SetKeepSlices(true); |
290 | + |
291 | + unaccepted_gestures_.insert(SharedGesture(gesture)); |
292 | + |
293 | + LOG(Dbg) << "New tentative gesture " << gesture->id() |
294 | + << " matched subscription " << subscription << " with mask " |
295 | + << subscription->mask() << " for touches " << free_touches_.ToString() |
296 | + << std::endl; |
297 | + } |
298 | +} |
299 | + |
300 | +void AtomicRecognizer::FindGestureToAccept(uint64_t event_time) |
301 | +{ |
302 | + uint64_t delta_time; |
303 | + for (auto it = unaccepted_gestures_.begin(); |
304 | + it != unaccepted_gestures_.end(); |
305 | + ) { |
306 | + const SharedGesture& gesture = *it++; |
307 | + |
308 | + delta_time = event_time - gesture->start_time(); |
309 | + |
310 | + /* Atomic gestures must be accepted if they meet the subscription |
311 | + criteria. |
312 | + Wait a bit until accepting them to avoid premature gestures that |
313 | + will immediately get cancelled due to the apparition of a new touch |
314 | + point on the following events. |
315 | + e.g. like when a user puts four fingers on a touch screen but |
316 | + the corresponding touch points come in separate events (because fingers |
317 | + don't land precisely in sync and/or UTouch frame doesn't process their |
318 | + arrivals in the very same event). We should generate only the "final" |
319 | + 4-touches' gesture and not the intermediates 2-touches and 3-touches |
320 | + gestures. |
321 | + */ |
322 | + if (gesture->IsActive() && delta_time > 0 |
323 | + && delta_time >= kCompositionTime) { |
324 | + |
325 | + gesture->SetKeepSlices(false); |
326 | + |
327 | + LOG(Dbg) << "accepting active atomic gesture " << gesture->id() << "\n"; |
328 | + AcceptGesture(gesture->id()); |
329 | + } |
330 | + } |
331 | +} |
332 | + |
333 | +} // namespace grail |
334 | +} // namespace utouch |
335 | |
336 | === added file 'src/v3/atomic-recognizer.h' |
337 | --- src/v3/atomic-recognizer.h 1970-01-01 00:00:00 +0000 |
338 | +++ src/v3/atomic-recognizer.h 2012-03-14 19:17:21 +0000 |
339 | @@ -0,0 +1,52 @@ |
340 | +/***************************************************************************** |
341 | + * |
342 | + * grail - Gesture Recognition And Instantiation Library |
343 | + * |
344 | + * Copyright (C) 2012 Canonical Ltd. |
345 | + * |
346 | + * This program is free software: you can redistribute it and/or modify it |
347 | + * under the terms of the GNU General Public License as published by the |
348 | + * Free Software Foundation, either version 3 of the License, or (at your |
349 | + * option) any later version. |
350 | + * |
351 | + * This program is distributed in the hope that it will be useful, but |
352 | + * WITHOUT ANY WARRANTY; without even the implied warranty of |
353 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
354 | + * General Public License for more details. |
355 | + * |
356 | + * You should have received a copy of the GNU General Public License along |
357 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
358 | + * |
359 | + ****************************************************************************/ |
360 | + |
361 | +#ifndef UTOUCH_GRAIL_ATOMIC_RECOGNIZER_H_ |
362 | +#define UTOUCH_GRAIL_ATOMIC_RECOGNIZER_H_ |
363 | + |
364 | +#include "v3/recognizer.h" |
365 | + |
366 | +namespace utouch { |
367 | +namespace grail { |
368 | + |
369 | +class AtomicRecognizer : public Recognizer { |
370 | + public: |
371 | + AtomicRecognizer(UGHandle* handle, const UFDevice device, UFWindowId window); |
372 | + |
373 | + virtual bool atomic() const {return true;} |
374 | + virtual void ProcessFrameEvent(const UFEvent event); |
375 | + |
376 | + private: |
377 | + void HandleNewTouchesForAcceptedGesture(const SharedGesture& gesture); |
378 | + void HandleNewTouchesForUnacceptedGesture(const SharedGesture& gesture); |
379 | + void CollectNewTouches(const UFEvent event); |
380 | + void MatchSubscriptionsForNewTouches(); |
381 | + void MatchGestures(); |
382 | + void FindGestureToAccept(uint64_t event_time); |
383 | + |
384 | + // Touches that have begun but not yet been matched against subscriptions |
385 | + // (for the creation of new gestures) or used to update existing gestures. |
386 | + TouchSet new_touches_; |
387 | +}; |
388 | + |
389 | +} // namespace grail |
390 | +} // namespace utouch |
391 | +#endif |
392 | |
393 | === modified file 'src/v3/forward.h' |
394 | --- src/v3/forward.h 2011-11-25 18:11:49 +0000 |
395 | +++ src/v3/forward.h 2012-03-14 19:17:21 +0000 |
396 | @@ -24,6 +24,7 @@ |
397 | |
398 | #include <memory> |
399 | #include <set> |
400 | +#include <sstream> |
401 | |
402 | #include <utouch/frame.h> |
403 | |
404 | @@ -48,7 +49,19 @@ |
405 | class UGSubscription; |
406 | typedef std::shared_ptr<UGSubscription> SharedUGSubscription; |
407 | |
408 | -typedef std::set<UFTouchId> TouchSet; |
409 | +class TouchSet : public std::set<UFTouchId> { |
410 | + |
411 | +public: |
412 | + std::string ToString() const { |
413 | + std::ostringstream stream; |
414 | + auto it = begin(); |
415 | + if (it != end()) |
416 | + stream << *it++; |
417 | + while (it != end()) |
418 | + stream << ", " << *it++; |
419 | + return stream.str(); |
420 | + } |
421 | +}; |
422 | |
423 | } // namespace grail |
424 | } // namespace utouch |
425 | |
426 | === modified file 'src/v3/gesture.cpp' |
427 | --- src/v3/gesture.cpp 2012-02-15 04:36:48 +0000 |
428 | +++ src/v3/gesture.cpp 2012-03-14 19:17:21 +0000 |
429 | @@ -51,7 +51,8 @@ |
430 | not_owned_(false), |
431 | recognized_(0), |
432 | canceled_(false), |
433 | - ended_(false) { |
434 | + ended_(false), |
435 | + keep_slices_(false) { |
436 | } |
437 | |
438 | /** |
439 | @@ -83,6 +84,23 @@ |
440 | |
441 | /** |
442 | * @internal |
443 | + * Add a new set of touches to an existing gesture. |
444 | + */ |
445 | +void Gesture::AddTouches(TouchSet touch_set) { |
446 | + current_touches_.insert(touch_set.begin(), touch_set.end()); |
447 | + unowned_touches_.insert(touch_set.begin(), touch_set.end()); |
448 | +} |
449 | + |
450 | +/** |
451 | + * @internal |
452 | + * Returns whether that gesture contains the given touch. |
453 | + */ |
454 | +bool Gesture::ContainsTouch(UFTouchId touch_id) const { |
455 | + return current_touches_.find(touch_id) != current_touches_.end(); |
456 | +} |
457 | + |
458 | +/** |
459 | + * @internal |
460 | * Update a gesture with the passed in frame event and list of modified touches |
461 | */ |
462 | void Gesture::Update(UFEvent frame_event, TouchSet& modified_touches) { |
463 | @@ -298,6 +316,9 @@ |
464 | * @internal |
465 | * Flush all pending gesture slices to the client as grail events */ |
466 | void Gesture::FlushSlices() { |
467 | + if (keep_slices_) |
468 | + return; |
469 | + |
470 | while (!slices_.empty()) { |
471 | UGEvent* event = new UGEvent(slices_.front()); |
472 | slices_.front()->ReferenceGesture(); |
473 | @@ -373,5 +394,22 @@ |
474 | unowned_touches_.clear(); |
475 | } |
476 | |
477 | +/** |
478 | + * @internal |
479 | + * If true, FlushSlices() will have no effect. The Gesture will keep all its |
480 | + * slices until this property is disabled again, which will cause all pending |
481 | + * slices to be flushed. |
482 | + * |
483 | + * By default, this property is false. */ |
484 | +void Gesture::SetKeepSlices(bool keep_slices) |
485 | +{ |
486 | + if (keep_slices_ && !keep_slices) { |
487 | + keep_slices_ = keep_slices; |
488 | + FlushSlices(); |
489 | + } else { |
490 | + keep_slices_ = keep_slices; |
491 | + } |
492 | +} |
493 | + |
494 | } // namespace grail |
495 | } // namespace utouch |
496 | |
497 | === modified file 'src/v3/gesture.h' |
498 | --- src/v3/gesture.h 2012-02-15 04:36:48 +0000 |
499 | +++ src/v3/gesture.h 2012-03-14 19:17:21 +0000 |
500 | @@ -42,6 +42,8 @@ |
501 | Gesture(const Gesture* gesture, TouchSet& touches); |
502 | |
503 | void AddTouch(UFTouchId touch_id); |
504 | + void AddTouches(TouchSet touch_set); |
505 | + bool ContainsTouch(UFTouchId touch_id) const; |
506 | void Update(UFEvent event, TouchSet& touches); |
507 | bool IsActive() const; |
508 | bool IsConstructionFinished() const; |
509 | @@ -63,6 +65,8 @@ |
510 | Gesture(const Gesture&) = delete; |
511 | Gesture& operator=(const Gesture&) = delete; |
512 | |
513 | + void SetKeepSlices(bool keep_slices); |
514 | + |
515 | private: |
516 | void CheckOwned(); |
517 | void FlushSlices(); |
518 | @@ -81,6 +85,7 @@ |
519 | bool canceled_; |
520 | bool ended_; |
521 | std::map<UFTouchId, float> angles_; |
522 | + bool keep_slices_; |
523 | }; |
524 | |
525 | } // namespace grail |
526 | |
527 | === modified file 'src/v3/handle.cpp' |
528 | --- src/v3/handle.cpp 2012-01-21 00:00:16 +0000 |
529 | +++ src/v3/handle.cpp 2012-03-14 19:17:21 +0000 |
530 | @@ -32,9 +32,10 @@ |
531 | |
532 | #include <utouch/frame_x11.h> |
533 | |
534 | +#include "v3/atomic-recognizer.h" |
535 | #include "v3/event.h" |
536 | #include "v3/log.h" |
537 | -#include "v3/recognizer.h" |
538 | +#include "v3/regular-recognizer.h" |
539 | #include "v3/subscription.h" |
540 | |
541 | namespace utouch { |
542 | @@ -49,6 +50,25 @@ |
543 | } |
544 | } |
545 | |
546 | +Recognizer *UGHandle::CreateRecognizerForSubscription( |
547 | + UGSubscription* subscription) { |
548 | + Recognizer* recognizer; |
549 | + |
550 | + if (subscription->atomic()) |
551 | + recognizer = new AtomicRecognizer(this, |
552 | + subscription->device(), |
553 | + subscription->window_id()); |
554 | + else |
555 | + recognizer = new RegularRecognizer(this, |
556 | + subscription->device(), |
557 | + subscription->window_id()); |
558 | + |
559 | + recognizers_[subscription->device()][subscription->window_id()] = |
560 | + std::move(UniqueRecognizer(recognizer)); |
561 | + |
562 | + return recognizer; |
563 | +} |
564 | + |
565 | UGStatus UGHandle::ActivateSubscription(UGSubscription* subscription) { |
566 | Recognizer* recognizer; |
567 | |
568 | @@ -59,11 +79,15 @@ |
569 | recognizers_[subscription->device()].find(subscription->window_id()); |
570 | if (it != recognizers_[subscription->device()].end()) { |
571 | recognizer = it->second.get(); |
572 | + |
573 | + if (recognizer->atomic() != subscription->atomic() |
574 | + && recognizer->num_subscriptions() == 0) { |
575 | + // Fix the mismatch |
576 | + recognizer = CreateRecognizerForSubscription(subscription); |
577 | + } |
578 | + |
579 | } else { |
580 | - recognizer = new Recognizer(this, subscription->device(), |
581 | - subscription->window_id()); |
582 | - recognizers_[subscription->device()][subscription->window_id()] = |
583 | - std::move(UniqueRecognizer(recognizer)); |
584 | + recognizer = CreateRecognizerForSubscription(subscription); |
585 | } |
586 | |
587 | return recognizer->ActivateSubscription(subscription); |
588 | |
589 | === modified file 'src/v3/handle.h' |
590 | --- src/v3/handle.h 2011-11-29 20:13:02 +0000 |
591 | +++ src/v3/handle.h 2012-03-14 19:17:21 +0000 |
592 | @@ -43,6 +43,7 @@ |
593 | ~UGHandle(); |
594 | |
595 | int event_fd() const { return event_fd_; } |
596 | + Recognizer *CreateRecognizerForSubscription(UGSubscription* subscription); |
597 | UGStatus ActivateSubscription(UGSubscription* subscription); |
598 | void DeactivateSubscription(UGSubscription* subscription); |
599 | unsigned int NewGestureID(Recognizer* recognizer); |
600 | |
601 | === modified file 'src/v3/log.cpp' |
602 | --- src/v3/log.cpp 2012-01-06 20:00:08 +0000 |
603 | +++ src/v3/log.cpp 2012-03-14 19:17:21 +0000 |
604 | @@ -59,5 +59,9 @@ |
605 | } |
606 | } |
607 | |
608 | +Logger& Logger::instance() { |
609 | + return logger; |
610 | +} |
611 | + |
612 | } // namespace grail |
613 | } // namespace utouch |
614 | |
615 | === modified file 'src/v3/log.h' |
616 | --- src/v3/log.h 2012-01-06 20:00:08 +0000 |
617 | +++ src/v3/log.h 2012-03-14 19:17:21 +0000 |
618 | @@ -44,6 +44,10 @@ |
619 | |
620 | static std::ostream& Log(Level level); |
621 | |
622 | + static Logger& instance(); |
623 | + |
624 | + Level level() const {return static_cast<Level>(level_);}; |
625 | + |
626 | private: |
627 | int level_; |
628 | NullStreamBuf null_buf_; |
629 | |
630 | === modified file 'src/v3/recognizer.cpp' |
631 | --- src/v3/recognizer.cpp 2012-03-14 14:54:09 +0000 |
632 | +++ src/v3/recognizer.cpp 2012-03-14 19:17:21 +0000 |
633 | @@ -22,6 +22,7 @@ |
634 | #include "v3/recognizer.h" |
635 | |
636 | #include <algorithm> |
637 | +#include <cassert> |
638 | #include <cstdint> |
639 | #include <cstdio> |
640 | #include <limits> |
641 | @@ -33,27 +34,11 @@ |
642 | #include "v3/gesture.h" |
643 | #include "v3/log.h" |
644 | |
645 | -#define INSERT_TOUCH(element, set) \ |
646 | - { \ |
647 | - (set).insert(element); \ |
648 | - LOG(Dbg) << "touch " << element << " has been added to " #set "\n"; \ |
649 | - } |
650 | - |
651 | -#define ERASE_TOUCH(element, set) \ |
652 | - { \ |
653 | - (set).erase(element); \ |
654 | - LOG(Dbg) << "touch " << element << " has been erased from " #set "\n"; \ |
655 | - } |
656 | - |
657 | -namespace { |
658 | - |
659 | -const uint64_t COMPOSITION_TIME = 60; |
660 | - |
661 | -} // namespace |
662 | - |
663 | namespace utouch { |
664 | namespace grail { |
665 | |
666 | +uint64_t Recognizer::kCompositionTime = 60; |
667 | + |
668 | /** |
669 | * @internal |
670 | * Create a new recognizer for a given device and window |
671 | @@ -64,7 +49,6 @@ |
672 | device_(device), |
673 | window_id_(window_id), |
674 | device_direct_(true), |
675 | - atomic_(false), |
676 | num_subscriptions_(0) { |
677 | /* Save direct property for gesture processing */ |
678 | UFStatus status = frame_device_get_property(device, UFDevicePropertyDirect, |
679 | @@ -107,13 +91,11 @@ |
680 | */ |
681 | UGStatus Recognizer::ActivateSubscription(UGSubscription* subscription) { |
682 | /* All the subscriptions must be atomic or non-atomic, mixes break things */ |
683 | - for (auto subscriptions : subscriptions_) |
684 | - if (subscriptions.size() > 0 && subscription->atomic() != atomic_) |
685 | + if (subscription->atomic() != atomic()) |
686 | return UGStatusErrorAtomicity; |
687 | |
688 | /* Save the subscription and update atomicity */ |
689 | subscriptions_[subscription->touches_start() - 1].insert(subscription); |
690 | - atomic_ = subscription->atomic(); |
691 | num_subscriptions_++; |
692 | |
693 | return UGStatusSuccess; |
694 | @@ -157,425 +139,6 @@ |
695 | num_subscriptions_--; |
696 | } |
697 | |
698 | -/** |
699 | - * @internal |
700 | - * Process a uTouch-Frame event |
701 | - */ |
702 | -void Recognizer::ProcessFrameEvent(const UFEvent event) { |
703 | - LOG(Dbg) << "new event " << event << " with time " |
704 | - << frame_event_get_time(event) << "\n"; |
705 | - UpdateTime(frame_event_get_time(event)); |
706 | - MatchSubscriptionsForEvent(event); |
707 | - ProcessEvent(event); |
708 | -} |
709 | - |
710 | -/** |
711 | - * @internal |
712 | - * Analyze a uTouch-Frame event to see if any new gestures should begin |
713 | - */ |
714 | -void Recognizer::MatchSubscriptionsForEvent(const UFEvent event) { |
715 | - /* Check if any subscriptions are active before doing any processing */ |
716 | - if (num_subscriptions_ == 0) |
717 | - return; |
718 | - |
719 | - UFFrame frame; |
720 | - UFStatus status = frame_event_get_property(event, UFEventPropertyFrame, |
721 | - &frame); |
722 | - if (status != UFStatusSuccess) { |
723 | - LOG(Warn) << "failed to get frame from event\n"; |
724 | - return; |
725 | - } |
726 | - |
727 | - /* Process all the touches that began in this frame */ |
728 | - unsigned int num_touches = frame_frame_get_num_touches(frame); |
729 | - for (unsigned int i = 0; i < num_touches; ++i) { |
730 | - UFTouch touch; |
731 | - status = frame_frame_get_touch_by_index(frame, i, &touch); |
732 | - if (status != UFStatusSuccess) { |
733 | - LOG(Warn) << "failed to get touch from frame\n"; |
734 | - continue; |
735 | - } |
736 | - |
737 | - if (frame_touch_get_state(touch) != UFTouchStateBegin) |
738 | - continue; |
739 | - |
740 | - UFTouchId touch_id = frame_touch_get_id(touch); |
741 | - |
742 | - /* Note touch start time and add to initial touch lists */ |
743 | - start_times_[touch_id] = frame_touch_get_start_time(touch); |
744 | - LOG(Dbg) << "touch " << touch_id << " began with start time " |
745 | - << start_times_[touch_id] << "\n"; |
746 | - |
747 | - INSERT_TOUCH(touch_id, unaccepted_touches_); |
748 | - INSERT_TOUCH(touch_id, free_touches_); |
749 | - |
750 | - /* HandleNewTouchForAcceptedGesture may erase the gesture from |
751 | - * accepted_gestures_, so we can't use range-based for loops */ |
752 | - for (auto it = accepted_gestures_.begin(); |
753 | - it != accepted_gestures_.end(); |
754 | - ) { |
755 | - const SharedGesture& gesture = *it++; |
756 | - HandleNewTouchForAcceptedGesture(touch_id, gesture); |
757 | - } |
758 | - |
759 | - /* HandleNewTouchForAcceptedGesture may erase the gesture from |
760 | - * accepted_gestures_, so we can't use range-based for loops */ |
761 | - for (auto it = unaccepted_gestures_.begin(); |
762 | - it != unaccepted_gestures_.end(); |
763 | - ) { |
764 | - const SharedGesture& gesture = *it++; |
765 | - HandleNewTouchForUnacceptedGesture(touch_id, gesture); |
766 | - } |
767 | - |
768 | - /* Attempt to match new gestures for active subscriptions */ |
769 | - MatchOneTouchGestures(touch_id); |
770 | - MatchTwoTouchGestures(touch_id); |
771 | - MatchThreeTouchGestures(touch_id); |
772 | - MatchFourTouchGestures(touch_id); |
773 | - MatchFiveTouchGestures(touch_id); |
774 | - } |
775 | -} |
776 | - |
777 | -/** |
778 | - * @internal |
779 | - * Perform tasks necessary for when a new touch occurs and there is an existing |
780 | - * accepted gesture |
781 | - * |
782 | - * Under normal processing: |
783 | - * If a gesture may add a touch without crossing the maximum for the |
784 | - * subscription, create a new unaccepted gesture with the new touch. |
785 | - * Otherwise, do nothing. New gestures may still begin elsewhere. |
786 | - * |
787 | - * Under atomic gesture processing: |
788 | - * If a gesture may add a touch without crossing the maximum for the |
789 | - * subscription, add the touch to the gesture and accept it. Otherwise, end |
790 | - * the gesture and add the current gesture touches to the free touches list. |
791 | - */ |
792 | -void Recognizer::HandleNewTouchForAcceptedGesture( |
793 | - UFTouchId touch_id, |
794 | - const SharedGesture& gesture) { |
795 | - UGSubscription* subscription = gesture->subscription(); |
796 | - if (gesture->touches().size() < subscription->touches_max()) { |
797 | - if (atomic_) { |
798 | - gesture->AddTouch(touch_id); |
799 | - LOG(Dbg) << "touch " << touch_id << " has been added to atomic gesture " |
800 | - << gesture->id() << "\n"; |
801 | - if (frame_x11_accept_touch(device_, window_id_, touch_id) != |
802 | - UFStatusSuccess) |
803 | - LOG(Err) << "touch " << touch_id << " failed to be accepted\n"; |
804 | - LOG(Dbg) << "touch " << touch_id |
805 | - << " has been accepted because it has been added to an atomic " |
806 | - "gesture"; |
807 | - INSERT_TOUCH(touch_id, accepted_touches_); |
808 | - ERASE_TOUCH(touch_id, unaccepted_touches_); |
809 | - ERASE_TOUCH(touch_id, free_touches_); |
810 | - } else { |
811 | - TouchSet set(gesture->touches()); |
812 | - set.insert(touch_id); |
813 | - Gesture* new_gesture = new Gesture(gesture.get(), set); |
814 | - LOG(Dbg) << "touch " << touch_id << " has been added to accepted gesture " |
815 | - << gesture->id() << " to create new gesture " |
816 | - << new_gesture->id() << "\n"; |
817 | - unaccepted_gestures_.insert(SharedGesture(new_gesture)); |
818 | - LOG(Dbg) << "gesture " << new_gesture << " has been added to unaccepted " |
819 | - "gestures\n"; |
820 | - } |
821 | - } else if (atomic_) { |
822 | - for (UFTouchId touch : gesture->touches()) |
823 | - INSERT_TOUCH(touch, free_touches_); |
824 | - gesture->End(); |
825 | - LOG(Dbg) << "ended active atomic gesture " << gesture->id() |
826 | - << " because a new touch began and the max touches has been " |
827 | - << "reached\n"; |
828 | - accepted_gestures_.erase(gesture); |
829 | - } |
830 | -} |
831 | - |
832 | -/** |
833 | - * @internal |
834 | - * Perform tasks necessary for when a new touch occurs and there is an existing |
835 | - * unaccepted gesture |
836 | - * |
837 | - * Under normal processing: |
838 | - * If a gesture may add a touch without crossing the maximum for the |
839 | - * subscription, create a new unaccepted gesture with the new touch. |
840 | - * Otherwise, do nothing. New gestures may still begin elsewhere. |
841 | - * |
842 | - * Under atomic gesture processing: |
843 | - * If a gesture may add a touch without crossing the maximum for the |
844 | - * subscription, add the touch to the gesture and accept it. Otherwise, cancel |
845 | - * the gesture and add the current gesture touches to the free touches list. |
846 | - */ |
847 | -void Recognizer::HandleNewTouchForUnacceptedGesture( |
848 | - UFTouchId touch_id, |
849 | - const SharedGesture& gesture) { |
850 | - UGSubscription* subscription = gesture->subscription(); |
851 | - if (gesture->touches().size() < subscription->touches_max()) { |
852 | - if (atomic_) { |
853 | - gesture->AddTouch(touch_id); |
854 | - LOG(Dbg) << "touch " << touch_id << " has been added to atomic gesture " |
855 | - << gesture->id() << "\n"; |
856 | - ERASE_TOUCH(touch_id, free_touches_); |
857 | - } else { |
858 | - TouchSet set(gesture->touches()); |
859 | - set.insert(touch_id); |
860 | - Gesture* new_gesture = new Gesture(gesture.get(), set); |
861 | - LOG(Dbg) << "touch " << touch_id |
862 | - << " has been added to unaccepted gesture " << gesture->id() |
863 | - << " to create new gesture " << new_gesture->id() << "\n"; |
864 | - unaccepted_gestures_.insert(SharedGesture(new_gesture)); |
865 | - LOG(Dbg) << "gesture " << new_gesture << " has been added to unaccepted " |
866 | - "gestures\n"; |
867 | - } |
868 | - } else if (atomic_) { |
869 | - for (UFTouchId touch : gesture->touches()) |
870 | - INSERT_TOUCH(touch, free_touches_); |
871 | - gesture->Cancel(); |
872 | - LOG(Dbg) << "canceled inactive atomic gesture " << gesture->id() |
873 | - << " because a new touch began and the max touches has been " |
874 | - << "reached\n"; |
875 | - unaccepted_gestures_.erase(gesture); |
876 | - } |
877 | -} |
878 | - |
879 | -/** |
880 | - * @internal |
881 | - * Attempt to match the given touch against one touch subscriptions |
882 | - */ |
883 | -void Recognizer::MatchOneTouchGestures(UFTouchId touch_id) { |
884 | - /* Under atomic gesture processing, don't begin a new gesture unless it |
885 | - * includes all the free touches */ |
886 | - if (atomic_ && free_touches_.size() != 1) |
887 | - return; |
888 | - |
889 | - for (UGSubscription* subscription : subscriptions_[0]) { |
890 | - TouchSet set; |
891 | - set.insert(touch_id); |
892 | - Gesture* gesture = new Gesture(this, subscription, set, |
893 | - start_times_[touch_id]); |
894 | - unaccepted_gestures_.insert(SharedGesture(gesture)); |
895 | - |
896 | - LOG(Dbg) << "New tentative gesture " << gesture->id() |
897 | - << " matched subscription " << subscription << " with mask " |
898 | - << subscription->mask() << " for touch " << touch_id << "\n"; |
899 | - } |
900 | -} |
901 | - |
902 | -/** |
903 | - * @internal |
904 | - * Attempt to match the given touch against two touch subscriptions |
905 | - */ |
906 | -void Recognizer::MatchTwoTouchGestures(UFTouchId touch_id) { |
907 | - /* Under atomic gesture processing, don't begin a new gesture unless it |
908 | - * includes all the free touches */ |
909 | - if (atomic_ && free_touches_.size() != 2) |
910 | - return; |
911 | - |
912 | - for (UGSubscription* subscription : subscriptions_[1]) { |
913 | - for (UFTouchId other_id : free_touches_) { |
914 | - if (other_id == touch_id) |
915 | - continue; |
916 | - |
917 | - /* All touches in a gesture must begin within a composition timeframe */ |
918 | - uint64_t min_start_time = start_times_[touch_id]; |
919 | - if (start_times_[other_id] < min_start_time && |
920 | - unaccepted_touches_.find(other_id) != unaccepted_touches_.end()) |
921 | - min_start_time = start_times_[other_id]; |
922 | - |
923 | - if (start_times_[touch_id] - min_start_time < COMPOSITION_TIME) { |
924 | - TouchSet set; |
925 | - set.insert(touch_id); |
926 | - set.insert(other_id); |
927 | - Gesture* gesture = new Gesture(this, subscription, set, |
928 | - start_times_[touch_id]); |
929 | - unaccepted_gestures_.insert(SharedGesture(gesture)); |
930 | - |
931 | - LOG(Dbg) << "New tentative gesture " << gesture->id() |
932 | - << " matched subscription " << subscription << " with mask " |
933 | - << subscription->mask() << " for touches " << touch_id << ", " |
934 | - << other_id << "\n"; |
935 | - } |
936 | - } |
937 | - } |
938 | -} |
939 | - |
940 | -/** |
941 | - * @internal |
942 | - * Attempt to match the given touch against three touch subscriptions |
943 | - */ |
944 | -void Recognizer::MatchThreeTouchGestures(UFTouchId touch_id) { |
945 | - /* Under atomic gesture processing, don't begin a new gesture unless it |
946 | - * includes all the free touches */ |
947 | - if (atomic_ && free_touches_.size() != 3) |
948 | - return; |
949 | - |
950 | - for (UGSubscription* subscription : subscriptions_[2]) { |
951 | - for (UFTouchId other_id_1 : free_touches_) { |
952 | - if (other_id_1 == touch_id) |
953 | - continue; |
954 | - |
955 | - for (UFTouchId other_id_2 : free_touches_) { |
956 | - if (other_id_2 <= other_id_1 || other_id_2 == touch_id) |
957 | - continue; |
958 | - |
959 | - /* All touches in a gesture must begin within a composition timeframe */ |
960 | - uint64_t min_start_time = start_times_[touch_id]; |
961 | - if (start_times_[other_id_1] < min_start_time && |
962 | - unaccepted_touches_.find(other_id_1) != unaccepted_touches_.end()) |
963 | - min_start_time = start_times_[other_id_1]; |
964 | - if (start_times_[other_id_2] < min_start_time && |
965 | - unaccepted_touches_.find(other_id_2) != unaccepted_touches_.end()) |
966 | - min_start_time = start_times_[other_id_2]; |
967 | - |
968 | - if (start_times_[touch_id] - min_start_time < COMPOSITION_TIME) { |
969 | - TouchSet set; |
970 | - set.insert(touch_id); |
971 | - set.insert(other_id_1); |
972 | - set.insert(other_id_2); |
973 | - Gesture* gesture = new Gesture(this, subscription, set, |
974 | - start_times_[touch_id]); |
975 | - unaccepted_gestures_.insert(SharedGesture(gesture)); |
976 | - |
977 | - LOG(Dbg) << "New tentative gesture " << gesture->id() |
978 | - << " matched subscription " << subscription << " with mask " |
979 | - << subscription->mask() << " for touches " << touch_id |
980 | - << ", " << other_id_1 << ", " << other_id_2 << "\n"; |
981 | - } |
982 | - } |
983 | - } |
984 | - } |
985 | -} |
986 | - |
987 | -/** |
988 | - * @internal |
989 | - * Attempt to match the given touch against four touch subscriptions |
990 | - */ |
991 | -void Recognizer::MatchFourTouchGestures(UFTouchId touch_id) { |
992 | - /* Under atomic gesture processing, don't begin a new gesture unless it |
993 | - * includes all the free touches */ |
994 | - if (atomic_ && free_touches_.size() != 4) |
995 | - return; |
996 | - |
997 | - for (UGSubscription* subscription : subscriptions_[3]) { |
998 | - for (UFTouchId other_id_1 : free_touches_) { |
999 | - if (other_id_1 == touch_id) |
1000 | - continue; |
1001 | - |
1002 | - for (UFTouchId other_id_2 : free_touches_) { |
1003 | - if (other_id_2 <= other_id_1 || other_id_2 == touch_id) |
1004 | - continue; |
1005 | - |
1006 | - for (UFTouchId other_id_3 : free_touches_) { |
1007 | - if (other_id_3 <= other_id_2 || other_id_3 == touch_id) |
1008 | - continue; |
1009 | - |
1010 | - /* All touches in a gesture must begin within a composition |
1011 | - * timeframe */ |
1012 | - uint64_t min_start_time = start_times_[touch_id]; |
1013 | - if (start_times_[other_id_1] < min_start_time && |
1014 | - unaccepted_touches_.find(other_id_1) != unaccepted_touches_.end()) |
1015 | - min_start_time = start_times_[other_id_1]; |
1016 | - if (start_times_[other_id_2] < min_start_time && |
1017 | - unaccepted_touches_.find(other_id_2) != unaccepted_touches_.end()) |
1018 | - min_start_time = start_times_[other_id_2]; |
1019 | - if (start_times_[other_id_3] < min_start_time && |
1020 | - unaccepted_touches_.find(other_id_3) != unaccepted_touches_.end()) |
1021 | - min_start_time = start_times_[other_id_3]; |
1022 | - |
1023 | - if (start_times_[touch_id] - min_start_time < COMPOSITION_TIME) { |
1024 | - TouchSet set; |
1025 | - set.insert(touch_id); |
1026 | - set.insert(other_id_1); |
1027 | - set.insert(other_id_2); |
1028 | - set.insert(other_id_3); |
1029 | - Gesture* gesture = new Gesture(this, subscription, set, |
1030 | - start_times_[touch_id]); |
1031 | - unaccepted_gestures_.insert(SharedGesture(gesture)); |
1032 | - |
1033 | - LOG(Dbg) << "New tentative gesture " << gesture->id() |
1034 | - << " matched subscription " << subscription |
1035 | - << " with mask " << subscription->mask() << " for touches " |
1036 | - << touch_id << ", " << other_id_1 << ", " << other_id_2 |
1037 | - << ", " << other_id_3 << "\n"; |
1038 | - } |
1039 | - } |
1040 | - } |
1041 | - } |
1042 | - } |
1043 | -} |
1044 | - |
1045 | -/** |
1046 | - * @internal |
1047 | - * Attempt to match the given touch against five touch subscriptions |
1048 | - */ |
1049 | -void Recognizer::MatchFiveTouchGestures(UFTouchId touch_id) { |
1050 | - /* Under atomic gesture processing, don't begin a new gesture unless it |
1051 | - * includes all the free touches */ |
1052 | - if (atomic_ && free_touches_.size() != 5) |
1053 | - return; |
1054 | - |
1055 | - for (UGSubscription* subscription : subscriptions_[4]) { |
1056 | - for (UFTouchId other_id_1 : free_touches_) { |
1057 | - if (other_id_1 == touch_id) |
1058 | - continue; |
1059 | - |
1060 | - for (UFTouchId other_id_2 : free_touches_) { |
1061 | - if (other_id_2 <= other_id_1 || other_id_2 == touch_id) |
1062 | - continue; |
1063 | - |
1064 | - for (UFTouchId other_id_3 : free_touches_) { |
1065 | - if (other_id_3 <= other_id_2 || other_id_3 == touch_id) |
1066 | - continue; |
1067 | - |
1068 | - for (UFTouchId other_id_4 : free_touches_) { |
1069 | - if (other_id_4 <= other_id_3 || other_id_4 == touch_id) |
1070 | - continue; |
1071 | - |
1072 | - /* All touches in a gesture must begin within a composition |
1073 | - * timeframe */ |
1074 | - uint64_t min_start_time = start_times_[touch_id]; |
1075 | - if (start_times_[other_id_1] < min_start_time && |
1076 | - unaccepted_touches_.find(other_id_1) != |
1077 | - unaccepted_touches_.end()) |
1078 | - min_start_time = start_times_[other_id_1]; |
1079 | - if (start_times_[other_id_2] < min_start_time && |
1080 | - unaccepted_touches_.find(other_id_2) != |
1081 | - unaccepted_touches_.end()) |
1082 | - min_start_time = start_times_[other_id_2]; |
1083 | - if (start_times_[other_id_3] < min_start_time && |
1084 | - unaccepted_touches_.find(other_id_3) != |
1085 | - unaccepted_touches_.end()) |
1086 | - min_start_time = start_times_[other_id_3]; |
1087 | - if (start_times_[other_id_4] < min_start_time && |
1088 | - unaccepted_touches_.find(other_id_4) != |
1089 | - unaccepted_touches_.end()) |
1090 | - min_start_time = start_times_[other_id_4]; |
1091 | - |
1092 | - if (start_times_[touch_id] - min_start_time < COMPOSITION_TIME) { |
1093 | - TouchSet set; |
1094 | - set.insert(touch_id); |
1095 | - set.insert(other_id_1); |
1096 | - set.insert(other_id_2); |
1097 | - set.insert(other_id_3); |
1098 | - set.insert(other_id_4); |
1099 | - Gesture* gesture = new Gesture(this, subscription, set, |
1100 | - start_times_[touch_id]); |
1101 | - unaccepted_gestures_.insert(SharedGesture(gesture)); |
1102 | - |
1103 | - LOG(Dbg) << "New tentative gesture " << gesture->id() |
1104 | - << " matched subscription " << subscription |
1105 | - << " with mask " << subscription->mask() |
1106 | - << " for touches " << touch_id << ", " << other_id_1 |
1107 | - << ", " << other_id_2 << ", " << other_id_3 << ", " |
1108 | - << other_id_4 << "\n"; |
1109 | - } |
1110 | - } |
1111 | - } |
1112 | - } |
1113 | - } |
1114 | - } |
1115 | -} |
1116 | - |
1117 | namespace { |
1118 | |
1119 | /** |
1120 | @@ -670,11 +233,6 @@ |
1121 | LOG(Dbg) << "rejecting gesture " << gesture->id() << " because it has " |
1122 | " been canceled\n"; |
1123 | RejectGesture(gesture); |
1124 | - } else if (gesture->IsActive() && gesture->subscription()->atomic()) { |
1125 | - /* Atomic gestures must be accepted if they meet the subscription criteria |
1126 | - */ |
1127 | - LOG(Dbg) << "accepting active atomic gesture " << gesture->id() << "\n"; |
1128 | - AcceptGesture(gesture->id()); |
1129 | } |
1130 | } |
1131 | |
1132 | @@ -713,7 +271,7 @@ |
1133 | * gesture has not crossed the recognition thresholds yet) |
1134 | */ |
1135 | void Recognizer::CheckConstructionFinished(uint64_t time) { |
1136 | - if (atomic_) |
1137 | + if (atomic()) |
1138 | return; |
1139 | |
1140 | for (const SharedGesture& gesture : unaccepted_gestures_) { |
1141 | @@ -721,7 +279,7 @@ |
1142 | continue; |
1143 | |
1144 | for (UFTouchId touch_id : gesture->touches()) { |
1145 | - if (time - start_times_[touch_id] < COMPOSITION_TIME) |
1146 | + if (time - start_times_[touch_id] < kCompositionTime) |
1147 | goto next_gesture; |
1148 | |
1149 | for (const SharedGesture& other_gesture : unaccepted_gestures_) { |
1150 | @@ -771,7 +329,7 @@ |
1151 | it != unaccepted_touches_.end(); |
1152 | ) { |
1153 | UFTouchId touch_id = *it++; |
1154 | - if (time - start_times_[touch_id] < COMPOSITION_TIME) |
1155 | + if (time - start_times_[touch_id] < kCompositionTime) |
1156 | continue; |
1157 | |
1158 | for (const SharedGesture& gesture : unaccepted_gestures_) |
1159 | @@ -808,8 +366,8 @@ |
1160 | if (gesture->touches().find(touch_id) != gesture->touches().end()) |
1161 | goto next_touch; |
1162 | |
1163 | - if (COMPOSITION_TIME + start_times_[touch_id] < min_timeout) |
1164 | - min_timeout = start_times_[touch_id] + COMPOSITION_TIME; |
1165 | + if (kCompositionTime + start_times_[touch_id] < min_timeout) |
1166 | + min_timeout = start_times_[touch_id] + kCompositionTime; |
1167 | |
1168 | next_touch: ; |
1169 | } |
1170 | @@ -859,7 +417,7 @@ |
1171 | * gesture. Cancel the old gesture and remove any gesture events for it |
1172 | * from the event queue. Atomic behavior does not allow for gestures to be |
1173 | * extended in this way, and gestures may overlap.*/ |
1174 | - if (!atomic_) { |
1175 | + if (!atomic()) { |
1176 | for (auto it = accepted_gestures_.begin(); |
1177 | it != accepted_gestures_.end(); |
1178 | ) { |
1179 | @@ -886,7 +444,7 @@ |
1180 | |
1181 | /* Reject any overlapping unaccepted gestures. Atomic subscriptions may have |
1182 | * overlapping gestures due to historical behavior. */ |
1183 | - if (!atomic_) { |
1184 | + if (!atomic()) { |
1185 | for (auto it = unaccepted_gestures_.begin(); |
1186 | it != unaccepted_gestures_.end(); |
1187 | ) { |
1188 | |
1189 | === modified file 'src/v3/recognizer.h' |
1190 | --- src/v3/recognizer.h 2012-01-27 11:57:35 +0000 |
1191 | +++ src/v3/recognizer.h 2012-03-14 19:17:21 +0000 |
1192 | @@ -33,17 +33,43 @@ |
1193 | #include "v3/forward.h" |
1194 | #include "v3/subscription.h" |
1195 | |
1196 | +#define INSERT_TOUCH(element, set) \ |
1197 | + { \ |
1198 | + (set).insert(element); \ |
1199 | + LOG(Dbg) << "touch " << element << " has been added to " #set "\n"; \ |
1200 | + } |
1201 | + |
1202 | +#define ERASE_TOUCH(element, set) \ |
1203 | + { \ |
1204 | + (set).erase(element); \ |
1205 | + LOG(Dbg) << "touch " << element << " has been erased from " #set "\n"; \ |
1206 | + } |
1207 | + |
1208 | +// OBS: it avoids the "expensive" ToString() call when debug output is not wanted. |
1209 | +#define CLEAR_TOUCHES(set) \ |
1210 | + { \ |
1211 | + if (utouch::grail::Logger::instance().level() <= utouch::grail::Logger::Dbg) \ |
1212 | + if ((set).size() > 0) \ |
1213 | + LOG(Dbg) << "touch(es) " << (set).ToString() \ |
1214 | + << " have been erased from " #set "\n"; \ |
1215 | + (set).clear(); \ |
1216 | + } |
1217 | + |
1218 | namespace utouch { |
1219 | namespace grail { |
1220 | |
1221 | class Recognizer { |
1222 | public: |
1223 | Recognizer(UGHandle* handle, const UFDevice device, UFWindowId window); |
1224 | - ~Recognizer(); |
1225 | + virtual ~Recognizer(); |
1226 | + |
1227 | + virtual bool atomic() const = 0; |
1228 | + virtual void ProcessFrameEvent(const UFEvent event) = 0; |
1229 | + |
1230 | + unsigned int num_subscriptions() const {return num_subscriptions_;} |
1231 | |
1232 | UGStatus ActivateSubscription(UGSubscription* subscription); |
1233 | void DeactivateSubscription(UGSubscription* subscription); |
1234 | - void ProcessFrameEvent(const UFEvent event); |
1235 | void UpdateTime(uint64_t time); |
1236 | uint64_t NextTimeout(); |
1237 | UGStatus AcceptGesture(unsigned int id); |
1238 | @@ -57,7 +83,9 @@ |
1239 | Recognizer(const Recognizer&) = delete; |
1240 | Recognizer& operator=(const Recognizer&) = delete; |
1241 | |
1242 | - private: |
1243 | + protected: |
1244 | + static uint64_t kCompositionTime; /* in milliseconds */ |
1245 | + |
1246 | UGHandle* const handle_; |
1247 | const UFDevice device_; |
1248 | const UFWindowId window_id_; |
1249 | @@ -72,22 +100,12 @@ |
1250 | TouchSet unaccepted_touches_; |
1251 | TouchSet accepted_touches_; |
1252 | TouchSet free_touches_; |
1253 | + |
1254 | unsigned int num_subscriptions_; |
1255 | |
1256 | - void HandleNewTouchForAcceptedGesture(UFTouchId touch_id, |
1257 | - const SharedGesture& gesture); |
1258 | - void HandleNewTouchForUnacceptedGesture(UFTouchId touch_id, |
1259 | - const SharedGesture& gesture); |
1260 | - void MatchSubscriptionsForEvent(const UFEvent event); |
1261 | - void MatchSubscriptionsForTouch(UFTouchId touch_id); |
1262 | - void MatchOneTouchGestures(UFTouchId touch_id); |
1263 | - void MatchTwoTouchGestures(UFTouchId touch_id); |
1264 | - void MatchThreeTouchGestures(UFTouchId touch_id); |
1265 | - void MatchFourTouchGestures(UFTouchId touch_id); |
1266 | - void MatchFiveTouchGestures(UFTouchId touch_id); |
1267 | - void ProcessEvent(const UFEvent& event); |
1268 | void CheckConstructionFinished(uint64_t time); |
1269 | void RejectGesture(SharedGesture gesture); |
1270 | + void ProcessEvent(const UFEvent& event); |
1271 | }; |
1272 | |
1273 | } // namespace grail |
1274 | |
1275 | === added file 'src/v3/regular-recognizer.cpp' |
1276 | --- src/v3/regular-recognizer.cpp 1970-01-01 00:00:00 +0000 |
1277 | +++ src/v3/regular-recognizer.cpp 2012-03-14 19:17:21 +0000 |
1278 | @@ -0,0 +1,396 @@ |
1279 | +/***************************************************************************** |
1280 | + * |
1281 | + * grail - Gesture Recognition And Instantiation Library |
1282 | + * |
1283 | + * Copyright (C) 2012 Canonical Ltd. |
1284 | + * |
1285 | + * This program is free software: you can redistribute it and/or modify it |
1286 | + * under the terms of the GNU General Public License as published by the |
1287 | + * Free Software Foundation, either version 3 of the License, or (at your |
1288 | + * option) any later version. |
1289 | + * |
1290 | + * This program is distributed in the hope that it will be useful, but |
1291 | + * WITHOUT ANY WARRANTY; without even the implied warranty of |
1292 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1293 | + * General Public License for more details. |
1294 | + * |
1295 | + * You should have received a copy of the GNU General Public License along |
1296 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
1297 | + * |
1298 | + ****************************************************************************/ |
1299 | + |
1300 | +#include "v3/regular-recognizer.h" |
1301 | + |
1302 | +#include <algorithm> |
1303 | +#include <cassert> |
1304 | +#include <cstdint> |
1305 | +#include <cstdio> |
1306 | +#include <limits> |
1307 | + |
1308 | +#include <utouch/frame.h> |
1309 | +#include <utouch/frame_x11.h> |
1310 | + |
1311 | +#include "v3/handle.h" |
1312 | +#include "v3/gesture.h" |
1313 | +#include "v3/log.h" |
1314 | + |
1315 | +namespace utouch { |
1316 | +namespace grail { |
1317 | + |
1318 | +/** |
1319 | + * @internal |
1320 | + * Create a new regular recognizer for a given device and window |
1321 | + */ |
1322 | +RegularRecognizer::RegularRecognizer(UGHandle* handle, const UFDevice device, |
1323 | + UFWindowId window_id) |
1324 | + : Recognizer(handle, device, window_id) { |
1325 | +} |
1326 | + |
1327 | +/** |
1328 | + * @internal |
1329 | + * Process a uTouch-Frame event |
1330 | + */ |
1331 | +void RegularRecognizer::ProcessFrameEvent(const UFEvent event) { |
1332 | + LOG(Dbg) << "new event " << event << " with time " |
1333 | + << frame_event_get_time(event) << "\n"; |
1334 | + UpdateTime(frame_event_get_time(event)); |
1335 | + MatchSubscriptionsForEvent(event); |
1336 | + ProcessEvent(event); |
1337 | +} |
1338 | + |
1339 | +/** |
1340 | + * @internal |
1341 | + * Analyze a uTouch-Frame event to see if any new gestures should begin |
1342 | + */ |
1343 | +void RegularRecognizer::MatchSubscriptionsForEvent(const UFEvent event) { |
1344 | + /* Check if any subscriptions are active before doing any processing */ |
1345 | + if (num_subscriptions_ == 0) |
1346 | + return; |
1347 | + |
1348 | + UFFrame frame; |
1349 | + UFStatus status = frame_event_get_property(event, UFEventPropertyFrame, |
1350 | + &frame); |
1351 | + if (status != UFStatusSuccess) { |
1352 | + LOG(Warn) << "failed to get frame from event\n"; |
1353 | + return; |
1354 | + } |
1355 | + |
1356 | + /* Process all the touches that began in this frame */ |
1357 | + unsigned int num_touches = frame_frame_get_num_touches(frame); |
1358 | + for (unsigned int i = 0; i < num_touches; ++i) { |
1359 | + UFTouch touch; |
1360 | + status = frame_frame_get_touch_by_index(frame, i, &touch); |
1361 | + if (status != UFStatusSuccess) { |
1362 | + LOG(Warn) << "failed to get touch from frame\n"; |
1363 | + continue; |
1364 | + } |
1365 | + |
1366 | + if (frame_touch_get_state(touch) != UFTouchStateBegin) |
1367 | + continue; |
1368 | + |
1369 | + UFTouchId touch_id = frame_touch_get_id(touch); |
1370 | + |
1371 | + /* Note touch start time and add to initial touch lists */ |
1372 | + start_times_[touch_id] = frame_touch_get_start_time(touch); |
1373 | + LOG(Dbg) << "touch " << touch_id << " began with start time " |
1374 | + << start_times_[touch_id] << "\n"; |
1375 | + |
1376 | + INSERT_TOUCH(touch_id, unaccepted_touches_); |
1377 | + INSERT_TOUCH(touch_id, free_touches_); |
1378 | + |
1379 | + /* HandleNewTouchForAcceptedGesture may erase the gesture from |
1380 | + * accepted_gestures_, so we can't use range-based for loops */ |
1381 | + for (auto it = accepted_gestures_.begin(); |
1382 | + it != accepted_gestures_.end(); |
1383 | + ) { |
1384 | + const SharedGesture& gesture = *it++; |
1385 | + HandleNewTouchForAcceptedGesture(touch_id, gesture); |
1386 | + } |
1387 | + |
1388 | + /* HandleNewTouchForAcceptedGesture may erase the gesture from |
1389 | + * accepted_gestures_, so we can't use range-based for loops */ |
1390 | + for (auto it = unaccepted_gestures_.begin(); |
1391 | + it != unaccepted_gestures_.end(); |
1392 | + ) { |
1393 | + const SharedGesture& gesture = *it++; |
1394 | + HandleNewTouchForUnacceptedGesture(touch_id, gesture); |
1395 | + } |
1396 | + |
1397 | + /* Attempt to match new gestures for active subscriptions */ |
1398 | + MatchOneTouchGestures(touch_id); |
1399 | + MatchTwoTouchGestures(touch_id); |
1400 | + MatchThreeTouchGestures(touch_id); |
1401 | + MatchFourTouchGestures(touch_id); |
1402 | + MatchFiveTouchGestures(touch_id); |
1403 | + } |
1404 | +} |
1405 | + |
1406 | +/** |
1407 | + * @internal |
1408 | + * Perform tasks necessary for when a new touch occurs and there is an existing |
1409 | + * accepted gesture |
1410 | + * |
1411 | + * If a gesture may add a touch without crossing the maximum for the |
1412 | + * subscription, create a new unaccepted gesture with the new touch. |
1413 | + * Otherwise, do nothing. New gestures may still begin elsewhere. |
1414 | + */ |
1415 | +void RegularRecognizer::HandleNewTouchForAcceptedGesture( |
1416 | + UFTouchId touch_id, |
1417 | + const SharedGesture& gesture) { |
1418 | + UGSubscription* subscription = gesture->subscription(); |
1419 | + if (gesture->touches().size() < subscription->touches_max() |
1420 | + && !gesture->ContainsTouch(touch_id)) { |
1421 | + TouchSet set(gesture->touches()); |
1422 | + set.insert(touch_id); |
1423 | + Gesture* new_gesture = new Gesture(gesture.get(), set); |
1424 | + LOG(Dbg) << "touch " << touch_id << " has been added to accepted gesture " |
1425 | + << gesture->id() << " to create new gesture " |
1426 | + << new_gesture->id() << "\n"; |
1427 | + unaccepted_gestures_.insert(SharedGesture(new_gesture)); |
1428 | + LOG(Dbg) << "gesture " << new_gesture << " has been added to unaccepted " |
1429 | + "gestures\n"; |
1430 | + } |
1431 | +} |
1432 | + |
1433 | +/** |
1434 | + * @internal |
1435 | + * Perform tasks necessary for when a new touch occurs and there is an existing |
1436 | + * unaccepted gesture |
1437 | + * |
1438 | + * If a gesture may add a touch without crossing the maximum for the |
1439 | + * subscription, create a new unaccepted gesture with the new touch. |
1440 | + * Otherwise, do nothing. New gestures may still begin elsewhere. |
1441 | + */ |
1442 | +void RegularRecognizer::HandleNewTouchForUnacceptedGesture( |
1443 | + UFTouchId touch_id, |
1444 | + const SharedGesture& gesture) { |
1445 | + UGSubscription* subscription = gesture->subscription(); |
1446 | + if (gesture->touches().size() < subscription->touches_max() |
1447 | + && !gesture->ContainsTouch(touch_id)) { |
1448 | + TouchSet set(gesture->touches()); |
1449 | + set.insert(touch_id); |
1450 | + Gesture* new_gesture = new Gesture(gesture.get(), set); |
1451 | + LOG(Dbg) << "touch " << touch_id |
1452 | + << " has been added to unaccepted gesture " << gesture->id() |
1453 | + << " to create new gesture " << new_gesture->id() << "\n"; |
1454 | + unaccepted_gestures_.insert(SharedGesture(new_gesture)); |
1455 | + LOG(Dbg) << "gesture " << new_gesture << " has been added to unaccepted " |
1456 | + "gestures\n"; |
1457 | + } |
1458 | +} |
1459 | + |
1460 | +/** |
1461 | + * @internal |
1462 | + * Attempt to match the given touch against one touch subscriptions |
1463 | + */ |
1464 | +void RegularRecognizer::MatchOneTouchGestures(UFTouchId touch_id) { |
1465 | + for (UGSubscription* subscription : subscriptions_[0]) { |
1466 | + TouchSet set; |
1467 | + set.insert(touch_id); |
1468 | + Gesture* gesture = new Gesture(this, subscription, set, |
1469 | + start_times_[touch_id]); |
1470 | + unaccepted_gestures_.insert(SharedGesture(gesture)); |
1471 | + |
1472 | + LOG(Dbg) << "New tentative gesture " << gesture->id() |
1473 | + << " matched subscription " << subscription << " with mask " |
1474 | + << subscription->mask() << " for touch " << touch_id << "\n"; |
1475 | + } |
1476 | +} |
1477 | + |
1478 | +/** |
1479 | + * @internal |
1480 | + * Attempt to match the given touch against two touch subscriptions |
1481 | + */ |
1482 | +void RegularRecognizer::MatchTwoTouchGestures(UFTouchId touch_id) { |
1483 | + for (UGSubscription* subscription : subscriptions_[1]) { |
1484 | + for (UFTouchId other_id : free_touches_) { |
1485 | + if (other_id == touch_id) |
1486 | + continue; |
1487 | + |
1488 | + /* All touches in a gesture must begin within a composition timeframe */ |
1489 | + uint64_t min_start_time = start_times_[touch_id]; |
1490 | + if (start_times_[other_id] < min_start_time && |
1491 | + unaccepted_touches_.find(other_id) != unaccepted_touches_.end()) |
1492 | + min_start_time = start_times_[other_id]; |
1493 | + |
1494 | + if (start_times_[touch_id] - min_start_time < kCompositionTime) { |
1495 | + TouchSet set; |
1496 | + set.insert(touch_id); |
1497 | + set.insert(other_id); |
1498 | + Gesture* gesture = new Gesture(this, subscription, set, |
1499 | + start_times_[touch_id]); |
1500 | + unaccepted_gestures_.insert(SharedGesture(gesture)); |
1501 | + |
1502 | + LOG(Dbg) << "New tentative gesture " << gesture->id() |
1503 | + << " matched subscription " << subscription << " with mask " |
1504 | + << subscription->mask() << " for touches " << touch_id << ", " |
1505 | + << other_id << "\n"; |
1506 | + } |
1507 | + } |
1508 | + } |
1509 | +} |
1510 | + |
1511 | +/** |
1512 | + * @internal |
1513 | + * Attempt to match the given touch against three touch subscriptions |
1514 | + */ |
1515 | +void RegularRecognizer::MatchThreeTouchGestures(UFTouchId touch_id) { |
1516 | + for (UGSubscription* subscription : subscriptions_[2]) { |
1517 | + for (UFTouchId other_id_1 : free_touches_) { |
1518 | + if (other_id_1 == touch_id) |
1519 | + continue; |
1520 | + |
1521 | + for (UFTouchId other_id_2 : free_touches_) { |
1522 | + if (other_id_2 <= other_id_1 || other_id_2 == touch_id) |
1523 | + continue; |
1524 | + |
1525 | + /* All touches in a gesture must begin within a composition timeframe */ |
1526 | + uint64_t min_start_time = start_times_[touch_id]; |
1527 | + if (start_times_[other_id_1] < min_start_time && |
1528 | + unaccepted_touches_.find(other_id_1) != unaccepted_touches_.end()) |
1529 | + min_start_time = start_times_[other_id_1]; |
1530 | + if (start_times_[other_id_2] < min_start_time && |
1531 | + unaccepted_touches_.find(other_id_2) != unaccepted_touches_.end()) |
1532 | + min_start_time = start_times_[other_id_2]; |
1533 | + |
1534 | + if (start_times_[touch_id] - min_start_time < kCompositionTime) { |
1535 | + TouchSet set; |
1536 | + set.insert(touch_id); |
1537 | + set.insert(other_id_1); |
1538 | + set.insert(other_id_2); |
1539 | + Gesture* gesture = new Gesture(this, subscription, set, |
1540 | + start_times_[touch_id]); |
1541 | + unaccepted_gestures_.insert(SharedGesture(gesture)); |
1542 | + |
1543 | + LOG(Dbg) << "New tentative gesture " << gesture->id() |
1544 | + << " matched subscription " << subscription << " with mask " |
1545 | + << subscription->mask() << " for touches " << touch_id |
1546 | + << ", " << other_id_1 << ", " << other_id_2 << "\n"; |
1547 | + } |
1548 | + } |
1549 | + } |
1550 | + } |
1551 | +} |
1552 | + |
1553 | +/** |
1554 | + * @internal |
1555 | + * Attempt to match the given touch against four touch subscriptions |
1556 | + */ |
1557 | +void RegularRecognizer::MatchFourTouchGestures(UFTouchId touch_id) { |
1558 | + for (UGSubscription* subscription : subscriptions_[3]) { |
1559 | + for (UFTouchId other_id_1 : free_touches_) { |
1560 | + if (other_id_1 == touch_id) |
1561 | + continue; |
1562 | + |
1563 | + for (UFTouchId other_id_2 : free_touches_) { |
1564 | + if (other_id_2 <= other_id_1 || other_id_2 == touch_id) |
1565 | + continue; |
1566 | + |
1567 | + for (UFTouchId other_id_3 : free_touches_) { |
1568 | + if (other_id_3 <= other_id_2 || other_id_3 == touch_id) |
1569 | + continue; |
1570 | + |
1571 | + /* All touches in a gesture must begin within a composition |
1572 | + * timeframe */ |
1573 | + uint64_t min_start_time = start_times_[touch_id]; |
1574 | + if (start_times_[other_id_1] < min_start_time && |
1575 | + unaccepted_touches_.find(other_id_1) != unaccepted_touches_.end()) |
1576 | + min_start_time = start_times_[other_id_1]; |
1577 | + if (start_times_[other_id_2] < min_start_time && |
1578 | + unaccepted_touches_.find(other_id_2) != unaccepted_touches_.end()) |
1579 | + min_start_time = start_times_[other_id_2]; |
1580 | + if (start_times_[other_id_3] < min_start_time && |
1581 | + unaccepted_touches_.find(other_id_3) != unaccepted_touches_.end()) |
1582 | + min_start_time = start_times_[other_id_3]; |
1583 | + |
1584 | + if (start_times_[touch_id] - min_start_time < kCompositionTime) { |
1585 | + TouchSet set; |
1586 | + set.insert(touch_id); |
1587 | + set.insert(other_id_1); |
1588 | + set.insert(other_id_2); |
1589 | + set.insert(other_id_3); |
1590 | + Gesture* gesture = new Gesture(this, subscription, set, |
1591 | + start_times_[touch_id]); |
1592 | + unaccepted_gestures_.insert(SharedGesture(gesture)); |
1593 | + |
1594 | + LOG(Dbg) << "New tentative gesture " << gesture->id() |
1595 | + << " matched subscription " << subscription |
1596 | + << " with mask " << subscription->mask() << " for touches " |
1597 | + << touch_id << ", " << other_id_1 << ", " << other_id_2 |
1598 | + << ", " << other_id_3 << "\n"; |
1599 | + } |
1600 | + } |
1601 | + } |
1602 | + } |
1603 | + } |
1604 | +} |
1605 | + |
1606 | +/** |
1607 | + * @internal |
1608 | + * Attempt to match the given touch against five touch subscriptions |
1609 | + */ |
1610 | +void RegularRecognizer::MatchFiveTouchGestures(UFTouchId touch_id) { |
1611 | + for (UGSubscription* subscription : subscriptions_[4]) { |
1612 | + for (UFTouchId other_id_1 : free_touches_) { |
1613 | + if (other_id_1 == touch_id) |
1614 | + continue; |
1615 | + |
1616 | + for (UFTouchId other_id_2 : free_touches_) { |
1617 | + if (other_id_2 <= other_id_1 || other_id_2 == touch_id) |
1618 | + continue; |
1619 | + |
1620 | + for (UFTouchId other_id_3 : free_touches_) { |
1621 | + if (other_id_3 <= other_id_2 || other_id_3 == touch_id) |
1622 | + continue; |
1623 | + |
1624 | + for (UFTouchId other_id_4 : free_touches_) { |
1625 | + if (other_id_4 <= other_id_3 || other_id_4 == touch_id) |
1626 | + continue; |
1627 | + |
1628 | + /* All touches in a gesture must begin within a composition |
1629 | + * timeframe */ |
1630 | + uint64_t min_start_time = start_times_[touch_id]; |
1631 | + if (start_times_[other_id_1] < min_start_time && |
1632 | + unaccepted_touches_.find(other_id_1) != |
1633 | + unaccepted_touches_.end()) |
1634 | + min_start_time = start_times_[other_id_1]; |
1635 | + if (start_times_[other_id_2] < min_start_time && |
1636 | + unaccepted_touches_.find(other_id_2) != |
1637 | + unaccepted_touches_.end()) |
1638 | + min_start_time = start_times_[other_id_2]; |
1639 | + if (start_times_[other_id_3] < min_start_time && |
1640 | + unaccepted_touches_.find(other_id_3) != |
1641 | + unaccepted_touches_.end()) |
1642 | + min_start_time = start_times_[other_id_3]; |
1643 | + if (start_times_[other_id_4] < min_start_time && |
1644 | + unaccepted_touches_.find(other_id_4) != |
1645 | + unaccepted_touches_.end()) |
1646 | + min_start_time = start_times_[other_id_4]; |
1647 | + |
1648 | + if (start_times_[touch_id] - min_start_time < kCompositionTime) { |
1649 | + TouchSet set; |
1650 | + set.insert(touch_id); |
1651 | + set.insert(other_id_1); |
1652 | + set.insert(other_id_2); |
1653 | + set.insert(other_id_3); |
1654 | + set.insert(other_id_4); |
1655 | + Gesture* gesture = new Gesture(this, subscription, set, |
1656 | + start_times_[touch_id]); |
1657 | + unaccepted_gestures_.insert(SharedGesture(gesture)); |
1658 | + |
1659 | + LOG(Dbg) << "New tentative gesture " << gesture->id() |
1660 | + << " matched subscription " << subscription |
1661 | + << " with mask " << subscription->mask() |
1662 | + << " for touches " << touch_id << ", " << other_id_1 |
1663 | + << ", " << other_id_2 << ", " << other_id_3 << ", " |
1664 | + << other_id_4 << "\n"; |
1665 | + } |
1666 | + } |
1667 | + } |
1668 | + } |
1669 | + } |
1670 | + } |
1671 | +} |
1672 | + |
1673 | +} // namespace grail |
1674 | +} // namespace utouch |
1675 | |
1676 | === added file 'src/v3/regular-recognizer.h' |
1677 | --- src/v3/regular-recognizer.h 1970-01-01 00:00:00 +0000 |
1678 | +++ src/v3/regular-recognizer.h 2012-03-14 19:17:21 +0000 |
1679 | @@ -0,0 +1,52 @@ |
1680 | +/***************************************************************************** |
1681 | + * |
1682 | + * grail - Gesture Recognition And Instantiation Library |
1683 | + * |
1684 | + * Copyright (C) 2012 Canonical Ltd. |
1685 | + * |
1686 | + * This program is free software: you can redistribute it and/or modify it |
1687 | + * under the terms of the GNU General Public License as published by the |
1688 | + * Free Software Foundation, either version 3 of the License, or (at your |
1689 | + * option) any later version. |
1690 | + * |
1691 | + * This program is distributed in the hope that it will be useful, but |
1692 | + * WITHOUT ANY WARRANTY; without even the implied warranty of |
1693 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1694 | + * General Public License for more details. |
1695 | + * |
1696 | + * You should have received a copy of the GNU General Public License along |
1697 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
1698 | + * |
1699 | + ****************************************************************************/ |
1700 | + |
1701 | +#ifndef UTOUCH_GRAIL_REGULAR_RECOGNIZER_H_ |
1702 | +#define UTOUCH_GRAIL_REGULAR_RECOGNIZER_H_ |
1703 | + |
1704 | +#include "v3/recognizer.h" |
1705 | + |
1706 | +namespace utouch { |
1707 | +namespace grail { |
1708 | + |
1709 | +class RegularRecognizer : public Recognizer { |
1710 | + public: |
1711 | + RegularRecognizer(UGHandle* handle, const UFDevice device, UFWindowId window); |
1712 | + |
1713 | + virtual bool atomic() const {return false;} |
1714 | + virtual void ProcessFrameEvent(const UFEvent event); |
1715 | + |
1716 | + private: |
1717 | + void HandleNewTouchForAcceptedGesture(UFTouchId touch_id, |
1718 | + const SharedGesture& gesture); |
1719 | + void HandleNewTouchForUnacceptedGesture(UFTouchId touch_id, |
1720 | + const SharedGesture& gesture); |
1721 | + void MatchSubscriptionsForEvent(const UFEvent event); |
1722 | + void MatchOneTouchGestures(UFTouchId touch_id); |
1723 | + void MatchTwoTouchGestures(UFTouchId touch_id); |
1724 | + void MatchThreeTouchGestures(UFTouchId touch_id); |
1725 | + void MatchFourTouchGestures(UFTouchId touch_id); |
1726 | + void MatchFiveTouchGestures(UFTouchId touch_id); |
1727 | +}; |
1728 | + |
1729 | +} // namespace grail |
1730 | +} // namespace utouch |
1731 | +#endif |
1732 | |
1733 | === modified file 'test/Makefile.am' |
1734 | --- test/Makefile.am 2012-03-06 20:12:40 +0000 |
1735 | +++ test/Makefile.am 2012-03-14 19:17:21 +0000 |
1736 | @@ -29,6 +29,7 @@ |
1737 | recording.h \ |
1738 | x11/fixture.cpp \ |
1739 | x11/fixture.h \ |
1740 | + x11/no-premature-gestures.cpp \ |
1741 | x11/no-tap-after-drag.cpp \ |
1742 | x11/twodrag.cpp \ |
1743 | x11/dragthresh.cpp \ |
1744 | |
1745 | === added file 'test/recordings/apple-wtrackpad-synced-4-drag.event' |
1746 | --- test/recordings/apple-wtrackpad-synced-4-drag.event 1970-01-01 00:00:00 +0000 |
1747 | +++ test/recordings/apple-wtrackpad-synced-4-drag.event 2012-03-14 19:17:21 +0000 |
1748 | @@ -0,0 +1,713 @@ |
1749 | +E: 1331641155.505566 0003 0039 1 |
1750 | +E: 1331641155.505567 0003 0030 84 |
1751 | +E: 1331641155.505568 0003 0031 132 |
1752 | +E: 1331641155.505568 0003 0034 8 |
1753 | +E: 1331641155.505569 0003 0035 -1940 |
1754 | +E: 1331641155.505570 0003 0036 -910 |
1755 | +E: 1331641155.505571 0000 0002 0 |
1756 | +E: 1331641155.505571 0003 0039 2 |
1757 | +E: 1331641155.505572 0003 0030 64 |
1758 | +E: 1331641155.505573 0003 0031 76 |
1759 | +E: 1331641155.505573 0003 0034 1 |
1760 | +E: 1331641155.505574 0003 0035 1649 |
1761 | +E: 1331641155.505575 0003 0036 -1430 |
1762 | +E: 1331641155.505575 0000 0002 0 |
1763 | +E: 1331641155.505576 0003 0039 3 |
1764 | +E: 1331641155.505577 0003 0030 164 |
1765 | +E: 1331641155.505577 0003 0031 124 |
1766 | +E: 1331641155.505578 0003 0034 0 |
1767 | +E: 1331641155.505578 0003 0035 -1055 |
1768 | +E: 1331641155.505579 0003 0036 -1523 |
1769 | +E: 1331641155.505580 0000 0002 0 |
1770 | +E: 1331641155.505580 0003 0039 8 |
1771 | +E: 1331641155.505581 0003 0030 180 |
1772 | +E: 1331641155.505582 0003 0031 188 |
1773 | +E: 1331641155.505582 0003 0034 32 |
1774 | +E: 1331641155.505583 0003 0035 249 |
1775 | +E: 1331641155.505584 0003 0036 -1808 |
1776 | +E: 1331641155.505584 0000 0002 0 |
1777 | +E: 1331641155.505585 0001 014a 1 |
1778 | +E: 1331641155.505587 0001 014f 1 |
1779 | +E: 1331641155.505587 0003 0000 -1940 |
1780 | +E: 1331641155.505588 0003 0001 -910 |
1781 | +E: 1331641155.505589 0000 0000 0 |
1782 | +E: 1331641155.530563 0003 0039 1 |
1783 | +E: 1331641155.530564 0003 0030 100 |
1784 | +E: 1331641155.530564 0003 0031 152 |
1785 | +E: 1331641155.530565 0003 0034 0 |
1786 | +E: 1331641155.530565 0003 0035 -1950 |
1787 | +E: 1331641155.530566 0003 0036 -898 |
1788 | +E: 1331641155.530567 0000 0002 0 |
1789 | +E: 1331641155.530568 0003 0039 2 |
1790 | +E: 1331641155.530568 0003 0030 96 |
1791 | +E: 1331641155.530569 0003 0031 132 |
1792 | +E: 1331641155.530569 0003 0034 0 |
1793 | +E: 1331641155.530570 0003 0035 1631 |
1794 | +E: 1331641155.530571 0003 0036 -1420 |
1795 | +E: 1331641155.530571 0000 0002 0 |
1796 | +E: 1331641155.530572 0003 0039 3 |
1797 | +E: 1331641155.530573 0003 0030 148 |
1798 | +E: 1331641155.530573 0003 0031 136 |
1799 | +E: 1331641155.530574 0003 0034 0 |
1800 | +E: 1331641155.530575 0003 0035 -1061 |
1801 | +E: 1331641155.530575 0003 0036 -1516 |
1802 | +E: 1331641155.530576 0000 0002 0 |
1803 | +E: 1331641155.530577 0003 0039 8 |
1804 | +E: 1331641155.530577 0003 0030 176 |
1805 | +E: 1331641155.530578 0003 0031 168 |
1806 | +E: 1331641155.530579 0003 0034 0 |
1807 | +E: 1331641155.530579 0003 0035 251 |
1808 | +E: 1331641155.530580 0003 0036 -1814 |
1809 | +E: 1331641155.530581 0000 0002 0 |
1810 | +E: 1331641155.530583 0003 0000 -1950 |
1811 | +E: 1331641155.530584 0003 0001 -898 |
1812 | +E: 1331641155.530585 0000 0000 0 |
1813 | +E: 1331641155.546821 0003 0039 1 |
1814 | +E: 1331641155.546822 0003 0030 120 |
1815 | +E: 1331641155.546822 0003 0031 164 |
1816 | +E: 1331641155.546823 0003 0034 0 |
1817 | +E: 1331641155.546824 0003 0035 -1950 |
1818 | +E: 1331641155.546824 0003 0036 -868 |
1819 | +E: 1331641155.546825 0000 0002 0 |
1820 | +E: 1331641155.546826 0003 0039 2 |
1821 | +E: 1331641155.546826 0003 0030 104 |
1822 | +E: 1331641155.546827 0003 0031 168 |
1823 | +E: 1331641155.546828 0003 0034 0 |
1824 | +E: 1331641155.546828 0003 0035 1622 |
1825 | +E: 1331641155.546829 0003 0036 -1416 |
1826 | +E: 1331641155.546830 0000 0002 0 |
1827 | +E: 1331641155.546830 0003 0039 3 |
1828 | +E: 1331641155.546831 0003 0030 156 |
1829 | +E: 1331641155.546831 0003 0031 144 |
1830 | +E: 1331641155.546832 0003 0034 0 |
1831 | +E: 1331641155.546833 0003 0035 -1061 |
1832 | +E: 1331641155.546833 0003 0036 -1483 |
1833 | +E: 1331641155.546834 0000 0002 0 |
1834 | +E: 1331641155.546835 0003 0039 8 |
1835 | +E: 1331641155.546835 0003 0030 164 |
1836 | +E: 1331641155.546836 0003 0031 148 |
1837 | +E: 1331641155.546837 0003 0034 0 |
1838 | +E: 1331641155.546837 0003 0035 247 |
1839 | +E: 1331641155.546838 0003 0036 -1791 |
1840 | +E: 1331641155.546838 0000 0002 0 |
1841 | +E: 1331641155.546842 0003 0001 -868 |
1842 | +E: 1331641155.546842 0000 0000 0 |
1843 | +E: 1331641155.549309 0003 0039 1 |
1844 | +E: 1331641155.549310 0003 0030 132 |
1845 | +E: 1331641155.549310 0003 0031 176 |
1846 | +E: 1331641155.549311 0003 0034 0 |
1847 | +E: 1331641155.549312 0003 0035 -1954 |
1848 | +E: 1331641155.549312 0003 0036 -825 |
1849 | +E: 1331641155.549313 0000 0002 0 |
1850 | +E: 1331641155.549314 0003 0039 2 |
1851 | +E: 1331641155.549314 0003 0030 120 |
1852 | +E: 1331641155.549315 0003 0031 196 |
1853 | +E: 1331641155.549315 0003 0034 0 |
1854 | +E: 1331641155.549316 0003 0035 1616 |
1855 | +E: 1331641155.549317 0003 0036 -1382 |
1856 | +E: 1331641155.549317 0000 0002 0 |
1857 | +E: 1331641155.549318 0003 0039 3 |
1858 | +E: 1331641155.549319 0003 0030 176 |
1859 | +E: 1331641155.549319 0003 0031 180 |
1860 | +E: 1331641155.549320 0003 0034 0 |
1861 | +E: 1331641155.549321 0003 0035 -1056 |
1862 | +E: 1331641155.549321 0003 0036 -1443 |
1863 | +E: 1331641155.549322 0000 0002 0 |
1864 | +E: 1331641155.549323 0003 0039 8 |
1865 | +E: 1331641155.549323 0003 0030 156 |
1866 | +E: 1331641155.549324 0003 0031 152 |
1867 | +E: 1331641155.549325 0003 0034 0 |
1868 | +E: 1331641155.549325 0003 0035 241 |
1869 | +E: 1331641155.549326 0003 0036 -1760 |
1870 | +E: 1331641155.549327 0000 0002 0 |
1871 | +E: 1331641155.549329 0003 0000 -1952 |
1872 | +E: 1331641155.549330 0003 0001 -825 |
1873 | +E: 1331641155.549331 0000 0000 0 |
1874 | +E: 1331641155.551812 0003 0039 1 |
1875 | +E: 1331641155.551813 0003 0030 140 |
1876 | +E: 1331641155.551814 0003 0031 204 |
1877 | +E: 1331641155.551815 0003 0034 0 |
1878 | +E: 1331641155.551815 0003 0035 -1949 |
1879 | +E: 1331641155.551816 0003 0036 -767 |
1880 | +E: 1331641155.551817 0000 0002 0 |
1881 | +E: 1331641155.551817 0003 0039 2 |
1882 | +E: 1331641155.551818 0003 0030 132 |
1883 | +E: 1331641155.551819 0003 0031 208 |
1884 | +E: 1331641155.551819 0003 0034 0 |
1885 | +E: 1331641155.551820 0003 0035 1614 |
1886 | +E: 1331641155.551820 0003 0036 -1331 |
1887 | +E: 1331641155.551821 0000 0002 0 |
1888 | +E: 1331641155.551822 0003 0039 3 |
1889 | +E: 1331641155.551823 0003 0030 176 |
1890 | +E: 1331641155.551823 0003 0031 200 |
1891 | +E: 1331641155.551824 0003 0034 0 |
1892 | +E: 1331641155.551824 0003 0035 -1049 |
1893 | +E: 1331641155.551825 0003 0036 -1387 |
1894 | +E: 1331641155.551826 0000 0002 0 |
1895 | +E: 1331641155.551826 0003 0039 8 |
1896 | +E: 1331641155.551827 0003 0030 168 |
1897 | +E: 1331641155.551828 0003 0031 184 |
1898 | +E: 1331641155.551828 0003 0034 0 |
1899 | +E: 1331641155.551829 0003 0035 238 |
1900 | +E: 1331641155.551829 0003 0036 -1715 |
1901 | +E: 1331641155.551830 0000 0002 0 |
1902 | +E: 1331641155.551833 0003 0000 -1951 |
1903 | +E: 1331641155.551834 0003 0001 -767 |
1904 | +E: 1331641155.551834 0000 0000 0 |
1905 | +E: 1331641155.555561 0003 0039 1 |
1906 | +E: 1331641155.555562 0003 0030 156 |
1907 | +E: 1331641155.555563 0003 0031 216 |
1908 | +E: 1331641155.555563 0003 0034 0 |
1909 | +E: 1331641155.555564 0003 0035 -1940 |
1910 | +E: 1331641155.555565 0003 0036 -705 |
1911 | +E: 1331641155.555565 0000 0002 0 |
1912 | +E: 1331641155.555566 0003 0039 2 |
1913 | +E: 1331641155.555567 0003 0030 120 |
1914 | +E: 1331641155.555567 0003 0031 228 |
1915 | +E: 1331641155.555568 0003 0034 0 |
1916 | +E: 1331641155.555569 0003 0035 1618 |
1917 | +E: 1331641155.555569 0003 0036 -1275 |
1918 | +E: 1331641155.555570 0000 0002 0 |
1919 | +E: 1331641155.555571 0003 0039 3 |
1920 | +E: 1331641155.555571 0003 0030 180 |
1921 | +E: 1331641155.555572 0003 0031 180 |
1922 | +E: 1331641155.555572 0003 0034 0 |
1923 | +E: 1331641155.555573 0003 0035 -1039 |
1924 | +E: 1331641155.555574 0003 0036 -1323 |
1925 | +E: 1331641155.555574 0000 0002 0 |
1926 | +E: 1331641155.555575 0003 0039 8 |
1927 | +E: 1331641155.555576 0003 0030 184 |
1928 | +E: 1331641155.555576 0003 0031 192 |
1929 | +E: 1331641155.555577 0003 0034 -29 |
1930 | +E: 1331641155.555577 0003 0035 240 |
1931 | +E: 1331641155.555578 0003 0036 -1657 |
1932 | +E: 1331641155.555579 0000 0002 0 |
1933 | +E: 1331641155.555581 0003 0000 -1940 |
1934 | +E: 1331641155.555582 0003 0001 -705 |
1935 | +E: 1331641155.555583 0000 0000 0 |
1936 | +E: 1331641155.575560 0003 0039 1 |
1937 | +E: 1331641155.575561 0003 0030 148 |
1938 | +E: 1331641155.575562 0003 0031 208 |
1939 | +E: 1331641155.575563 0003 0034 0 |
1940 | +E: 1331641155.575563 0003 0035 -1928 |
1941 | +E: 1331641155.575564 0003 0036 -629 |
1942 | +E: 1331641155.575565 0000 0002 0 |
1943 | +E: 1331641155.575565 0003 0039 2 |
1944 | +E: 1331641155.575566 0003 0030 116 |
1945 | +E: 1331641155.575567 0003 0031 208 |
1946 | +E: 1331641155.575567 0003 0034 0 |
1947 | +E: 1331641155.575568 0003 0035 1625 |
1948 | +E: 1331641155.575569 0003 0036 -1207 |
1949 | +E: 1331641155.575569 0000 0002 0 |
1950 | +E: 1331641155.575570 0003 0039 3 |
1951 | +E: 1331641155.575571 0003 0030 168 |
1952 | +E: 1331641155.575571 0003 0031 164 |
1953 | +E: 1331641155.575572 0003 0034 0 |
1954 | +E: 1331641155.575573 0003 0035 -1025 |
1955 | +E: 1331641155.575573 0003 0036 -1243 |
1956 | +E: 1331641155.575574 0000 0002 0 |
1957 | +E: 1331641155.575575 0003 0039 8 |
1958 | +E: 1331641155.575575 0003 0030 172 |
1959 | +E: 1331641155.575576 0003 0031 168 |
1960 | +E: 1331641155.575576 0003 0034 0 |
1961 | +E: 1331641155.575577 0003 0035 245 |
1962 | +E: 1331641155.575578 0003 0036 -1591 |
1963 | +E: 1331641155.575578 0000 0002 0 |
1964 | +E: 1331641155.575581 0003 0000 -1928 |
1965 | +E: 1331641155.575582 0003 0001 -629 |
1966 | +E: 1331641155.575582 0000 0000 0 |
1967 | +E: 1331641155.578059 0003 0039 1 |
1968 | +E: 1331641155.578060 0003 0030 152 |
1969 | +E: 1331641155.578061 0003 0031 232 |
1970 | +E: 1331641155.578062 0003 0034 0 |
1971 | +E: 1331641155.578062 0003 0035 -1914 |
1972 | +E: 1331641155.578063 0003 0036 -549 |
1973 | +E: 1331641155.578064 0000 0002 0 |
1974 | +E: 1331641155.578064 0003 0039 2 |
1975 | +E: 1331641155.578065 0003 0030 116 |
1976 | +E: 1331641155.578066 0003 0031 196 |
1977 | +E: 1331641155.578066 0003 0034 0 |
1978 | +E: 1331641155.578067 0003 0035 1632 |
1979 | +E: 1331641155.578068 0003 0036 -1130 |
1980 | +E: 1331641155.578068 0000 0002 0 |
1981 | +E: 1331641155.578069 0003 0039 3 |
1982 | +E: 1331641155.578070 0003 0030 156 |
1983 | +E: 1331641155.578070 0003 0031 176 |
1984 | +E: 1331641155.578071 0003 0034 0 |
1985 | +E: 1331641155.578072 0003 0035 -999 |
1986 | +E: 1331641155.578072 0003 0036 -1120 |
1987 | +E: 1331641155.578073 0000 0002 0 |
1988 | +E: 1331641155.578074 0003 0039 8 |
1989 | +E: 1331641155.578074 0003 0030 188 |
1990 | +E: 1331641155.578074 0003 0031 188 |
1991 | +E: 1331641155.578075 0003 0034 0 |
1992 | +E: 1331641155.578076 0003 0035 253 |
1993 | +E: 1331641155.578076 0003 0036 -1511 |
1994 | +E: 1331641155.578077 0000 0002 0 |
1995 | +E: 1331641155.578080 0003 0000 -1914 |
1996 | +E: 1331641155.578080 0003 0001 -549 |
1997 | +E: 1331641155.578081 0000 0000 0 |
1998 | +E: 1331641155.585562 0003 0039 1 |
1999 | +E: 1331641155.585563 0003 0030 160 |
2000 | +E: 1331641155.585563 0003 0031 208 |
2001 | +E: 1331641155.585564 0003 0034 0 |
2002 | +E: 1331641155.585565 0003 0035 -1893 |
2003 | +E: 1331641155.585565 0003 0036 -424 |
2004 | +E: 1331641155.585566 0000 0002 0 |
2005 | +E: 1331641155.585567 0003 0039 2 |
2006 | +E: 1331641155.585567 0003 0030 124 |
2007 | +E: 1331641155.585568 0003 0031 200 |
2008 | +E: 1331641155.585569 0003 0034 0 |
2009 | +E: 1331641155.585569 0003 0035 1640 |
2010 | +E: 1331641155.585570 0003 0036 -1046 |
2011 | +E: 1331641155.585571 0000 0002 0 |
2012 | +E: 1331641155.585571 0003 0039 3 |
2013 | +E: 1331641155.585572 0003 0030 140 |
2014 | +E: 1331641155.585573 0003 0031 160 |
2015 | +E: 1331641155.585573 0003 0034 0 |
2016 | +E: 1331641155.585574 0003 0035 -958 |
2017 | +E: 1331641155.585575 0003 0036 -924 |
2018 | +E: 1331641155.585575 0000 0002 0 |
2019 | +E: 1331641155.585576 0003 0039 8 |
2020 | +E: 1331641155.585577 0003 0030 192 |
2021 | +E: 1331641155.585577 0003 0031 196 |
2022 | +E: 1331641155.585578 0003 0034 -30 |
2023 | +E: 1331641155.585578 0003 0035 267 |
2024 | +E: 1331641155.585579 0003 0036 -1391 |
2025 | +E: 1331641155.585580 0000 0002 0 |
2026 | +E: 1331641155.585582 0003 0000 -1893 |
2027 | +E: 1331641155.585583 0003 0001 -424 |
2028 | +E: 1331641155.585584 0000 0000 0 |
2029 | +E: 1331641155.605561 0003 0039 1 |
2030 | +E: 1331641155.605562 0003 0030 164 |
2031 | +E: 1331641155.605563 0003 0031 232 |
2032 | +E: 1331641155.605563 0003 0034 0 |
2033 | +E: 1331641155.605564 0003 0035 -1868 |
2034 | +E: 1331641155.605564 0003 0036 -286 |
2035 | +E: 1331641155.605565 0000 0002 0 |
2036 | +E: 1331641155.605566 0003 0039 2 |
2037 | +E: 1331641155.605567 0003 0030 116 |
2038 | +E: 1331641155.605567 0003 0031 204 |
2039 | +E: 1331641155.605568 0003 0034 0 |
2040 | +E: 1331641155.605568 0003 0035 1657 |
2041 | +E: 1331641155.605569 0003 0036 -877 |
2042 | +E: 1331641155.605570 0000 0002 0 |
2043 | +E: 1331641155.605571 0003 0039 3 |
2044 | +E: 1331641155.605571 0003 0030 160 |
2045 | +E: 1331641155.605571 0003 0031 160 |
2046 | +E: 1331641155.605572 0003 0034 0 |
2047 | +E: 1331641155.605573 0003 0035 -934 |
2048 | +E: 1331641155.605573 0003 0036 -805 |
2049 | +E: 1331641155.605574 0000 0002 0 |
2050 | +E: 1331641155.605575 0003 0039 8 |
2051 | +E: 1331641155.605575 0003 0030 196 |
2052 | +E: 1331641155.605576 0003 0031 184 |
2053 | +E: 1331641155.605577 0003 0034 32 |
2054 | +E: 1331641155.605577 0003 0035 285 |
2055 | +E: 1331641155.605578 0003 0036 -1253 |
2056 | +E: 1331641155.605578 0000 0002 0 |
2057 | +E: 1331641155.605581 0003 0000 -1868 |
2058 | +E: 1331641155.605582 0003 0001 -286 |
2059 | +E: 1331641155.605582 0000 0000 0 |
2060 | +E: 1331641155.608299 0003 0039 1 |
2061 | +E: 1331641155.608300 0003 0030 164 |
2062 | +E: 1331641155.608301 0003 0031 236 |
2063 | +E: 1331641155.608302 0003 0034 0 |
2064 | +E: 1331641155.608302 0003 0035 -1842 |
2065 | +E: 1331641155.608303 0003 0036 -135 |
2066 | +E: 1331641155.608304 0000 0002 0 |
2067 | +E: 1331641155.608304 0003 0039 2 |
2068 | +E: 1331641155.608305 0003 0030 132 |
2069 | +E: 1331641155.608306 0003 0031 224 |
2070 | +E: 1331641155.608306 0003 0034 0 |
2071 | +E: 1331641155.608307 0003 0035 1677 |
2072 | +E: 1331641155.608308 0003 0036 -724 |
2073 | +E: 1331641155.608308 0000 0002 0 |
2074 | +E: 1331641155.608309 0003 0039 3 |
2075 | +E: 1331641155.608310 0003 0030 176 |
2076 | +E: 1331641155.608310 0003 0031 160 |
2077 | +E: 1331641155.608311 0003 0034 32 |
2078 | +E: 1331641155.608311 0003 0035 -887 |
2079 | +E: 1331641155.608312 0003 0036 -562 |
2080 | +E: 1331641155.608313 0000 0002 0 |
2081 | +E: 1331641155.608313 0003 0039 8 |
2082 | +E: 1331641155.608314 0003 0030 200 |
2083 | +E: 1331641155.608315 0003 0031 204 |
2084 | +E: 1331641155.608315 0003 0034 0 |
2085 | +E: 1331641155.608316 0003 0035 307 |
2086 | +E: 1331641155.608317 0003 0036 -1102 |
2087 | +E: 1331641155.608317 0000 0002 0 |
2088 | +E: 1331641155.608320 0003 0000 -1842 |
2089 | +E: 1331641155.608321 0003 0001 -135 |
2090 | +E: 1331641155.608321 0000 0000 0 |
2091 | +E: 1331641155.628292 0003 0039 1 |
2092 | +E: 1331641155.628293 0003 0030 176 |
2093 | +E: 1331641155.628293 0003 0031 216 |
2094 | +E: 1331641155.628294 0003 0034 0 |
2095 | +E: 1331641155.628295 0003 0035 -1815 |
2096 | +E: 1331641155.628295 0003 0036 24 |
2097 | +E: 1331641155.628296 0000 0002 0 |
2098 | +E: 1331641155.628297 0003 0039 2 |
2099 | +E: 1331641155.628297 0003 0030 128 |
2100 | +E: 1331641155.628298 0003 0031 204 |
2101 | +E: 1331641155.628299 0003 0034 0 |
2102 | +E: 1331641155.628299 0003 0035 1700 |
2103 | +E: 1331641155.628300 0003 0036 -565 |
2104 | +E: 1331641155.628300 0000 0002 0 |
2105 | +E: 1331641155.628301 0003 0039 3 |
2106 | +E: 1331641155.628302 0003 0030 176 |
2107 | +E: 1331641155.628302 0003 0031 164 |
2108 | +E: 1331641155.628303 0003 0034 0 |
2109 | +E: 1331641155.628304 0003 0035 -863 |
2110 | +E: 1331641155.628304 0003 0036 -435 |
2111 | +E: 1331641155.628305 0000 0002 0 |
2112 | +E: 1331641155.628306 0003 0039 8 |
2113 | +E: 1331641155.628306 0003 0030 200 |
2114 | +E: 1331641155.628307 0003 0031 188 |
2115 | +E: 1331641155.628308 0003 0034 -30 |
2116 | +E: 1331641155.628308 0003 0035 332 |
2117 | +E: 1331641155.628309 0003 0036 -942 |
2118 | +E: 1331641155.628310 0000 0002 0 |
2119 | +E: 1331641155.628312 0003 0000 -1815 |
2120 | +E: 1331641155.628313 0003 0001 24 |
2121 | +E: 1331641155.628314 0000 0000 0 |
2122 | +E: 1331641155.630546 0003 0039 1 |
2123 | +E: 1331641155.630547 0003 0030 168 |
2124 | +E: 1331641155.630548 0003 0031 188 |
2125 | +E: 1331641155.630548 0003 0034 0 |
2126 | +E: 1331641155.630549 0003 0035 -1787 |
2127 | +E: 1331641155.630549 0003 0036 190 |
2128 | +E: 1331641155.630550 0000 0002 0 |
2129 | +E: 1331641155.630551 0003 0039 2 |
2130 | +E: 1331641155.630552 0003 0030 136 |
2131 | +E: 1331641155.630552 0003 0031 204 |
2132 | +E: 1331641155.630553 0003 0034 0 |
2133 | +E: 1331641155.630554 0003 0035 1725 |
2134 | +E: 1331641155.630554 0003 0036 -398 |
2135 | +E: 1331641155.630555 0000 0002 0 |
2136 | +E: 1331641155.630556 0003 0039 3 |
2137 | +E: 1331641155.630556 0003 0030 184 |
2138 | +E: 1331641155.630557 0003 0031 148 |
2139 | +E: 1331641155.630558 0003 0034 32 |
2140 | +E: 1331641155.630558 0003 0035 -830 |
2141 | +E: 1331641155.630559 0003 0036 -246 |
2142 | +E: 1331641155.630559 0000 0002 0 |
2143 | +E: 1331641155.630560 0003 0039 8 |
2144 | +E: 1331641155.630561 0003 0030 204 |
2145 | +E: 1331641155.630561 0003 0031 192 |
2146 | +E: 1331641155.630562 0003 0034 -31 |
2147 | +E: 1331641155.630563 0003 0035 359 |
2148 | +E: 1331641155.630563 0003 0036 -773 |
2149 | +E: 1331641155.630564 0000 0002 0 |
2150 | +E: 1331641155.630567 0003 0000 -1787 |
2151 | +E: 1331641155.630567 0003 0001 190 |
2152 | +E: 1331641155.630568 0000 0000 0 |
2153 | +E: 1331641155.636814 0003 0039 1 |
2154 | +E: 1331641155.636815 0003 0030 156 |
2155 | +E: 1331641155.636815 0003 0031 188 |
2156 | +E: 1331641155.636816 0003 0034 0 |
2157 | +E: 1331641155.636817 0003 0035 -1757 |
2158 | +E: 1331641155.636817 0003 0036 358 |
2159 | +E: 1331641155.636818 0000 0002 0 |
2160 | +E: 1331641155.636819 0003 0039 2 |
2161 | +E: 1331641155.636819 0003 0030 148 |
2162 | +E: 1331641155.636820 0003 0031 204 |
2163 | +E: 1331641155.636821 0003 0034 0 |
2164 | +E: 1331641155.636821 0003 0035 1751 |
2165 | +E: 1331641155.636822 0003 0036 -224 |
2166 | +E: 1331641155.636823 0000 0002 0 |
2167 | +E: 1331641155.636823 0003 0039 3 |
2168 | +E: 1331641155.636824 0003 0030 180 |
2169 | +E: 1331641155.636825 0003 0031 136 |
2170 | +E: 1331641155.636825 0003 0034 0 |
2171 | +E: 1331641155.636826 0003 0035 -800 |
2172 | +E: 1331641155.636826 0003 0036 -58 |
2173 | +E: 1331641155.636827 0000 0002 0 |
2174 | +E: 1331641155.636828 0003 0039 8 |
2175 | +E: 1331641155.636828 0003 0030 184 |
2176 | +E: 1331641155.636829 0003 0031 204 |
2177 | +E: 1331641155.636830 0003 0034 0 |
2178 | +E: 1331641155.636830 0003 0035 388 |
2179 | +E: 1331641155.636831 0003 0036 -601 |
2180 | +E: 1331641155.636832 0000 0002 0 |
2181 | +E: 1331641155.636834 0003 0000 -1757 |
2182 | +E: 1331641155.636835 0003 0001 358 |
2183 | +E: 1331641155.636836 0000 0000 0 |
2184 | +E: 1331641155.656821 0003 0039 1 |
2185 | +E: 1331641155.656822 0003 0030 156 |
2186 | +E: 1331641155.656822 0003 0031 156 |
2187 | +E: 1331641155.656823 0003 0034 0 |
2188 | +E: 1331641155.656824 0003 0035 -1729 |
2189 | +E: 1331641155.656824 0003 0036 529 |
2190 | +E: 1331641155.656825 0000 0002 0 |
2191 | +E: 1331641155.656826 0003 0039 2 |
2192 | +E: 1331641155.656826 0003 0030 144 |
2193 | +E: 1331641155.656827 0003 0031 188 |
2194 | +E: 1331641155.656828 0003 0034 0 |
2195 | +E: 1331641155.656828 0003 0035 1777 |
2196 | +E: 1331641155.656829 0003 0036 -47 |
2197 | +E: 1331641155.656830 0000 0002 0 |
2198 | +E: 1331641155.656830 0003 0039 3 |
2199 | +E: 1331641155.656831 0003 0030 160 |
2200 | +E: 1331641155.656832 0003 0031 132 |
2201 | +E: 1331641155.656832 0003 0034 0 |
2202 | +E: 1331641155.656833 0003 0035 -771 |
2203 | +E: 1331641155.656833 0003 0036 121 |
2204 | +E: 1331641155.656834 0000 0002 0 |
2205 | +E: 1331641155.656835 0003 0039 8 |
2206 | +E: 1331641155.656835 0003 0030 184 |
2207 | +E: 1331641155.656836 0003 0031 208 |
2208 | +E: 1331641155.656837 0003 0034 0 |
2209 | +E: 1331641155.656837 0003 0035 417 |
2210 | +E: 1331641155.656838 0003 0036 -425 |
2211 | +E: 1331641155.656839 0000 0002 0 |
2212 | +E: 1331641155.656842 0003 0000 -1729 |
2213 | +E: 1331641155.656842 0003 0001 529 |
2214 | +E: 1331641155.656843 0000 0000 0 |
2215 | +E: 1331641155.659312 0003 0039 1 |
2216 | +E: 1331641155.659313 0003 0030 148 |
2217 | +E: 1331641155.659314 0003 0031 172 |
2218 | +E: 1331641155.659315 0003 0034 0 |
2219 | +E: 1331641155.659315 0003 0035 -1703 |
2220 | +E: 1331641155.659316 0003 0036 696 |
2221 | +E: 1331641155.659317 0000 0002 0 |
2222 | +E: 1331641155.659317 0003 0039 2 |
2223 | +E: 1331641155.659318 0003 0030 144 |
2224 | +E: 1331641155.659319 0003 0031 204 |
2225 | +E: 1331641155.659319 0003 0034 0 |
2226 | +E: 1331641155.659320 0003 0035 1804 |
2227 | +E: 1331641155.659321 0003 0036 129 |
2228 | +E: 1331641155.659321 0000 0002 0 |
2229 | +E: 1331641155.659322 0003 0039 3 |
2230 | +E: 1331641155.659323 0003 0030 156 |
2231 | +E: 1331641155.659323 0003 0031 128 |
2232 | +E: 1331641155.659324 0003 0034 0 |
2233 | +E: 1331641155.659325 0003 0035 -746 |
2234 | +E: 1331641155.659325 0003 0036 298 |
2235 | +E: 1331641155.659326 0000 0002 0 |
2236 | +E: 1331641155.659327 0003 0039 8 |
2237 | +E: 1331641155.659327 0003 0030 180 |
2238 | +E: 1331641155.659328 0003 0031 160 |
2239 | +E: 1331641155.659328 0003 0034 0 |
2240 | +E: 1331641155.659329 0003 0035 448 |
2241 | +E: 1331641155.659330 0003 0036 -250 |
2242 | +E: 1331641155.659330 0000 0002 0 |
2243 | +E: 1331641155.659333 0003 0000 -1703 |
2244 | +E: 1331641155.659334 0003 0001 696 |
2245 | +E: 1331641155.659334 0000 0000 0 |
2246 | +E: 1331641155.666794 0003 0039 1 |
2247 | +E: 1331641155.666795 0003 0030 152 |
2248 | +E: 1331641155.666795 0003 0031 168 |
2249 | +E: 1331641155.666796 0003 0034 0 |
2250 | +E: 1331641155.666797 0003 0035 -1674 |
2251 | +E: 1331641155.666797 0003 0036 859 |
2252 | +E: 1331641155.666798 0000 0002 0 |
2253 | +E: 1331641155.666799 0003 0039 2 |
2254 | +E: 1331641155.666799 0003 0030 128 |
2255 | +E: 1331641155.666800 0003 0031 184 |
2256 | +E: 1331641155.666801 0003 0034 0 |
2257 | +E: 1331641155.666801 0003 0035 1830 |
2258 | +E: 1331641155.666802 0003 0036 306 |
2259 | +E: 1331641155.666803 0000 0002 0 |
2260 | +E: 1331641155.666803 0003 0039 3 |
2261 | +E: 1331641155.666804 0003 0030 144 |
2262 | +E: 1331641155.666805 0003 0031 124 |
2263 | +E: 1331641155.666805 0003 0034 0 |
2264 | +E: 1331641155.666806 0003 0035 -724 |
2265 | +E: 1331641155.666807 0003 0036 466 |
2266 | +E: 1331641155.666807 0000 0002 0 |
2267 | +E: 1331641155.666808 0003 0039 8 |
2268 | +E: 1331641155.666809 0003 0030 176 |
2269 | +E: 1331641155.666809 0003 0031 192 |
2270 | +E: 1331641155.666810 0003 0034 0 |
2271 | +E: 1331641155.666811 0003 0035 478 |
2272 | +E: 1331641155.666811 0003 0036 -75 |
2273 | +E: 1331641155.666812 0000 0002 0 |
2274 | +E: 1331641155.666815 0003 0000 -1674 |
2275 | +E: 1331641155.666815 0003 0001 859 |
2276 | +E: 1331641155.666816 0000 0000 0 |
2277 | +E: 1331641155.686806 0003 0039 1 |
2278 | +E: 1331641155.686807 0003 0030 140 |
2279 | +E: 1331641155.686808 0003 0031 148 |
2280 | +E: 1331641155.686808 0003 0034 0 |
2281 | +E: 1331641155.686809 0003 0035 -1644 |
2282 | +E: 1331641155.686810 0003 0036 1019 |
2283 | +E: 1331641155.686810 0000 0002 0 |
2284 | +E: 1331641155.686811 0003 0039 2 |
2285 | +E: 1331641155.686812 0003 0030 100 |
2286 | +E: 1331641155.686812 0003 0031 156 |
2287 | +E: 1331641155.686813 0003 0034 0 |
2288 | +E: 1331641155.686814 0003 0035 1859 |
2289 | +E: 1331641155.686814 0003 0036 482 |
2290 | +E: 1331641155.686815 0000 0002 0 |
2291 | +E: 1331641155.686816 0003 0039 3 |
2292 | +E: 1331641155.686816 0003 0030 132 |
2293 | +E: 1331641155.686817 0003 0031 124 |
2294 | +E: 1331641155.686818 0003 0034 0 |
2295 | +E: 1331641155.686818 0003 0035 -711 |
2296 | +E: 1331641155.686819 0003 0036 570 |
2297 | +E: 1331641155.686820 0000 0002 0 |
2298 | +E: 1331641155.686820 0003 0039 8 |
2299 | +E: 1331641155.686821 0003 0030 168 |
2300 | +E: 1331641155.686821 0003 0031 164 |
2301 | +E: 1331641155.686822 0003 0034 0 |
2302 | +E: 1331641155.686823 0003 0035 509 |
2303 | +E: 1331641155.686823 0003 0036 94 |
2304 | +E: 1331641155.686824 0000 0002 0 |
2305 | +E: 1331641155.686827 0003 0000 -1644 |
2306 | +E: 1331641155.686827 0003 0001 1019 |
2307 | +E: 1331641155.686828 0000 0000 0 |
2308 | +E: 1331641155.689315 0003 0039 1 |
2309 | +E: 1331641155.689316 0003 0030 140 |
2310 | +E: 1331641155.689316 0003 0031 160 |
2311 | +E: 1331641155.689317 0003 0034 0 |
2312 | +E: 1331641155.689317 0003 0035 -1622 |
2313 | +E: 1331641155.689318 0003 0036 1115 |
2314 | +E: 1331641155.689319 0000 0002 0 |
2315 | +E: 1331641155.689320 0003 0039 2 |
2316 | +E: 1331641155.689320 0003 0030 92 |
2317 | +E: 1331641155.689321 0003 0031 152 |
2318 | +E: 1331641155.689321 0003 0034 0 |
2319 | +E: 1331641155.689322 0003 0035 1887 |
2320 | +E: 1331641155.689323 0003 0036 654 |
2321 | +E: 1331641155.689323 0000 0002 0 |
2322 | +E: 1331641155.689324 0003 0039 3 |
2323 | +E: 1331641155.689325 0003 0030 120 |
2324 | +E: 1331641155.689325 0003 0031 140 |
2325 | +E: 1331641155.689326 0003 0034 0 |
2326 | +E: 1331641155.689327 0003 0035 -689 |
2327 | +E: 1331641155.689327 0003 0036 717 |
2328 | +E: 1331641155.689328 0000 0002 0 |
2329 | +E: 1331641155.689329 0003 0039 8 |
2330 | +E: 1331641155.689329 0003 0030 168 |
2331 | +E: 1331641155.689330 0003 0031 156 |
2332 | +E: 1331641155.689331 0003 0034 0 |
2333 | +E: 1331641155.689331 0003 0035 538 |
2334 | +E: 1331641155.689332 0003 0036 260 |
2335 | +E: 1331641155.689332 0000 0002 0 |
2336 | +E: 1331641155.689335 0003 0000 -1622 |
2337 | +E: 1331641155.689336 0003 0001 1115 |
2338 | +E: 1331641155.689336 0000 0000 0 |
2339 | +E: 1331641155.709313 0003 0039 1 |
2340 | +E: 1331641155.709314 0003 0030 128 |
2341 | +E: 1331641155.709315 0003 0031 136 |
2342 | +E: 1331641155.709316 0003 0034 0 |
2343 | +E: 1331641155.709316 0003 0035 -1579 |
2344 | +E: 1331641155.709317 0003 0036 1308 |
2345 | +E: 1331641155.709318 0000 0002 0 |
2346 | +E: 1331641155.709318 0003 0039 2 |
2347 | +E: 1331641155.709319 0003 0030 76 |
2348 | +E: 1331641155.709320 0003 0031 144 |
2349 | +E: 1331641155.709320 0003 0034 0 |
2350 | +E: 1331641155.709321 0003 0035 1915 |
2351 | +E: 1331641155.709321 0003 0036 823 |
2352 | +E: 1331641155.709322 0000 0002 0 |
2353 | +E: 1331641155.709323 0003 0039 3 |
2354 | +E: 1331641155.709323 0003 0030 124 |
2355 | +E: 1331641155.709324 0003 0031 132 |
2356 | +E: 1331641155.709325 0003 0034 0 |
2357 | +E: 1331641155.709325 0003 0035 -666 |
2358 | +E: 1331641155.709326 0003 0036 850 |
2359 | +E: 1331641155.709327 0000 0002 0 |
2360 | +E: 1331641155.709327 0003 0039 8 |
2361 | +E: 1331641155.709328 0003 0030 152 |
2362 | +E: 1331641155.709329 0003 0031 160 |
2363 | +E: 1331641155.709329 0003 0034 0 |
2364 | +E: 1331641155.709330 0003 0035 567 |
2365 | +E: 1331641155.709331 0003 0036 417 |
2366 | +E: 1331641155.709331 0000 0002 0 |
2367 | +E: 1331641155.709334 0003 0000 -1579 |
2368 | +E: 1331641155.709335 0003 0001 1308 |
2369 | +E: 1331641155.709335 0000 0000 0 |
2370 | +E: 1331641155.711809 0003 0039 1 |
2371 | +E: 1331641155.711810 0003 0030 108 |
2372 | +E: 1331641155.711811 0003 0031 120 |
2373 | +E: 1331641155.711811 0003 0034 0 |
2374 | +E: 1331641155.711812 0003 0035 -1556 |
2375 | +E: 1331641155.711813 0003 0036 1394 |
2376 | +E: 1331641155.711813 0000 0002 0 |
2377 | +E: 1331641155.711814 0003 0039 2 |
2378 | +E: 1331641155.711815 0003 0030 0 |
2379 | +E: 1331641155.711815 0003 0031 0 |
2380 | +E: 1331641155.711815 0003 0034 0 |
2381 | +E: 1331641155.711816 0003 0035 1915 |
2382 | +E: 1331641155.711817 0003 0036 823 |
2383 | +E: 1331641155.711817 0000 0002 0 |
2384 | +E: 1331641155.711818 0003 0039 3 |
2385 | +E: 1331641155.711819 0003 0030 100 |
2386 | +E: 1331641155.711819 0003 0031 112 |
2387 | +E: 1331641155.711820 0003 0034 0 |
2388 | +E: 1331641155.711820 0003 0035 -649 |
2389 | +E: 1331641155.711821 0003 0036 925 |
2390 | +E: 1331641155.711822 0000 0002 0 |
2391 | +E: 1331641155.711823 0003 0039 8 |
2392 | +E: 1331641155.711823 0003 0030 136 |
2393 | +E: 1331641155.711823 0003 0031 136 |
2394 | +E: 1331641155.711824 0003 0034 0 |
2395 | +E: 1331641155.711825 0003 0035 584 |
2396 | +E: 1331641155.711825 0003 0036 511 |
2397 | +E: 1331641155.711826 0000 0002 0 |
2398 | +E: 1331641155.711829 0003 0000 -1556 |
2399 | +E: 1331641155.711829 0003 0001 1394 |
2400 | +E: 1331641155.711830 0000 0000 0 |
2401 | +E: 1331641155.718302 0003 0039 1 |
2402 | +E: 1331641155.718303 0003 0030 48 |
2403 | +E: 1331641155.718303 0003 0031 88 |
2404 | +E: 1331641155.718304 0003 0034 0 |
2405 | +E: 1331641155.718305 0003 0035 -1523 |
2406 | +E: 1331641155.718305 0003 0036 1525 |
2407 | +E: 1331641155.718306 0000 0002 0 |
2408 | +E: 1331641155.718307 0003 0039 3 |
2409 | +E: 1331641155.718308 0003 0030 100 |
2410 | +E: 1331641155.718308 0003 0031 80 |
2411 | +E: 1331641155.718309 0003 0034 0 |
2412 | +E: 1331641155.718310 0003 0035 -616 |
2413 | +E: 1331641155.718310 0003 0036 1083 |
2414 | +E: 1331641155.718311 0000 0002 0 |
2415 | +E: 1331641155.718312 0003 0039 8 |
2416 | +E: 1331641155.718312 0003 0030 124 |
2417 | +E: 1331641155.718313 0003 0031 92 |
2418 | +E: 1331641155.718313 0003 0034 0 |
2419 | +E: 1331641155.718314 0003 0035 612 |
2420 | +E: 1331641155.718315 0003 0036 644 |
2421 | +E: 1331641155.718315 0000 0002 0 |
2422 | +E: 1331641155.718317 0001 014e 1 |
2423 | +E: 1331641155.718318 0001 014f 0 |
2424 | +E: 1331641155.718319 0003 0000 -1523 |
2425 | +E: 1331641155.718320 0003 0001 1525 |
2426 | +E: 1331641155.718320 0000 0000 0 |
2427 | +E: 1331641155.738295 0003 0039 1 |
2428 | +E: 1331641155.738296 0003 0030 0 |
2429 | +E: 1331641155.738297 0003 0031 0 |
2430 | +E: 1331641155.738297 0003 0034 0 |
2431 | +E: 1331641155.738297 0003 0035 -1523 |
2432 | +E: 1331641155.738298 0003 0036 1525 |
2433 | +E: 1331641155.738299 0000 0002 0 |
2434 | +E: 1331641155.738300 0003 0039 3 |
2435 | +E: 1331641155.738300 0003 0030 120 |
2436 | +E: 1331641155.738301 0003 0031 72 |
2437 | +E: 1331641155.738301 0003 0034 0 |
2438 | +E: 1331641155.738302 0003 0035 -596 |
2439 | +E: 1331641155.738303 0003 0036 1145 |
2440 | +E: 1331641155.738303 0000 0002 0 |
2441 | +E: 1331641155.738304 0003 0039 8 |
2442 | +E: 1331641155.738305 0003 0030 0 |
2443 | +E: 1331641155.738305 0003 0031 0 |
2444 | +E: 1331641155.738305 0003 0034 0 |
2445 | +E: 1331641155.738306 0003 0035 612 |
2446 | +E: 1331641155.738306 0003 0036 644 |
2447 | +E: 1331641155.738307 0000 0002 0 |
2448 | +E: 1331641155.738311 0000 0000 0 |
2449 | +E: 1331641155.740540 0003 0039 3 |
2450 | +E: 1331641155.740541 0003 0030 0 |
2451 | +E: 1331641155.740541 0003 0031 0 |
2452 | +E: 1331641155.740541 0003 0034 0 |
2453 | +E: 1331641155.740542 0003 0035 -596 |
2454 | +E: 1331641155.740543 0003 0036 1145 |
2455 | +E: 1331641155.740543 0000 0002 0 |
2456 | +E: 1331641155.740544 0001 0145 1 |
2457 | +E: 1331641155.740545 0001 014e 0 |
2458 | +E: 1331641155.740546 0000 0000 0 |
2459 | +E: 1331641155.748043 0001 014a 0 |
2460 | +E: 1331641155.748044 0001 0145 0 |
2461 | +E: 1331641155.748044 0000 0000 0 |
2462 | |
2463 | === added file 'test/x11/no-premature-gestures.cpp' |
2464 | --- test/x11/no-premature-gestures.cpp 1970-01-01 00:00:00 +0000 |
2465 | +++ test/x11/no-premature-gestures.cpp 2012-03-14 19:17:21 +0000 |
2466 | @@ -0,0 +1,215 @@ |
2467 | +/***************************************************************************** |
2468 | + * |
2469 | + * grail - Gesture Recognition And Instantiation Library |
2470 | + * |
2471 | + * Copyright (C) 2012 Canonical Ltd. |
2472 | + * |
2473 | + * This program is free software: you can redistribute it and/or modify it |
2474 | + * under the terms of the GNU General Public License as published by the |
2475 | + * Free Software Foundation, either version 3 of the License, or (at your |
2476 | + * option) any later version. |
2477 | + * |
2478 | + * This program is distributed in the hope that it will be useful, but |
2479 | + * WITHOUT ANY WARRANTY; without even the implied warranty of |
2480 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
2481 | + * General Public License for more details. |
2482 | + * |
2483 | + * You should have received a copy of the GNU General Public License along |
2484 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
2485 | + * |
2486 | + ****************************************************************************/ |
2487 | + |
2488 | +/** |
2489 | + * @internal |
2490 | + * @file "No Premature Gestures" Test |
2491 | + * |
2492 | + * This test plays a four-touches' drag where the four fingers land almost in |
2493 | + * sync and checks that only 4-touches' slices are generated. |
2494 | + * Three subscriptions are used: |
2495 | + * (A) An atomic two-touches Touch |
2496 | + * (B) An atomic three-touches Touch |
2497 | + * (C) An atomic four-touches Touch. |
2498 | + * |
2499 | + * It's a regression test for https://bugs.launchpad.net/utouch-grail/+bug/949916 |
2500 | + * |
2501 | + * We don't want to see gestures being unnecessarily created (and therefore |
2502 | + * their slices) for subscriptions (A) and (B) since we already know from the |
2503 | + * very first events that there are four touches in total, not only two or three. |
2504 | + * |
2505 | + * Note that this logic holds only when atomic gesture rules are being used. |
2506 | + */ |
2507 | + |
2508 | +#include <future> |
2509 | +#include <gtest/gtest.h> |
2510 | +#include <utouch/frame_x11.h> |
2511 | + |
2512 | +// evemu wrappers |
2513 | +#include "device.h" |
2514 | +#include "recording.h" |
2515 | + |
2516 | +#include "x11/fixture.h" |
2517 | + |
2518 | +class NoPrematureGestures : public utouch::grail::x11::testing::Test { |
2519 | + public: |
2520 | + NoPrematureGestures() : device_(nullptr) {} |
2521 | + protected: |
2522 | + virtual void ProcessFrameEvents(); |
2523 | + virtual void ProcessGrailEvents(); |
2524 | + |
2525 | + // Holds the device we are interested in getting input from. |
2526 | + // More specifically, the fake one we will create via evemu. |
2527 | + UFDevice device_; |
2528 | + |
2529 | + private: |
2530 | + void ProcessFrameEventDeviceAdded(UFEvent event); |
2531 | + void CreateSubscriptions(); |
2532 | + void CreateSubscription(unsigned int num_touches, |
2533 | + UGGestureTypeMask gesture_mask); |
2534 | + void CheckSlice(UGSlice slice); |
2535 | +}; |
2536 | + |
2537 | +void NoPrematureGestures::ProcessFrameEvents() { |
2538 | + UFEvent event; |
2539 | + |
2540 | + UFStatus status; |
2541 | + while ((status = frame_get_event(frame_handle(), &event)) == UFStatusSuccess) { |
2542 | + grail_process_frame_event(grail_handle(), event); |
2543 | + |
2544 | + if (frame_event_get_type(event) == UFEventTypeDeviceAdded) { |
2545 | + ProcessFrameEventDeviceAdded(event); |
2546 | + } |
2547 | + |
2548 | + frame_event_unref(event); |
2549 | + } |
2550 | + |
2551 | + EXPECT_EQ(UFStatusErrorNoEvent, status); |
2552 | +} |
2553 | + |
2554 | +void NoPrematureGestures::ProcessFrameEventDeviceAdded(UFEvent event) |
2555 | +{ |
2556 | + UFStatus status; |
2557 | + UFDevice device; |
2558 | + const char* name; |
2559 | + |
2560 | + status = frame_event_get_property(event, UFEventPropertyDevice, &device); |
2561 | + ASSERT_EQ(UFStatusSuccess, status); |
2562 | + |
2563 | + status = frame_device_get_property(device, UFDevicePropertyName, &name); |
2564 | + ASSERT_EQ(UFStatusSuccess, status); |
2565 | + |
2566 | + if (strcmp(name, "Apple Wireless Trackpad") == 0) { |
2567 | + EXPECT_EQ(nullptr, device_); |
2568 | + device_ = device; |
2569 | + CreateSubscriptions(); |
2570 | + } |
2571 | +} |
2572 | + |
2573 | +void NoPrematureGestures::CreateSubscriptions() { |
2574 | + CreateSubscription(2, UGGestureTypeTouch); |
2575 | + CreateSubscription(3, UGGestureTypeTouch); |
2576 | + CreateSubscription(4, UGGestureTypeTouch); |
2577 | +} |
2578 | + |
2579 | +void NoPrematureGestures::CreateSubscription(unsigned int num_touches, |
2580 | + UGGestureTypeMask gesture_mask) { |
2581 | + UGSubscription subscription; |
2582 | + UGStatus status; |
2583 | + |
2584 | + status = grail_subscription_new(&subscription); |
2585 | + ASSERT_EQ(UGStatusSuccess, status); |
2586 | + |
2587 | + status = grail_subscription_set_property(subscription, |
2588 | + UGSubscriptionPropertyDevice, |
2589 | + &device_); |
2590 | + ASSERT_EQ(UFStatusSuccess, status); |
2591 | + |
2592 | + UFWindowId window_id = |
2593 | + frame_x11_create_window_id(DefaultRootWindow(Display())); |
2594 | + status = grail_subscription_set_property(subscription, |
2595 | + UGSubscriptionPropertyWindow, |
2596 | + &window_id); |
2597 | + ASSERT_EQ(UFStatusSuccess, status); |
2598 | + |
2599 | + status = grail_subscription_set_property(subscription, |
2600 | + UGSubscriptionPropertyTouchesStart, |
2601 | + &num_touches); |
2602 | + ASSERT_EQ(UFStatusSuccess, status); |
2603 | + |
2604 | + status = grail_subscription_set_property(subscription, |
2605 | + UGSubscriptionPropertyTouchesMaximum, |
2606 | + &num_touches); |
2607 | + ASSERT_EQ(UFStatusSuccess, status); |
2608 | + |
2609 | + status = grail_subscription_set_property(subscription, |
2610 | + UGSubscriptionPropertyTouchesMinimum, |
2611 | + &num_touches); |
2612 | + ASSERT_EQ(UFStatusSuccess, status); |
2613 | + |
2614 | + status = grail_subscription_set_property(subscription, |
2615 | + UGSubscriptionPropertyMask, |
2616 | + &gesture_mask); |
2617 | + ASSERT_EQ(UFStatusSuccess, status); |
2618 | + |
2619 | + int use_atomic_gestures = 1; |
2620 | + status = grail_subscription_set_property(subscription, |
2621 | + UGSubscriptionPropertyAtomicGestures, |
2622 | + &use_atomic_gestures); |
2623 | + ASSERT_EQ(UFStatusSuccess, status); |
2624 | + |
2625 | + status = grail_subscription_activate(grail_handle(), subscription); |
2626 | + ASSERT_EQ(UFStatusSuccess, status); |
2627 | +} |
2628 | + |
2629 | +void NoPrematureGestures::ProcessGrailEvents() { |
2630 | + UGEvent event; |
2631 | + |
2632 | + UGStatus status; |
2633 | + while ((status = grail_get_event(grail_handle(), &event)) == UGStatusSuccess) { |
2634 | + ASSERT_EQ(UGEventTypeSlice, grail_event_get_type(event)); |
2635 | + |
2636 | + UGSlice slice; |
2637 | + status = grail_event_get_property(event, UGEventPropertySlice, &slice); |
2638 | + ASSERT_EQ(UGStatusSuccess, status); |
2639 | + |
2640 | + CheckSlice(slice); |
2641 | + |
2642 | + grail_event_unref(event); |
2643 | + } |
2644 | + |
2645 | + EXPECT_EQ(UGStatusErrorNoEvent, status); |
2646 | +} |
2647 | + |
2648 | +void NoPrematureGestures::CheckSlice(UGSlice slice) { |
2649 | + UGStatus status; |
2650 | + unsigned int num_touches; |
2651 | + |
2652 | + status = grail_slice_get_property(slice, UGSlicePropertyNumTouches, |
2653 | + &num_touches); |
2654 | + ASSERT_EQ(UGStatusSuccess, status); |
2655 | + |
2656 | + // The main point of this test: |
2657 | + // Check that we don't get any slices from a 2 or 3 touches gesture. |
2658 | + EXPECT_EQ(4, num_touches) |
2659 | + << "Got a slice with " << num_touches << " touches from a synced 4-fingers drag."; |
2660 | +} |
2661 | + |
2662 | +TEST_F(NoPrematureGestures, Recording) { |
2663 | + utouch::evemu::Device device("recordings/apple-wireless-trackpad.prop"); |
2664 | + |
2665 | + /* Pump once to ensure the X server has initialized the device */ |
2666 | + PumpEvents(); |
2667 | + ASSERT_NE(device_, nullptr) << "X server failed to initialize trackpad"; |
2668 | + |
2669 | + utouch::evemu::Recording recording(device, "recordings/apple-wtrackpad-synced-4-drag.event"); |
2670 | + |
2671 | + /* We use the c++11 future module so any exceptions thrown by the thread can |
2672 | + * be caught later on. If we used the thread module, exceptions would take the |
2673 | + * whole thing down. */ |
2674 | + std::future<void> future = std::async(std::launch::async, |
2675 | + &utouch::evemu::Recording::Play, |
2676 | + &recording); |
2677 | + |
2678 | + PumpEvents(); |
2679 | + |
2680 | + future.wait(); |
2681 | +} |
* In AtomicRecognize r::HandleNewTou chesForAccepted Gesture( ), when a gesture is ended you have the following comment:
// OBS: Should they also go back to unaccepted_touches_ here?
An accepted touch cannot return to an unaccepted state. This is a property of the window manager, and of touch handling in general. If one client uses a touch, no one else may use the touch, period.
* Please use /* */ style comments for consistency.
* The fix for the bug involves dropping touch events until a timeout period is reached. This will make the gesture recognition inconsistent because the beginning frame event of a gesture will be indeterminate. If the user rolls the touches onto the touchpad vs putting them down all at once, the recognition might behave differently.
I think a better approach would be to prevent a gesture from becoming fully recognized until the construction finished timeout is reached.
* The test looks good, and I like the subclassing of recognizers :).