diff options
| author | Henrik Rydberg <rydberg@euromail.se> | 2011-02-24 23:38:01 +0100 |
|---|---|---|
| committer | Henrik Rydberg <rydberg@euromail.se> | 2011-03-14 12:55:19 +0100 |
| commit | f92c18c344c04a2501e01ae402441a92883da382 (patch) | |
| tree | fec506ca8784002083babe767505930be2a8d25a /src/grail-api.c | |
| parent | 609e367b3ee2b587f698b65393aa22357f453add (diff) | |
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.
Signed-off-by: Henrik Rydberg <rydberg@euromail.se>
Diffstat (limited to 'src/grail-api.c')
| -rw-r--r-- | src/grail-api.c | 173 |
1 files changed, 46 insertions, 127 deletions
diff --git a/src/grail-api.c b/src/grail-api.c index 1071825..6521f84 100644 --- a/src/grail-api.c +++ b/src/grail-api.c | |||
| @@ -34,11 +34,6 @@ | |||
| 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. */ | ||
| 38 | static const unsigned int stable_time = 50; | ||
| 39 | /* Maximum time (ms) for gesture to be recognized. */ | ||
| 40 | static const unsigned int recognition_time = 200; | ||
| 41 | |||
| 42 | void grail_filter_abs_events(struct grail *ge, int usage) | 37 | void grail_filter_abs_events(struct grail *ge, int usage) |
| 43 | { | 38 | { |
| 44 | struct grail_impl *x = ge->impl; | 39 | struct grail_impl *x = ge->impl; |
| @@ -132,62 +127,37 @@ void grail_get_units(const struct grail *ge, | |||
| 132 | max->y = s->max_y; | 127 | max->y = s->max_y; |
| 133 | } | 128 | } |
| 134 | 129 | ||
| 135 | /* Check for any potential gestures given the number of touch points and where | 130 | static void flush_events(struct grail *ge) |
| 136 | * they occur on screen. */ | ||
| 137 | static int check_potential_gestures(struct grail *ge, | ||
| 138 | const struct utouch_frame *frame) | ||
| 139 | { | 131 | { |
| 140 | grail_mask_t types[DIM_GRAIL_TYPE_BYTES] = {0}; | 132 | struct grail_impl *impl = ge->impl; |
| 141 | struct grail_client_info client; | 133 | struct input_event ev; |
| 142 | struct grail_coord pos[frame->num_active]; | 134 | |
| 143 | int i; | 135 | grailbuf_clear(&impl->gbuf); |
| 144 | 136 | while (!evbuf_empty(&impl->evbuf)) { | |
| 145 | switch (frame->num_active) { | 137 | evbuf_get(&impl->evbuf, &ev); |
| 146 | case 1: | 138 | if (ge->event) |
| 147 | grail_mask_set(types, GRAIL_TYPE_DRAG1); | 139 | ge->event(ge, &ev); |
| 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 | } | 140 | } |
| 141 | } | ||
| 183 | 142 | ||
| 184 | for (i = 0; i < frame->num_active; i++) { | 143 | static void flush_gestures(struct grail *ge) |
| 185 | pos[i].x = gin_prop_x(ge->gin, frame->active[i]->x); | 144 | { |
| 186 | pos[i].y = gin_prop_y(ge->gin, frame->active[i]->y); | 145 | struct grail_impl *impl = ge->impl; |
| 146 | struct grail_event ev; | ||
| 147 | |||
| 148 | evbuf_clear(&impl->evbuf); | ||
| 149 | while (!grailbuf_empty(&impl->gbuf)) { | ||
| 150 | grailbuf_get(&impl->gbuf, &ev); | ||
| 151 | if (ge->gesture) | ||
| 152 | ge->gesture(ge, &ev); | ||
| 187 | } | 153 | } |
| 154 | } | ||
| 188 | 155 | ||
| 189 | return ge->get_clients(ge, &client, 1, pos, frame->num_active, | 156 | static int gesture_timeout(struct grail *ge, const struct utouch_frame *frame) |
| 190 | types, DIM_GRAIL_TYPE_BYTES); | 157 | { |
| 158 | struct gesture_inserter *gin = ge->gin; | ||
| 159 | |||
| 160 | return grail_mask_count(gin->used, sizeof(gin->used)) == 0; | ||
| 191 | } | 161 | } |
| 192 | 162 | ||
| 193 | static void report_frame(struct grail *ge, | 163 | static void report_frame(struct grail *ge, |
| @@ -195,85 +165,27 @@ static void report_frame(struct grail *ge, | |||
| 195 | const struct input_event *syn) | 165 | const struct input_event *syn) |
| 196 | { | 166 | { |
| 197 | struct grail_impl *impl = ge->impl; | 167 | struct grail_impl *impl = ge->impl; |
| 198 | struct gesture_recognizer *gru = ge->gru; | ||
| 199 | struct input_event iev; | ||
| 200 | struct grail_event gev; | 168 | struct grail_event gev; |
| 201 | 169 | ||
| 202 | ge->impl->frame = frame; | 170 | ge->impl->frame = frame; |
| 203 | 171 | ||
| 204 | /* Reset timer when number of touches changes. */ | 172 | if (frame->num_active && !frame->prev->num_active) { |
| 205 | if (frame->prev->revision != frame->revision && frame->num_active) { | 173 | impl->ongoing = 1; |
| 206 | gru->start_time = frame->time; | 174 | impl->gesture = 0; |
| 207 | } | 175 | } |
| 208 | 176 | ||
| 209 | /* Once touches have stabilized, check if there are any potential | 177 | if (!impl->ongoing) |
| 210 | * gestures registered for the number of touches. */ | 178 | return; |
| 211 | if (gru->state == RECOGNIZING && | ||
| 212 | frame->time > gru->start_time + stable_time && | ||
| 213 | check_potential_gestures(ge, frame) == 0) | ||
| 214 | gru->state = UNRECOGNIZED; | ||
| 215 | |||
| 216 | /* Process the frame for gestures unless we're sure there are none. */ | ||
| 217 | if (gru->state != UNRECOGNIZED) { | ||
| 218 | gin_frame_begin(ge, frame); | ||
| 219 | gru_recognize(ge, frame); | ||
| 220 | gin_frame_end(ge, frame); | ||
| 221 | } | ||
| 222 | 179 | ||
| 223 | if (gru->state == RECOGNIZING) { | 180 | gin_frame_begin(ge, frame); |
| 224 | /* If a gesture is recognized and either all touches lifted or | 181 | gru_recognize(ge, frame); |
| 225 | * we are within the recognition interval, set state to | 182 | gin_frame_end(ge, frame); |
| 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 | 183 | ||
| 240 | /* Now we have the state set, process events. */ | 184 | if (!grailbuf_empty(&impl->gbuf)) |
| 241 | switch (gru->state) { | 185 | impl->gesture = 1; |
| 242 | case RECOGNIZED: | 186 | |
| 243 | while (!grailbuf_empty(&impl->gbuf)) { | 187 | if (frame->num_active == 0 || gesture_timeout(ge, frame)) |
| 244 | grailbuf_get(&impl->gbuf, &gev); | 188 | impl->ongoing &= impl->gesture; |
| 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; | ||
| 276 | } | ||
| 277 | } | 189 | } |
| 278 | 190 | ||
| 279 | static void grail_pump_mtdev(struct grail *ge, const struct input_event *ev) | 191 | static void grail_pump_mtdev(struct grail *ge, const struct input_event *ev) |
| @@ -288,6 +200,13 @@ static void grail_pump_mtdev(struct grail *ge, const struct input_event *ev) | |||
| 288 | if (frame) | 200 | if (frame) |
| 289 | report_frame(ge, frame, ev); | 201 | report_frame(ge, frame, ev); |
| 290 | } | 202 | } |
| 203 | |||
| 204 | if (ev->type == EV_SYN) { | ||
| 205 | if (!impl->ongoing) | ||
| 206 | flush_events(ge); | ||
| 207 | if (impl->gesture) | ||
| 208 | flush_gestures(ge); | ||
| 209 | } | ||
| 291 | } | 210 | } |
| 292 | 211 | ||
| 293 | int grail_pull(struct grail *ge, int fd) | 212 | int grail_pull(struct grail *ge, int fd) |
