summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/grail-api.c154
-rw-r--r--src/grail-recognizer.h8
2 files changed, 144 insertions, 18 deletions
diff --git a/src/grail-api.c b/src/grail-api.c
index 22724ee..1071825 100644
--- a/src/grail-api.c
+++ b/src/grail-api.c
@@ -34,6 +34,11 @@
34#define DIM_FRAMES 100 34#define DIM_FRAMES 100
35#define FRAME_RATE 100 35#define FRAME_RATE 100
36 36
37/* Wait time (ms) for number of touches to stabilize. */
38static const unsigned int stable_time = 50;
39/* Maximum time (ms) for gesture to be recognized. */
40static const unsigned int recognition_time = 200;
41
37void grail_filter_abs_events(struct grail *ge, int usage) 42void grail_filter_abs_events(struct grail *ge, int usage)
38{ 43{
39 struct grail_impl *x = ge->impl; 44 struct grail_impl *x = ge->impl;
@@ -127,34 +132,147 @@ void grail_get_units(const struct grail *ge,
127 max->y = s->max_y; 132 max->y = s->max_y;
128} 133}
129 134
135/* Check for any potential gestures given the number of touch points and where
136 * they occur on screen. */
137static int check_potential_gestures(struct grail *ge,
138 const struct utouch_frame *frame)
139{
140 grail_mask_t types[DIM_GRAIL_TYPE_BYTES] = {0};
141 struct grail_client_info client;
142 struct grail_coord pos[frame->num_active];
143 int i;
144
145 switch (frame->num_active) {
146 case 1:
147 grail_mask_set(types, GRAIL_TYPE_DRAG1);
148 grail_mask_set(types, GRAIL_TYPE_PINCH1);
149 grail_mask_set(types, GRAIL_TYPE_ROTATE1);
150 grail_mask_set(types, GRAIL_TYPE_TAP1);
151 break;
152 case 2:
153 grail_mask_set(types, GRAIL_TYPE_DRAG2);
154 grail_mask_set(types, GRAIL_TYPE_PINCH2);
155 grail_mask_set(types, GRAIL_TYPE_ROTATE2);
156 grail_mask_set(types, GRAIL_TYPE_TAP2);
157 break;
158 case 3:
159 grail_mask_set(types, GRAIL_TYPE_DRAG3);
160 grail_mask_set(types, GRAIL_TYPE_PINCH3);
161 grail_mask_set(types, GRAIL_TYPE_ROTATE3);
162 grail_mask_set(types, GRAIL_TYPE_TAP3);
163 grail_mask_set(types, GRAIL_TYPE_EDRAG);
164 grail_mask_set(types, GRAIL_TYPE_EPINCH);
165 grail_mask_set(types, GRAIL_TYPE_EROTATE);
166 break;
167 case 4:
168 grail_mask_set(types, GRAIL_TYPE_DRAG4);
169 grail_mask_set(types, GRAIL_TYPE_PINCH4);
170 grail_mask_set(types, GRAIL_TYPE_ROTATE4);
171 grail_mask_set(types, GRAIL_TYPE_TAP4);
172 grail_mask_set(types, GRAIL_TYPE_MDRAG);
173 grail_mask_set(types, GRAIL_TYPE_MPINCH);
174 grail_mask_set(types, GRAIL_TYPE_MROTATE);
175 break;
176 case 5:
177 grail_mask_set(types, GRAIL_TYPE_DRAG5);
178 grail_mask_set(types, GRAIL_TYPE_PINCH5);
179 grail_mask_set(types, GRAIL_TYPE_ROTATE5);
180 grail_mask_set(types, GRAIL_TYPE_TAP5);
181 break;
182 }
183
184 for (i = 0; i < frame->num_active; i++) {
185 pos[i].x = gin_prop_x(ge->gin, frame->active[i]->x);
186 pos[i].y = gin_prop_y(ge->gin, frame->active[i]->y);
187 }
188
189 return ge->get_clients(ge, &client, 1, pos, frame->num_active,
190 types, DIM_GRAIL_TYPE_BYTES);
191}
192
130static void report_frame(struct grail *ge, 193static void report_frame(struct grail *ge,
131 const struct utouch_frame *frame, 194 const struct utouch_frame *frame,
132 const struct input_event *syn) 195 const struct input_event *syn)
133{ 196{
134
135 struct grail_impl *impl = ge->impl; 197 struct grail_impl *impl = ge->impl;
198 struct gesture_recognizer *gru = ge->gru;
136 struct input_event iev; 199 struct input_event iev;
137 struct grail_event gev; 200 struct grail_event gev;
138 201
139 ge->impl->frame = frame; 202 ge->impl->frame = frame;
140 203
141 gin_frame_begin(ge, frame); 204 /* Reset timer when number of touches changes. */
142 gru_recognize(ge, frame); 205 if (frame->prev->revision != frame->revision && frame->num_active) {
143 gin_frame_end(ge, frame); 206 gru->start_time = frame->time;
144 207 }
145 if (grailbuf_empty(&impl->gbuf)) { 208
146 while (!evbuf_empty(&impl->evbuf)) { 209 /* Once touches have stabilized, check if there are any potential
147 evbuf_get(&impl->evbuf, &iev); 210 * gestures registered for the number of touches. */
148 if (ge->event) 211 if (gru->state == RECOGNIZING &&
149 ge->event(ge, &iev); 212 frame->time > gru->start_time + stable_time &&
150 } 213 check_potential_gestures(ge, frame) == 0)
151 } else { 214 gru->state = UNRECOGNIZED;
152 while (!grailbuf_empty(&impl->gbuf)) { 215
153 grailbuf_get(&impl->gbuf, &gev); 216 /* Process the frame for gestures unless we're sure there are none. */
154 if (ge->gesture) 217 if (gru->state != UNRECOGNIZED) {
155 ge->gesture(ge, &gev); 218 gin_frame_begin(ge, frame);
156 } 219 gru_recognize(ge, frame);
157 evbuf_clear(&impl->evbuf); 220 gin_frame_end(ge, frame);
221 }
222
223 if (gru->state == RECOGNIZING) {
224 /* If a gesture is recognized and either all touches lifted or
225 * we are within the recognition interval, set state to
226 * recognized. Note that taps do not stay in the used array, so
227 * we must check if any gesture events are buffered. */
228 if ((grail_mask_count(ge->gin->used, DIM_INSTANCE_BYTES) ||
229 !grailbuf_empty(&impl->gbuf)) &&
230 (frame->num_active == 0 ||
231 (frame->time > gru->start_time + stable_time &&
232 frame->time <= gru->start_time + recognition_time)))
233 gru->state = RECOGNIZED;
234 /* If there is no gesture and all touches lifted, set state to
235 * unrecognized. */
236 else if (frame->num_active == 0)
237 gru->state = UNRECOGNIZED;
238 }
239
240 /* Now we have the state set, process events. */
241 switch (gru->state) {
242 case RECOGNIZED:
243 while (!grailbuf_empty(&impl->gbuf)) {
244 grailbuf_get(&impl->gbuf, &gev);
245 if (ge->gesture)
246 ge->gesture(ge, &gev);
247 }
248 evbuf_clear(&impl->evbuf);
249
250 /* Once all touches are lifted and no gestures are
251 * active, reset recognition state. */
252 if (grail_mask_count(ge->gin->used, DIM_INSTANCE_BYTES) == 0 &&
253 frame->num_active == 0)
254 gru->state = RECOGNIZING;
255 break;
256
257 case RECOGNIZING:
258 /* If we're still actively recognizing, stop here. */
259 if (frame->time <= gru->start_time + recognition_time)
260 break;
261 gru->state = UNRECOGNIZED;
262
263 case UNRECOGNIZED:
264 while (!evbuf_empty(&impl->evbuf)) {
265 evbuf_get(&impl->evbuf, &iev);
266 if (ge->event)
267 ge->event(ge, &iev);
268 }
269 grailbuf_clear(&impl->gbuf);
270
271 /* Once all touches are lifted, reset recognition
272 * state. */
273 if (frame->num_active == 0)
274 gru->state = RECOGNIZING;
275 break;
158 } 276 }
159} 277}
160 278
diff --git a/src/grail-recognizer.h b/src/grail-recognizer.h
index 56e5b8d..b08ff34 100644
--- a/src/grail-recognizer.h
+++ b/src/grail-recognizer.h
@@ -25,6 +25,12 @@
25 25
26#include "grail-gestures.h" 26#include "grail-gestures.h"
27 27
28enum recognition_state {
29 RECOGNIZING,
30 RECOGNIZED,
31 UNRECOGNIZED
32};
33
28struct gesture_recognizer { 34struct gesture_recognizer {
29 struct move_model move; 35 struct move_model move;
30 struct combo_model drag; 36 struct combo_model drag;
@@ -34,6 +40,8 @@ struct gesture_recognizer {
34 struct combo_model winpinch; 40 struct combo_model winpinch;
35 struct combo_model winrotate; 41 struct combo_model winrotate;
36 struct tapping_model tapping; 42 struct tapping_model tapping;
43 utouch_frame_time_t start_time;
44 enum recognition_state state;
37}; 45};
38 46
39int gru_init(struct grail *ge); 47int gru_init(struct grail *ge);