diff options
| -rw-r--r-- | src/grail-api.c | 154 | ||||
| -rw-r--r-- | src/grail-recognizer.h | 8 |
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. */ | ||
| 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 | |||
| 37 | void grail_filter_abs_events(struct grail *ge, int usage) | 42 | void 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. */ | ||
| 137 | static 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 | |||
| 130 | static void report_frame(struct grail *ge, | 193 | static 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 | ||
| 28 | enum recognition_state { | ||
| 29 | RECOGNIZING, | ||
| 30 | RECOGNIZED, | ||
| 31 | UNRECOGNIZED | ||
| 32 | }; | ||
| 33 | |||
| 28 | struct gesture_recognizer { | 34 | struct 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 | ||
| 39 | int gru_init(struct grail *ge); | 47 | int gru_init(struct grail *ge); |
