Merge lp:~oif-team/grail/trunk.fixes into lp:grail

Proposed by Henrik Rydberg
Status: Superseded
Proposed branch: lp:~oif-team/grail/trunk.fixes
Merge into: lp:grail
Diff against target: 613 lines (+162/-202)
11 files modified
src/evbuf.h (+1/-1)
src/gestures-drag.c (+14/-0)
src/gestures-pinch.c (+15/-1)
src/gestures-rotate.c (+15/-1)
src/gestures-tapping.c (+6/-2)
src/grail-api.c (+90/-162)
src/grail-event.c (+2/-16)
src/grail-gestures.c (+14/-7)
src/grail-gestures.h (+3/-2)
src/grail-impl.h (+2/-0)
src/grail-recognizer.h (+0/-10)
To merge this branch: bzr merge lp:~oif-team/grail/trunk.fixes
Reviewer Review Type Date Requested Status
Chase Douglas Pending
Stephen M. Webb Pending
Review via email: mp+51210@code.launchpad.net

This proposal supersedes a proposal from 2011-02-24.

This proposal has been superseded by a proposal from 2011-02-24.

Description of the change

A bunch of patches aiming to integrate the ideas of v1.0.19 more seamlessly into the grail code. This will fix the remaining tap bug and help further development. The only part not addressed by this branch is the sysflag, and a discussion around it is likely enough to see how to form a patch for it.

To post a comment you must log in.
Revision history for this message
Stephen M. Webb (bregma) wrote : Posted in a previous version of this proposal

A more elegant and nuanced way of handling the various timeout issues. Compiles and runs OK.

review: Approve
Revision history for this message
Chase Douglas (chasedouglas) wrote : Posted in a previous version of this proposal

In line 371 of the patch below, there's an ambiguity in the if statement "if (a || b && c)". This should be cleaned up.

I need to test this branch, but I think the changes look reasonable. However, I can't approve the request until it also handles the global flag. This is something I think we will really need in natty, since we're going to have more applications using gestures.

review: Needs Fixing
Revision history for this message
Chase Douglas (chasedouglas) wrote : Posted in a previous version of this proposal

Test results:

1. Regression: If you use a physical trackpad button to click while there's no movement on the trackpad, it's held up until a movement is performed.

2. Timeouts seem ok. I was able to request all 3, 4, and 5 finger gestures and still perform two finger multitouch reasonably. I will perform more thorough testing when the regressions are resolved.

3. Regression: I often get a tap event at the end of a drag gesture sequence. The tap touch count matches the drag touch count.

review: Needs Fixing
Revision history for this message
Henrik Rydberg (rydberg) wrote : Posted in a previous version of this proposal

Thank you very much for the tests! I have updated the branch with fixes for
the two problems found. I will add something for the global flag shortly.

Revision history for this message
Henrik Rydberg (rydberg) wrote :

Fix of the fix - the first regression was pretty complex, and revealed some
additional assumptions that were not true. Hopefully this version will do better.

lp:~oif-team/grail/trunk.fixes updated
115. By Henrik Rydberg

Revert "Add button passthrough"

116. By Henrik Rydberg

Revert "Add global vs local gesture handling"

117. By Henrik Rydberg

Introduce gesture timeouts

The timeout of a gesture is integral to the gesture type.
This patch introduces timeout per gesture type, potentially
enabling more control over gesture timing aspects. The timeout
logic replaces the recently added recognition state.

118. By Henrik Rydberg

Introduce activation hold time

Do not activate a drag, pinch or rotate immediately, even
if the activation threshold is met. This allows for a smoother
transition between fingers.

119. By Henrik Rydberg

Wait for the right number of fingers before gesture timeout

A client listening only for multi-finger gestures will not get
the chance to recognize unless there is a gesture timeout. This
patch waits until the drag hold time has passed before releasing
the touch.

120. By Henrik Rydberg

Skip events selectively

Buffer all events as planned, but strip the stream of all events
involved with pointer and MT, rather than bluntly removing all
events. In practise, this means button and switch events are let
through, undistorted although possibly slightly delayed.

121. By Henrik Rydberg

Adjust gesture buffer sizes and timings

Adjust timings to put drag, pinch and rotate on more equal footing,
with regard to gesture timeouts. Also make sure events are not lost
during hold, now that all MT events are buffered as well.

122. By Henrik Rydberg

Reset tap state after timeout

A touch and hold will not properly reset the tap state, such that
the next tap fails to register. Fixed with this patch.

123. By Henrik Rydberg

Remove unused tapping state

This patch removes some cruft that was left over from the
removal of the short tap time logic.

124. By Henrik Rydberg

Make reset logic of pinch and drag same as for drag

There is no direct reason for one-fingered pinch/rotate gestures
to be discarded immediately, so only reset gestures on touch down,
as for drags.

125. By Henrik Rydberg

Make grabbing client exclusive

When a possible gesture is started for a global client (sysflag set),
it is desirable that gestures to other clients are disregarded until
all contacts have left the surface. In principle this could be refined
further, such that if gesture are not detected, they are passed on to
other clients, but that also affects how touches are passed onto lower
layers like XI2.1, so simply making sure a global system client gets
all events potentially leading to gestures is good enough for now.

Also note that in the current combination of synaptics/evdev X servers
and grail, there can be no overlapping potential gestures between two
global clients, or the resulting event recipient is not correct.

126. By Henrik Rydberg

Bump to v1.0.20

127. By Henrik Rydberg

Disable rotation gestures for semi-mt devices

To avoid poor user experience with semi-mt devices, disable
rotation detection, such that only drag and scale is emitted.

Signed-off-by: Chase Douglas <email address hidden>
Signed-off-by: Henrik Rydberg <email address hidden>

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/evbuf.h'
2--- src/evbuf.h 2010-08-06 20:30:20 +0000
3+++ src/evbuf.h 2011-02-24 22:54:44 +0000
4@@ -29,7 +29,7 @@
5 #ifndef GRAIL_EVBUF_H
6 #define GRAIL_EVBUF_H
7
8-#define DIM_EVENTS 512
9+#define DIM_EVENTS 4096
10
11 struct evbuf {
12 int head;
13
14=== modified file 'src/gestures-drag.c'
15--- src/gestures-drag.c 2011-01-02 12:08:08 +0000
16+++ src/gestures-drag.c 2011-02-24 22:54:44 +0000
17@@ -72,6 +72,13 @@
18 state->active = 0;
19 }
20 }
21+ if ((move->timeout & fm_mask) == fm_mask) {
22+ if (state->active) {
23+ gin_gid_discard(ge, state->gid);
24+ state->active = 0;
25+ }
26+ return 0;
27+ }
28 if (!state->active) {
29 int type = getype[move->ntouch];
30 if (type < 0)
31@@ -102,6 +109,13 @@
32 state->active = 0;
33 }
34 }
35+ if ((move->timeout & fm_mask) == fm_mask) {
36+ if (state->active) {
37+ gin_gid_discard(ge, state->gid);
38+ state->active = 0;
39+ }
40+ return 0;
41+ }
42 if (!state->active) {
43 if (move->ntouch == 4) {
44 state->gid = gin_gid_begin(ge, GRAIL_TYPE_MDRAG,
45
46=== modified file 'src/gestures-pinch.c'
47--- src/gestures-pinch.c 2011-01-02 12:08:08 +0000
48+++ src/gestures-pinch.c 2011-02-24 22:54:44 +0000
49@@ -54,7 +54,7 @@
50 struct combo_model *state = &gru->pinch;
51 struct move_model *move = &gru->move;
52 int mask = state->active ? (move->active & fm_mask) : fm_mask;
53- if (!move->multi) {
54+ if (!move->multi && !move->single) {
55 if (state->active) {
56 gru_end(ge, state->gid, move,
57 state->prop, state->nprop);
58@@ -62,6 +62,13 @@
59 }
60 return 0;
61 }
62+ if ((move->timeout & fm_mask) == fm_mask) {
63+ if (state->active) {
64+ gin_gid_discard(ge, state->gid);
65+ state->active = 0;
66+ }
67+ return 0;
68+ }
69 if (!(move->tickle & mask))
70 return 0;
71 if (!state->active) {
72@@ -93,6 +100,13 @@
73 }
74 return 0;
75 }
76+ if ((move->timeout & fm_mask) == fm_mask) {
77+ if (state->active) {
78+ gin_gid_discard(ge, state->gid);
79+ state->active = 0;
80+ }
81+ return 0;
82+ }
83 if (!(move->tickle & mask))
84 return 0;
85 if (!state->active) {
86
87=== modified file 'src/gestures-rotate.c'
88--- src/gestures-rotate.c 2011-01-02 12:08:08 +0000
89+++ src/gestures-rotate.c 2011-02-24 22:54:44 +0000
90@@ -53,7 +53,7 @@
91 struct combo_model *state = &gru->rotate;
92 struct move_model *move = &gru->move;
93 int mask = state->active ? (move->active & fm_mask) : fm_mask;
94- if (!move->multi) {
95+ if (!move->multi && !move->single) {
96 if (state->active) {
97 gru_end(ge, state->gid, move,
98 state->prop, state->nprop);
99@@ -61,6 +61,13 @@
100 }
101 return 0;
102 }
103+ if ((move->timeout & fm_mask) == fm_mask) {
104+ if (state->active) {
105+ gin_gid_discard(ge, state->gid);
106+ state->active = 0;
107+ }
108+ return 0;
109+ }
110 if (!(move->tickle & mask))
111 return 0;
112 if (!state->active) {
113@@ -92,6 +99,13 @@
114 }
115 return 0;
116 }
117+ if ((move->timeout & fm_mask) == fm_mask) {
118+ if (state->active) {
119+ gin_gid_discard(ge, state->gid);
120+ state->active = 0;
121+ }
122+ return 0;
123+ }
124 if (!(move->tickle & mask))
125 return 0;
126 if (!state->active) {
127
128=== modified file 'src/gestures-tapping.c'
129--- src/gestures-tapping.c 2011-02-09 15:17:50 +0000
130+++ src/gestures-tapping.c 2011-02-24 22:54:44 +0000
131@@ -43,8 +43,10 @@
132 struct tapping_model *state = &gru->tapping;
133 struct move_model *move = &gru->move;
134 state->tap = 0;
135- if (move->ntouch && move->ntouch < state->mintouch)
136- state->end = move->time;
137+ if (frame->num_active && !frame->prev->num_active) {
138+ state->mintouch = 0;
139+ state->maxtouch = 0;
140+ }
141 if (move->ntouch > state->maxtouch) {
142 if (state->active) {
143 gin_gid_discard(ge, state->gid);
144@@ -91,6 +93,8 @@
145 if ((move->active & fm_mask) ||
146 move->time - state->start > move->fm[FM_X].bar_ms) {
147 gin_gid_discard(ge, state->gid);
148+ state->mintouch = move->ntouch;
149+ state->maxtouch = move->ntouch;
150 state->active = 0;
151 }
152 return 0;
153
154=== modified file 'src/grail-api.c'
155--- src/grail-api.c 2011-02-21 01:22:08 +0000
156+++ src/grail-api.c 2011-02-24 22:54:44 +0000
157@@ -34,11 +34,6 @@
158 #define DIM_FRAMES 100
159 #define FRAME_RATE 100
160
161-/* Wait time (ms) for number of touches to stabilize. */
162-static const unsigned int stable_time = 50;
163-/* Maximum time (ms) for gesture to be recognized. */
164-static const unsigned int recognition_time = 300;
165-
166 void grail_filter_abs_events(struct grail *ge, int usage)
167 {
168 struct grail_impl *x = ge->impl;
169@@ -132,62 +127,72 @@
170 max->y = s->max_y;
171 }
172
173-/* Check for any potential gestures given the number of touch points and where
174- * they occur on screen. */
175-static int check_potential_gestures(struct grail *ge,
176- const struct utouch_frame *frame)
177-{
178- grail_mask_t types[DIM_GRAIL_TYPE_BYTES] = {0};
179- struct grail_client_info client;
180- struct grail_coord pos[frame->num_active];
181- int i;
182-
183- switch (frame->num_active) {
184- case 1:
185- grail_mask_set(types, GRAIL_TYPE_DRAG1);
186- grail_mask_set(types, GRAIL_TYPE_PINCH1);
187- grail_mask_set(types, GRAIL_TYPE_ROTATE1);
188- grail_mask_set(types, GRAIL_TYPE_TAP1);
189- break;
190- case 2:
191- grail_mask_set(types, GRAIL_TYPE_DRAG2);
192- grail_mask_set(types, GRAIL_TYPE_PINCH2);
193- grail_mask_set(types, GRAIL_TYPE_ROTATE2);
194- grail_mask_set(types, GRAIL_TYPE_TAP2);
195- break;
196- case 3:
197- grail_mask_set(types, GRAIL_TYPE_DRAG3);
198- grail_mask_set(types, GRAIL_TYPE_PINCH3);
199- grail_mask_set(types, GRAIL_TYPE_ROTATE3);
200- grail_mask_set(types, GRAIL_TYPE_TAP3);
201- grail_mask_set(types, GRAIL_TYPE_EDRAG);
202- grail_mask_set(types, GRAIL_TYPE_EPINCH);
203- grail_mask_set(types, GRAIL_TYPE_EROTATE);
204- break;
205- case 4:
206- grail_mask_set(types, GRAIL_TYPE_DRAG4);
207- grail_mask_set(types, GRAIL_TYPE_PINCH4);
208- grail_mask_set(types, GRAIL_TYPE_ROTATE4);
209- grail_mask_set(types, GRAIL_TYPE_TAP4);
210- grail_mask_set(types, GRAIL_TYPE_MDRAG);
211- grail_mask_set(types, GRAIL_TYPE_MPINCH);
212- grail_mask_set(types, GRAIL_TYPE_MROTATE);
213- break;
214- case 5:
215- grail_mask_set(types, GRAIL_TYPE_DRAG5);
216- grail_mask_set(types, GRAIL_TYPE_PINCH5);
217- grail_mask_set(types, GRAIL_TYPE_ROTATE5);
218- grail_mask_set(types, GRAIL_TYPE_TAP5);
219- break;
220- }
221-
222- for (i = 0; i < frame->num_active; i++) {
223- pos[i].x = gin_prop_x(ge->gin, frame->active[i]->x);
224- pos[i].y = gin_prop_y(ge->gin, frame->active[i]->y);
225- }
226-
227- return ge->get_clients(ge, &client, 1, pos, frame->num_active,
228- types, DIM_GRAIL_TYPE_BYTES);
229+static void flush_events(struct grail *ge)
230+{
231+ struct grail_impl *impl = ge->impl;
232+ struct input_event iev;
233+
234+ grailbuf_clear(&impl->gbuf);
235+ while (!evbuf_empty(&impl->evbuf)) {
236+ evbuf_get(&impl->evbuf, &iev);
237+ if (ge->event)
238+ ge->event(ge, &iev);
239+ }
240+}
241+
242+static int skip_event(const struct input_event *ev, int count)
243+{
244+ switch (ev->type) {
245+ case EV_ABS:
246+ return 1;
247+ case EV_KEY:
248+ return ev->code >= BTN_DIGI && ev->code < BTN_WHEEL;
249+ case EV_SYN:
250+ switch (ev->code) {
251+ case SYN_MT_REPORT:
252+ return 1;
253+ case SYN_REPORT:
254+ return count == 0;
255+ default:
256+ return 0;
257+ }
258+ default:
259+ return 0;
260+ }
261+}
262+
263+static void flush_gestures(struct grail *ge)
264+{
265+ struct grail_impl *impl = ge->impl;
266+ struct input_event iev;
267+ struct grail_event gev;
268+ int count = 0;
269+
270+ while (!evbuf_empty(&impl->evbuf)) {
271+ evbuf_get(&impl->evbuf, &iev);
272+ if (skip_event(&iev, count))
273+ continue;
274+ if (ge->event)
275+ ge->event(ge, &iev);
276+ if (iev.type == EV_SYN && iev.code == SYN_REPORT)
277+ count = 0;
278+ else
279+ count++;
280+ }
281+ while (!grailbuf_empty(&impl->gbuf)) {
282+ grailbuf_get(&impl->gbuf, &gev);
283+ if (ge->gesture)
284+ ge->gesture(ge, &gev);
285+ }
286+}
287+
288+static int gesture_timeout(struct grail *ge, const struct utouch_frame *frame)
289+{
290+ struct gesture_recognizer *gru = ge->gru;
291+ struct gesture_inserter *gin = ge->gin;
292+
293+ return grail_mask_count(gin->used, sizeof(gin->used)) == 0 &&
294+ frame->time - frame->mod_time > gru->move.fm[FM_X].hold_ms;
295 }
296
297 static void report_frame(struct grail *ge,
298@@ -195,96 +200,27 @@
299 const struct input_event *syn)
300 {
301 struct grail_impl *impl = ge->impl;
302- struct gesture_recognizer *gru = ge->gru;
303- struct input_event iev;
304 struct grail_event gev;
305
306 ge->impl->frame = frame;
307
308- /* Reset timer when number of touches changes. */
309- if (frame->prev->revision != frame->revision && frame->num_active) {
310- gru->start_time = frame->time;
311- }
312-
313- /* Once touches have stabilized, check if there are any potential
314- * gestures registered for the number of touches. */
315- if (gru->state == RECOGNIZING &&
316- frame->time > gru->start_time + stable_time &&
317- check_potential_gestures(ge, frame) == 0)
318- gru->state = UNRECOGNIZED;
319-
320- /* Process the frame for gestures unless we're sure there are none. */
321- if (gru->state != UNRECOGNIZED) {
322- gin_frame_begin(ge, frame);
323- gru_recognize(ge, frame);
324- gin_frame_end(ge, frame);
325- }
326-
327- if (gru->state == RECOGNIZING) {
328- /* If a gesture is recognized and either all touches lifted or
329- * we are within the recognition interval, set state to
330- * recognized. Note that taps do not stay in the used array, so
331- * we must check if any gesture events are buffered. */
332- if ((grail_mask_count(ge->gin->used, DIM_INSTANCE_BYTES) ||
333- !grailbuf_empty(&impl->gbuf)) &&
334- (frame->num_active == 0 ||
335- (frame->time > gru->start_time + stable_time &&
336- frame->time <= gru->start_time + recognition_time))) {
337- if (gru->global_client)
338- gru->state = GLOBAL;
339- else
340- gru->state = LOCAL;
341- }
342- /* If there is no gesture and all touches lifted, set state to
343- * unrecognized. */
344- else if (frame->num_active == 0)
345- gru->state = UNRECOGNIZED;
346- }
347-
348- /* Now we have the state set, process events. */
349- switch (gru->state) {
350- case LOCAL:
351- case GLOBAL:
352- while (!grailbuf_empty(&impl->gbuf)) {
353- grailbuf_get(&impl->gbuf, &gev);
354- if (ge->gesture &&
355- ((gru->state == GLOBAL &&
356- gev.client_id.client == gru->global_client) ||
357- (gru->state == LOCAL &&
358- gev.client_id.client != gru->global_client)))
359- ge->gesture(ge, &gev);
360- }
361- evbuf_clear(&impl->evbuf);
362-
363- /* Once all touches are lifted and no gestures are
364- * active, reset recognition state. */
365- if (grail_mask_count(ge->gin->used, DIM_INSTANCE_BYTES) == 0 &&
366- frame->num_active == 0) {
367- gru->state = RECOGNIZING;
368- gru->global_client = 0;
369- }
370- break;
371-
372- case RECOGNIZING:
373- /* If we're still actively recognizing, stop here. */
374- if (frame->time <= gru->start_time + recognition_time)
375- break;
376- gru->state = UNRECOGNIZED;
377-
378- case UNRECOGNIZED:
379- while (!evbuf_empty(&impl->evbuf)) {
380- evbuf_get(&impl->evbuf, &iev);
381- if (ge->event)
382- ge->event(ge, &iev);
383- }
384- grailbuf_clear(&impl->gbuf);
385-
386- if (frame->num_active == 0) {
387- gru->state = RECOGNIZING;
388- gru->global_client = 0;
389- }
390- break;
391- }
392+ if (frame->num_active && !frame->prev->num_active) {
393+ impl->ongoing = 1;
394+ impl->gesture = 0;
395+ }
396+
397+ if (!impl->ongoing)
398+ return;
399+
400+ gin_frame_begin(ge, frame);
401+ gru_recognize(ge, frame);
402+ gin_frame_end(ge, frame);
403+
404+ if (!grailbuf_empty(&impl->gbuf))
405+ impl->gesture = 1;
406+
407+ if (frame->num_active == 0 || gesture_timeout(ge, frame))
408+ impl->ongoing &= impl->gesture;
409 }
410
411 static void grail_pump_mtdev(struct grail *ge, const struct input_event *ev)
412@@ -292,21 +228,6 @@
413 struct grail_impl *impl = ge->impl;
414 const struct utouch_frame *frame;
415
416- if (ev->type == EV_KEY && (ev->code < BTN_DIGI ||
417- ev->code > BTN_TOOL_QUADTAP)) {
418- struct input_event sync_ev;
419-
420- ge->event(ge, ev);
421-
422- sync_ev.type = EV_SYN;
423- sync_ev.code = SYN_REPORT;
424- sync_ev.value = 1;
425- sync_ev.time = ev->time;
426- ge->event(ge, &sync_ev);
427-
428- return;
429- }
430-
431 evbuf_put(&impl->evbuf, ev);
432
433 if (ev->type == EV_SYN || ev->type == EV_ABS) {
434@@ -314,6 +235,13 @@
435 if (frame)
436 report_frame(ge, frame, ev);
437 }
438+
439+ if (ev->type == EV_SYN) {
440+ if (!impl->ongoing)
441+ flush_events(ge);
442+ if (impl->gesture)
443+ flush_gestures(ge);
444+ }
445 }
446
447 int grail_pull(struct grail *ge, int fd)
448
449=== modified file 'src/grail-event.c'
450--- src/grail-event.c 2011-02-09 15:12:13 +0000
451+++ src/grail-event.c 2011-02-24 22:54:44 +0000
452@@ -22,7 +22,6 @@
453
454 #include "grail-inserter.h"
455 #include "grail-impl.h"
456-#include "grail-recognizer.h"
457 #include <malloc.h>
458 #include <string.h>
459 #include <errno.h>
460@@ -83,7 +82,7 @@
461 const struct utouch_frame *frame)
462 {
463 struct grail_coord pos[DIM_TOUCH];
464- int i, npos = 0, num_clients;
465+ int i, npos = 0;
466 if (!ge->get_clients)
467 return 0;
468 grail_mask_foreach(i, span, bspan) {
469@@ -91,20 +90,7 @@
470 pos[npos].y = gin_prop_y(ge->gin, frame->slots[i]->y);
471 npos++;
472 }
473-
474- num_clients = ge->get_clients(ge, info, maxinfo, pos, npos, types,
475- btypes);
476-
477- /* Check if client is handling global gestures, using SYSFLAG1. */
478- if (num_clients > 0 && grail_mask_get(info[0].mask,
479- GRAIL_TYPE_SYSFLAG1)) {
480- /* Save client id, and clear SYSFLAG1 as it isn't a real
481- * gesture type. */
482- ge->gru->global_client = info[0].id.client;
483- grail_mask_clear(info[0].mask, GRAIL_TYPE_SYSFLAG1);
484- }
485-
486- return num_clients;
487+ return ge->get_clients(ge, info, maxinfo, pos, npos, types, btypes);
488 }
489
490 void gin_send_event(struct grail *ge, struct slot_state *s,
491
492=== modified file 'src/grail-gestures.c'
493--- src/grail-gestures.c 2011-01-02 12:08:08 +0000
494+++ src/grail-gestures.c 2011-02-24 22:54:44 +0000
495@@ -24,9 +24,10 @@
496 #include "grail-impl.h"
497 #include <math.h>
498
499-static const float FM_SN[DIM_FM] = { 1000, 1000, 200, 1000 };
500-static const float FM_BAR[DIM_FM] = { 50, 50, 30, 50 };
501-static const grail_time_t FM_BAR_MS[DIM_FM] = { 300, 300, 10000, 10000 };
502+static const float FM_SN[DIM_FM] = { 1000, 1000, 1000, 1000 };
503+static const float FM_BAR[DIM_FM] = { 50, 50, 50, 50 };
504+static const grail_time_t FM_HOLD_MS[DIM_FM] = { 60, 60, 60, 60 };
505+static const grail_time_t FM_BAR_MS[DIM_FM] = { 300, 300, 500, 500 };
506 static const grail_time_t SAMPLE_MS = 10;
507 static const float EPS = 1e-3;
508
509@@ -111,6 +112,7 @@
510 fm->sample_ms = t;
511 m->tickle &= ~(1 << i);
512 m->active &= ~(1 << i);
513+ m->timeout &= ~(1 << i);
514 }
515
516 static void move_update(struct move_model *m, int i, float x, grail_time_t t)
517@@ -132,11 +134,15 @@
518 if (m->active & (1 << i))
519 return;
520 fm->action_delta = x - fm->original;
521- if (fabs(fm->action_delta) > fm->bar ||
522- t - fm->original_ms > fm->bar_ms)
523- m->active |= (1 << i);
524- else
525+ if (t - fm->original_ms > fm->hold_ms &&
526+ fabs(fm->action_delta) > fm->bar) {
527+ m->active |= (1 << i);
528+ } else if (t - fm->original_ms > fm->bar_ms) {
529+ m->active |= (1 << i);
530+ m->timeout |= (1 << i);
531+ } else {
532 fm->action_delta = 0;
533+ }
534 }
535
536 void gru_init_motion(struct grail *ge)
537@@ -153,6 +159,7 @@
538 for (i = 0; i < DIM_FM; i++) {
539 m->fm[i].fuzz = D[i] / FM_SN[i];
540 m->fm[i].bar = D[i] / FM_BAR[i];
541+ m->fm[i].hold_ms = FM_HOLD_MS[i];
542 m->fm[i].bar_ms = FM_BAR_MS[i];
543 }
544 }
545
546=== modified file 'src/grail-gestures.h'
547--- src/grail-gestures.h 2011-01-02 12:08:08 +0000
548+++ src/grail-gestures.h 2011-02-24 22:54:44 +0000
549@@ -49,12 +49,13 @@
550 float bar;
551 grail_time_t original_ms;
552 grail_time_t sample_ms;
553+ grail_time_t hold_ms;
554 grail_time_t bar_ms;
555 };
556
557 struct move_model {
558 struct filter_model fm[DIM_FM];
559- int tickle, active;
560+ int tickle, active, timeout;
561 int single, multi, ntouch;
562 grail_time_t time;
563 };
564@@ -97,7 +98,7 @@
565 const struct utouch_frame *frame);
566
567 struct tapping_model {
568- grail_time_t start, end;
569+ grail_time_t start;
570 int mintouch, maxtouch;
571 int active, gid, tap;
572 int nprop;
573
574=== modified file 'src/grail-impl.h'
575--- src/grail-impl.h 2011-02-02 22:16:20 +0000
576+++ src/grail-impl.h 2011-02-24 22:54:44 +0000
577@@ -42,6 +42,8 @@
578 struct evbuf evbuf;
579 struct grailbuf gbuf;
580 int filter_abs;
581+ int ongoing;
582+ int gesture;
583 };
584
585 #endif
586
587=== modified file 'src/grail-recognizer.h'
588--- src/grail-recognizer.h 2011-02-09 15:12:13 +0000
589+++ src/grail-recognizer.h 2011-02-24 22:54:44 +0000
590@@ -25,13 +25,6 @@
591
592 #include "grail-gestures.h"
593
594-enum recognition_state {
595- RECOGNIZING,
596- LOCAL,
597- GLOBAL,
598- UNRECOGNIZED
599-};
600-
601 struct gesture_recognizer {
602 struct move_model move;
603 struct combo_model drag;
604@@ -41,9 +34,6 @@
605 struct combo_model winpinch;
606 struct combo_model winrotate;
607 struct tapping_model tapping;
608- utouch_frame_time_t start_time;
609- enum recognition_state state;
610- int global_client;
611 };
612
613 int gru_init(struct grail *ge);

Subscribers

People subscribed via source and target branches

to all changes: