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

Proposed by Henrik Rydberg
Status: Superseded
Proposed branch: lp:~oif-team/grail/trunk.touch
Merge into: lp:grail
Diff against target: 454 lines (+194/-29)
12 files modified
include/grail-types.h (+29/-0)
src/Makefile.am (+1/-0)
src/gestures-drag.c (+4/-8)
src/gestures-pinch.c (+2/-6)
src/gestures-rotate.c (+2/-6)
src/gestures-touch.c (+94/-0)
src/grail-gestures.c (+6/-7)
src/grail-gestures.h (+4/-0)
src/grail-inserter.c (+45/-2)
src/grail-inserter.h (+3/-0)
src/grail-recognizer.c (+2/-0)
src/grail-recognizer.h (+2/-0)
To merge this branch: bzr merge lp:~oif-team/grail/trunk.touch
Reviewer Review Type Date Requested Status
Open Input Framework Team Pending
Review via email: mp+54930@code.launchpad.net

This proposal supersedes a proposal from 2011-03-25.

This proposal has been superseded by a proposal from 2011-03-26.

Description of the change

This patchset introduces gesture touch events.

To post a comment you must log in.
Revision history for this message
Chase Douglas (chasedouglas) wrote : Posted in a previous version of this proposal

I'm guessing the functionality is correct, but the header file is missing the TOUCH event attributes (just like there are separate DRAG, PINCH, ROTATE, etc. attributes).

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

Seems like a mid-air collision - it seems they are present now.

lp:~oif-team/grail/trunk.touch updated
133. By Henrik Rydberg

Introduce touch gesture events

Touch gesture events follow the same logic as drags, except they
cannot be held back but are emitted immediately.

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

134. By Henrik Rydberg

Decouple timeout from discard

Move the actual gesture discard from the recognition phase
to the instantiation phase.

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

135. By Henrik Rydberg

Do not timeout gestures overlapping touch gestures

The notion of listening to touch gestures implies that the
touches of those gestures never timeout. Hence, any pending
gesture that overlaps those touches should not timeout.

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

136. By Henrik Rydberg

Never active gestures below activation threshold

Currently, all gestures activate after a certain time, such that
the smallest change result in gesture events. This was designed
to minimize disruption in pointer movement. Since grail no longer
handles pointers, the logic can be simplified to only activate when
the threshold is reached.

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

137. By Henrik Rydberg

Do not treat single finger activation differently

Single-finger drags should no longer behave differently from
any other drag gesture. Fixed with this patch.

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

138. By Henrik Rydberg

Do not hold back active gestures

Gestures that has once been sent should never be held back. The
current code would under some circumstance hold the gesture end
event and later discard it. This oneliner solves the problem, which
has been around since 241c5ec, Aug 2010. LP: #744391.

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 'include/grail-types.h'
2--- include/grail-types.h 2010-08-19 20:36:11 +0000
3+++ include/grail-types.h 2011-03-26 07:17:27 +0000
4@@ -59,11 +59,21 @@
5
6 #define GRAIL_TYPE_SYSFLAG1 26 /* reserved system flag */
7
8+/* touch event types use drag properties */
9+#define GRAIL_TYPE_TOUCH1 32 /* one-finger touch */
10+#define GRAIL_TYPE_TOUCH2 33 /* two-finger touch */
11+#define GRAIL_TYPE_TOUCH3 34 /* three-finger touch */
12+#define GRAIL_TYPE_TOUCH4 35 /* four-finger touch */
13+#define GRAIL_TYPE_TOUCH5 36 /* five-finger touch */
14+#define GRAIL_TYPE_ETOUCH 37 /* three-finger environment touch */
15+#define GRAIL_TYPE_MTOUCH 38 /* four-finger meta touch */
16+
17 #define GRAIL_MAIN_DRAG 0
18 #define GRAIL_MAIN_PINCH 1
19 #define GRAIL_MAIN_ROTATE 2
20 #define GRAIL_MAIN_TAP 3
21 #define GRAIL_MAIN_SYSFLAG 4
22+#define GRAIL_MAIN_TOUCH 5
23
24 #define GRAIL_PROP_DRAG_DX 0 /* horizontal position delta */
25 #define GRAIL_PROP_DRAG_DY 1 /* vertical position delta */
26@@ -160,5 +170,24 @@
27 #define GRAIL_PROP_TAP_X_T4 20
28 #define GRAIL_PROP_TAP_Y_T4 21
29
30+#define GRAIL_PROP_TOUCH_X1 0 /* bounding box x1 */
31+#define GRAIL_PROP_TOUCH_Y1 1 /* bounding box y1 */
32+#define GRAIL_PROP_TOUCH_X2 2 /* bounding box x2 */
33+#define GRAIL_PROP_TOUCH_Y2 3 /* bounding box y2 */
34+#define GRAIL_PROP_TOUCH_ID_T0 4 /* first touch id */
35+#define GRAIL_PROP_TOUCH_X_T0 5 /* first touch horizontal position */
36+#define GRAIL_PROP_TOUCH_Y_T0 6 /* first touch vertical position */
37+#define GRAIL_PROP_TOUCH_ID_T1 7
38+#define GRAIL_PROP_TOUCH_X_T1 8
39+#define GRAIL_PROP_TOUCH_Y_T1 9
40+#define GRAIL_PROP_TOUCH_ID_T2 10
41+#define GRAIL_PROP_TOUCH_X_T2 11
42+#define GRAIL_PROP_TOUCH_Y_T2 12
43+#define GRAIL_PROP_TOUCH_ID_T3 13
44+#define GRAIL_PROP_TOUCH_X_T3 14
45+#define GRAIL_PROP_TOUCH_Y_T3 15
46+#define GRAIL_PROP_TOUCH_ID_T4 16
47+#define GRAIL_PROP_TOUCH_X_T4 17
48+#define GRAIL_PROP_TOUCH_Y_T4 18
49
50 #endif
51
52=== modified file 'src/Makefile.am'
53--- src/Makefile.am 2011-01-02 12:08:42 +0000
54+++ src/Makefile.am 2011-03-26 07:17:27 +0000
55@@ -17,6 +17,7 @@
56 grail-inserter.h \
57 grail-gestures.c \
58 grail-gestures.h \
59+ gestures-touch.c \
60 gestures-drag.c \
61 gestures-pinch.c \
62 gestures-rotate.c \
63
64=== modified file 'src/gestures-drag.c'
65--- src/gestures-drag.c 2011-03-17 09:48:13 +0000
66+++ src/gestures-drag.c 2011-03-26 07:17:27 +0000
67@@ -70,10 +70,8 @@
68 }
69 if ((move->timeout & fm_mask) == fm_mask) {
70 if (state->active) {
71- gin_gid_discard(ge, state->gid);
72- state->active = 0;
73+ gin_gid_timeout(ge, state->gid);
74 }
75- return 0;
76 }
77 if (!state->active) {
78 int type = getype[move->ntouch];
79@@ -84,7 +82,7 @@
80 }
81 if (!(move->tickle & mask))
82 return 0;
83- if (!move->single && !(move->active & fm_mask))
84+ if (!(move->active & fm_mask))
85 return 0;
86 set_props(ge->gin, state, move, frame);
87 gru_event(ge, state->gid, move, state->prop, state->nprop);
88@@ -107,10 +105,8 @@
89 }
90 if ((move->timeout & fm_mask) == fm_mask) {
91 if (state->active) {
92- gin_gid_discard(ge, state->gid);
93- state->active = 0;
94+ gin_gid_timeout(ge, state->gid);
95 }
96- return 0;
97 }
98 if (!state->active) {
99 if (move->ntouch == 4) {
100@@ -131,7 +127,7 @@
101 }
102 if (!(move->tickle & mask))
103 return 0;
104- if (!move->single && !(move->active & fm_mask))
105+ if (!(move->active & fm_mask))
106 return 0;
107 set_props(ge->gin, state, move, frame);
108 gru_event(ge, state->gid, move, state->prop, state->nprop);
109
110=== modified file 'src/gestures-pinch.c'
111--- src/gestures-pinch.c 2011-03-17 09:48:13 +0000
112+++ src/gestures-pinch.c 2011-03-26 07:17:27 +0000
113@@ -64,10 +64,8 @@
114 }
115 if ((move->timeout & fm_mask) == fm_mask) {
116 if (state->active) {
117- gin_gid_discard(ge, state->gid);
118- state->active = 0;
119+ gin_gid_timeout(ge, state->gid);
120 }
121- return 0;
122 }
123 if (!(move->tickle & mask))
124 return 0;
125@@ -102,10 +100,8 @@
126 }
127 if ((move->timeout & fm_mask) == fm_mask) {
128 if (state->active) {
129- gin_gid_discard(ge, state->gid);
130- state->active = 0;
131+ gin_gid_timeout(ge, state->gid);
132 }
133- return 0;
134 }
135 if (!(move->tickle & mask))
136 return 0;
137
138=== modified file 'src/gestures-rotate.c'
139--- src/gestures-rotate.c 2011-02-24 22:51:33 +0000
140+++ src/gestures-rotate.c 2011-03-26 07:17:27 +0000
141@@ -63,10 +63,8 @@
142 }
143 if ((move->timeout & fm_mask) == fm_mask) {
144 if (state->active) {
145- gin_gid_discard(ge, state->gid);
146- state->active = 0;
147+ gin_gid_timeout(ge, state->gid);
148 }
149- return 0;
150 }
151 if (!(move->tickle & mask))
152 return 0;
153@@ -101,10 +99,8 @@
154 }
155 if ((move->timeout & fm_mask) == fm_mask) {
156 if (state->active) {
157- gin_gid_discard(ge, state->gid);
158- state->active = 0;
159+ gin_gid_timeout(ge, state->gid);
160 }
161- return 0;
162 }
163 if (!(move->tickle & mask))
164 return 0;
165
166=== added file 'src/gestures-touch.c'
167--- src/gestures-touch.c 1970-01-01 00:00:00 +0000
168+++ src/gestures-touch.c 2011-03-26 07:17:27 +0000
169@@ -0,0 +1,94 @@
170+/*****************************************************************************
171+ *
172+ * grail - Gesture Recognition And Instantiation Library
173+ *
174+ * Copyright (C) 2010 Canonical Ltd.
175+ * Copyright (C) 2010 Henrik Rydberg <rydberg@bitmath.org>
176+ *
177+ * This program is free software: you can redistribute it and/or modify it
178+ * under the terms of the GNU General Public License as published by the
179+ * Free Software Foundation, either version 3 of the License, or (at your
180+ * option) any later version.
181+ *
182+ * This program is distributed in the hope that it will be useful, but
183+ * WITHOUT ANY WARRANTY; without even the implied warranty of
184+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
185+ * General Public License for more details.
186+ *
187+ * You should have received a copy of the GNU General Public License along
188+ * with this program. If not, see <http://www.gnu.org/licenses/>.
189+ *
190+ ****************************************************************************/
191+
192+#include "grail-recognizer.h"
193+#include <math.h>
194+#include <stdio.h>
195+
196+static const int getype[DIM_TOUCH + 1] = {
197+ -1,
198+ GRAIL_TYPE_TOUCH1,
199+ GRAIL_TYPE_TOUCH2,
200+ GRAIL_TYPE_TOUCH3,
201+ GRAIL_TYPE_TOUCH4,
202+ GRAIL_TYPE_TOUCH5,
203+};
204+
205+int gru_touch(struct grail *ge,
206+ const struct utouch_frame *frame)
207+{
208+ struct gesture_recognizer *gru = ge->gru;
209+ struct combo_model *state = &gru->touch;
210+ struct move_model *move = &gru->move;
211+ if (frame->slot_revision != frame->prev->slot_revision) {
212+ if (state->active) {
213+ gru_end(ge, state->gid, move,
214+ state->prop, state->nprop);
215+ state->active = 0;
216+ }
217+ }
218+ if (!state->active) {
219+ int type = getype[move->ntouch];
220+ if (type <= 0)
221+ return 0;
222+ state->gid = gin_gid_begin(ge, type, -PRIO_GESTURE, frame);
223+ state->active = 1;
224+ }
225+ state->nprop = gin_add_contact_props(ge->gin, state->prop, frame);
226+ gru_event(ge, state->gid, move, state->prop, state->nprop);
227+ return 1;
228+}
229+
230+int gru_wintouch(struct grail *ge,
231+ const struct utouch_frame *frame)
232+{
233+ struct gesture_recognizer *gru = ge->gru;
234+ struct combo_model *state = &gru->wintouch;
235+ struct move_model *move = &gru->move;
236+ if (frame->slot_revision != frame->prev->slot_revision) {
237+ if (state->active && out_of_bounds(state, move)) {
238+ gru_end(ge, state->gid, move,
239+ state->prop, state->nprop);
240+ state->active = 0;
241+ }
242+ }
243+ if (!state->active) {
244+ if (move->ntouch == 4) {
245+ state->gid = gin_gid_begin(ge, GRAIL_TYPE_MTOUCH,
246+ -PRIO_META, frame);
247+ state->mintouch = 1;
248+ state->maxtouch = 4;
249+ state->active = 1;
250+ } else if (move->ntouch == 3) {
251+ state->gid = gin_gid_begin(ge, GRAIL_TYPE_ETOUCH,
252+ -PRIO_ENV, frame);
253+ state->mintouch = 1;
254+ state->maxtouch = 3;
255+ state->active = 1;
256+ } else {
257+ return 0;
258+ }
259+ }
260+ state->nprop = gin_add_contact_props(ge->gin, state->prop, frame);
261+ gru_event(ge, state->gid, move, state->prop, state->nprop);
262+ return 1;
263+}
264
265=== modified file 'src/grail-gestures.c'
266--- src/grail-gestures.c 2011-03-17 09:48:13 +0000
267+++ src/grail-gestures.c 2011-03-26 07:17:27 +0000
268@@ -133,15 +133,14 @@
269 m->tickle &= ~(1 << i);
270 if (m->active & (1 << i))
271 return;
272- fm->action_delta = x - fm->original;
273- if (t - fm->original_ms > fm->hold_ms &&
274- fabs(fm->action_delta) > fm->bar) {
275- m->active |= (1 << i);
276+ fm->action_delta = 0;
277+ if (fabs(x - fm->original) > fm->bar) {
278+ if (t - fm->original_ms > fm->hold_ms) {
279+ m->active |= (1 << i);
280+ fm->action_delta = x - fm->original;
281+ }
282 } else if (t - fm->original_ms > fm->bar_ms) {
283- m->active |= (1 << i);
284 m->timeout |= (1 << i);
285- } else {
286- fm->action_delta = 0;
287 }
288 }
289
290
291=== modified file 'src/grail-gestures.h'
292--- src/grail-gestures.h 2011-02-24 22:51:17 +0000
293+++ src/grail-gestures.h 2011-03-26 07:17:27 +0000
294@@ -77,6 +77,8 @@
295 grail_prop_t prop[DIM_GRAIL_PROP];
296 };
297
298+int gru_touch(struct grail *ge,
299+ const struct utouch_frame *frame);
300 int gru_drag(struct grail *ge,
301 const struct utouch_frame *frame);
302 int gru_pinch(struct grail *ge,
303@@ -90,6 +92,8 @@
304 return m->ntouch < s->mintouch || m->ntouch > s->maxtouch;
305 }
306
307+int gru_wintouch(struct grail *ge,
308+ const struct utouch_frame *frame);
309 int gru_windrag(struct grail *ge,
310 const struct utouch_frame *frame);
311 int gru_winpinch(struct grail *ge,
312
313=== modified file 'src/grail-inserter.c'
314--- src/grail-inserter.c 2011-03-17 09:48:13 +0000
315+++ src/grail-inserter.c 2011-03-26 07:17:27 +0000
316@@ -38,6 +38,18 @@
317 return -1;
318 }
319
320+static int mask_overlap(const grail_mask_t *a, const grail_mask_t *b,
321+ int bytes)
322+{
323+ int i;
324+
325+ for (i = 0; i < bytes; i++)
326+ if (a[i] & b[i])
327+ return 1;
328+
329+ return 0;
330+}
331+
332 // todo: spanning tree for multi-user case
333 static void setup_new_gestures(struct grail *ge,
334 const struct utouch_frame *frame)
335@@ -114,8 +126,10 @@
336 void gin_frame_end(struct grail *ge, const struct utouch_frame *frame)
337 {
338 struct gesture_inserter *gin = ge->gin;
339+ grail_mask_t keep[DIM_TOUCH_BYTES];
340 int i, hold = 0, discard = 0;
341
342+ memset(keep, 0, sizeof(keep));
343 setup_new_gestures(ge, frame);
344
345 grail_mask_foreach(i, gin->used, sizeof(gin->used)) {
346@@ -138,9 +152,24 @@
347
348 grail_mask_foreach(i, gin->used, sizeof(gin->used)) {
349 struct slot_state *s = &gin->state[i];
350+ if (!s->allowhold)
351+ grail_mask_set_mask(keep, s->span, sizeof(keep));
352+ }
353+
354+ grail_mask_foreach(i, gin->used, sizeof(gin->used)) {
355+ struct slot_state *s = &gin->state[i];
356+ if (!s->timeout)
357+ continue;
358+ if (mask_overlap(keep, s->span, sizeof(keep)))
359+ continue;
360+ gin_gid_discard(ge, s->id);
361+ }
362+
363+ grail_mask_foreach(i, gin->used, sizeof(gin->used)) {
364+ struct slot_state *s = &gin->state[i];
365 struct gesture_event ev;
366 grail_mask_set(gin->types, s->type);
367- if (s->priority < hold)
368+ if (s->priority < hold && s->allowhold)
369 continue;
370 while (!gebuf_empty(&s->buf)) {
371 gebuf_get(&s->buf, &ev);
372@@ -166,7 +195,14 @@
373 return -1;
374 s = &gin->state[i];
375 s->type = type;
376- s->priority = priority;
377+ if (priority < 0) {
378+ s->priority = -priority;
379+ s->allowhold = 0;
380+ } else {
381+ s->priority = priority;
382+ s->allowhold = 1;
383+ }
384+ s->timeout = 0;
385 s->id = gin->gestureid++ & MAX_GESTURE_ID;
386 s->status = GRAIL_STATUS_BEGIN;
387 s->nclient = 0;
388@@ -193,6 +229,13 @@
389 grail_mask_set(gin->unused, i);
390 }
391
392+void gin_gid_timeout(struct grail *ge, int gid)
393+{
394+ int i = find_gslot(ge->gin, gid);
395+ if (i >= 0)
396+ ge->gin->state[i].timeout = 1;
397+}
398+
399 void gin_gid_event(struct grail *ge, int gid,
400 float x, float y, int ntouch,
401 const grail_prop_t *prop, int nprop,
402
403=== modified file 'src/grail-inserter.h'
404--- src/grail-inserter.h 2011-03-17 09:48:13 +0000
405+++ src/grail-inserter.h 2011-03-26 07:17:27 +0000
406@@ -37,6 +37,8 @@
407 struct slot_state {
408 int type;
409 int priority;
410+ int allowhold;
411+ int timeout;
412 int id;
413 int status;
414 int nclient;
415@@ -78,6 +80,7 @@
416 int gin_gid_begin(struct grail *ge, int type, int priority,
417 const struct utouch_frame *frame);
418 void gin_gid_discard(struct grail *ge, int gid);
419+void gin_gid_timeout(struct grail *ge, int gid);
420
421 void gin_gid_event(struct grail *ge, int gid,
422 float x, float y, int ntouch,
423
424=== modified file 'src/grail-recognizer.c'
425--- src/grail-recognizer.c 2011-01-02 12:08:08 +0000
426+++ src/grail-recognizer.c 2011-03-26 07:17:27 +0000
427@@ -47,9 +47,11 @@
428 if (!ge->gin || !ge->gru)
429 return;
430 gru_motion(ge, frame);
431+ gru_touch(ge, frame);
432 gru_drag(ge, frame);
433 gru_pinch(ge, frame);
434 gru_rotate(ge, frame);
435+ gru_wintouch(ge, frame);
436 gru_windrag(ge, frame);
437 gru_winpinch(ge, frame);
438 gru_winrotate(ge, frame);
439
440=== modified file 'src/grail-recognizer.h'
441--- src/grail-recognizer.h 2011-02-24 22:49:22 +0000
442+++ src/grail-recognizer.h 2011-03-26 07:17:27 +0000
443@@ -27,9 +27,11 @@
444
445 struct gesture_recognizer {
446 struct move_model move;
447+ struct combo_model touch;
448 struct combo_model drag;
449 struct combo_model pinch;
450 struct combo_model rotate;
451+ struct combo_model wintouch;
452 struct combo_model windrag;
453 struct combo_model winpinch;
454 struct combo_model winrotate;

Subscribers

People subscribed via source and target branches

to all changes: