diff options
| -rw-r--r-- | src/gestures-drag.c | 14 | ||||
| -rw-r--r-- | src/gestures-pinch.c | 14 | ||||
| -rw-r--r-- | src/gestures-rotate.c | 14 | ||||
| -rw-r--r-- | src/grail-api.c | 173 | ||||
| -rw-r--r-- | src/grail-gestures.c | 10 | ||||
| -rw-r--r-- | src/grail-gestures.h | 2 | ||||
| -rw-r--r-- | src/grail-impl.h | 2 | ||||
| -rw-r--r-- | src/grail-recognizer.h | 8 |
8 files changed, 98 insertions, 139 deletions
diff --git a/src/gestures-drag.c b/src/gestures-drag.c index 05272da..9f2bcaf 100644 --- a/src/gestures-drag.c +++ b/src/gestures-drag.c | |||
| @@ -72,6 +72,13 @@ int gru_drag(struct grail *ge, | |||
| 72 | state->active = 0; | 72 | state->active = 0; |
| 73 | } | 73 | } |
| 74 | } | 74 | } |
| 75 | if ((move->timeout & fm_mask) == fm_mask) { | ||
| 76 | if (state->active) { | ||
| 77 | gin_gid_discard(ge, state->gid); | ||
| 78 | state->active = 0; | ||
| 79 | } | ||
| 80 | return 0; | ||
| 81 | } | ||
| 75 | if (!state->active) { | 82 | if (!state->active) { |
| 76 | int type = getype[move->ntouch]; | 83 | int type = getype[move->ntouch]; |
| 77 | if (type < 0) | 84 | if (type < 0) |
| @@ -102,6 +109,13 @@ int gru_windrag(struct grail *ge, | |||
| 102 | state->active = 0; | 109 | state->active = 0; |
| 103 | } | 110 | } |
| 104 | } | 111 | } |
| 112 | if ((move->timeout & fm_mask) == fm_mask) { | ||
| 113 | if (state->active) { | ||
| 114 | gin_gid_discard(ge, state->gid); | ||
| 115 | state->active = 0; | ||
| 116 | } | ||
| 117 | return 0; | ||
| 118 | } | ||
| 105 | if (!state->active) { | 119 | if (!state->active) { |
| 106 | if (move->ntouch == 4) { | 120 | if (move->ntouch == 4) { |
| 107 | state->gid = gin_gid_begin(ge, GRAIL_TYPE_MDRAG, | 121 | state->gid = gin_gid_begin(ge, GRAIL_TYPE_MDRAG, |
diff --git a/src/gestures-pinch.c b/src/gestures-pinch.c index fa8a626..e022e8d 100644 --- a/src/gestures-pinch.c +++ b/src/gestures-pinch.c | |||
| @@ -62,6 +62,13 @@ int gru_pinch(struct grail *ge, | |||
| 62 | } | 62 | } |
| 63 | return 0; | 63 | return 0; |
| 64 | } | 64 | } |
| 65 | if ((move->timeout & fm_mask) == fm_mask) { | ||
| 66 | if (state->active) { | ||
| 67 | gin_gid_discard(ge, state->gid); | ||
| 68 | state->active = 0; | ||
| 69 | } | ||
| 70 | return 0; | ||
| 71 | } | ||
| 65 | if (!(move->tickle & mask)) | 72 | if (!(move->tickle & mask)) |
| 66 | return 0; | 73 | return 0; |
| 67 | if (!state->active) { | 74 | if (!state->active) { |
| @@ -93,6 +100,13 @@ int gru_winpinch(struct grail *ge, | |||
| 93 | } | 100 | } |
| 94 | return 0; | 101 | return 0; |
| 95 | } | 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 | } | ||
| 96 | if (!(move->tickle & mask)) | 110 | if (!(move->tickle & mask)) |
| 97 | return 0; | 111 | return 0; |
| 98 | if (!state->active) { | 112 | if (!state->active) { |
diff --git a/src/gestures-rotate.c b/src/gestures-rotate.c index fde0db8..dd95c32 100644 --- a/src/gestures-rotate.c +++ b/src/gestures-rotate.c | |||
| @@ -61,6 +61,13 @@ int gru_rotate(struct grail *ge, | |||
| 61 | } | 61 | } |
| 62 | return 0; | 62 | return 0; |
| 63 | } | 63 | } |
| 64 | if ((move->timeout & fm_mask) == fm_mask) { | ||
| 65 | if (state->active) { | ||
| 66 | gin_gid_discard(ge, state->gid); | ||
| 67 | state->active = 0; | ||
| 68 | } | ||
| 69 | return 0; | ||
| 70 | } | ||
| 64 | if (!(move->tickle & mask)) | 71 | if (!(move->tickle & mask)) |
| 65 | return 0; | 72 | return 0; |
| 66 | if (!state->active) { | 73 | if (!state->active) { |
| @@ -92,6 +99,13 @@ int gru_winrotate(struct grail *ge, | |||
| 92 | } | 99 | } |
| 93 | return 0; | 100 | return 0; |
| 94 | } | 101 | } |
| 102 | if ((move->timeout & fm_mask) == fm_mask) { | ||
| 103 | if (state->active) { | ||
| 104 | gin_gid_discard(ge, state->gid); | ||
| 105 | state->active = 0; | ||
| 106 | } | ||
| 107 | return 0; | ||
| 108 | } | ||
| 95 | if (!(move->tickle & mask)) | 109 | if (!(move->tickle & mask)) |
| 96 | return 0; | 110 | return 0; |
| 97 | if (!state->active) { | 111 | if (!state->active) { |
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) |
diff --git a/src/grail-gestures.c b/src/grail-gestures.c index 035a199..efadde5 100644 --- a/src/grail-gestures.c +++ b/src/grail-gestures.c | |||
| @@ -111,6 +111,7 @@ static void move_reset(struct move_model *m, int i, float x, grail_time_t t) | |||
| 111 | fm->sample_ms = t; | 111 | fm->sample_ms = t; |
| 112 | m->tickle &= ~(1 << i); | 112 | m->tickle &= ~(1 << i); |
| 113 | m->active &= ~(1 << i); | 113 | m->active &= ~(1 << i); |
| 114 | m->timeout &= ~(1 << i); | ||
| 114 | } | 115 | } |
| 115 | 116 | ||
| 116 | static void move_update(struct move_model *m, int i, float x, grail_time_t t) | 117 | static void move_update(struct move_model *m, int i, float x, grail_time_t t) |
| @@ -132,11 +133,14 @@ static void move_update(struct move_model *m, int i, float x, grail_time_t t) | |||
| 132 | if (m->active & (1 << i)) | 133 | if (m->active & (1 << i)) |
| 133 | return; | 134 | return; |
| 134 | fm->action_delta = x - fm->original; | 135 | fm->action_delta = x - fm->original; |
| 135 | if (fabs(fm->action_delta) > fm->bar || | 136 | if (fabs(fm->action_delta) > fm->bar) { |
| 136 | t - fm->original_ms > fm->bar_ms) | ||
| 137 | m->active |= (1 << i); | 137 | m->active |= (1 << i); |
| 138 | else | 138 | } else if (t - fm->original_ms > fm->bar_ms) { |
| 139 | m->active |= (1 << i); | ||
| 140 | m->timeout |= (1 << i); | ||
| 141 | } else { | ||
| 139 | fm->action_delta = 0; | 142 | fm->action_delta = 0; |
| 143 | } | ||
| 140 | } | 144 | } |
| 141 | 145 | ||
| 142 | void gru_init_motion(struct grail *ge) | 146 | void gru_init_motion(struct grail *ge) |
diff --git a/src/grail-gestures.h b/src/grail-gestures.h index a6d51d5..c4c46c2 100644 --- a/src/grail-gestures.h +++ b/src/grail-gestures.h | |||
| @@ -54,7 +54,7 @@ struct filter_model { | |||
| 54 | 54 | ||
| 55 | struct move_model { | 55 | struct move_model { |
| 56 | struct filter_model fm[DIM_FM]; | 56 | struct filter_model fm[DIM_FM]; |
| 57 | int tickle, active; | 57 | int tickle, active, timeout; |
| 58 | int single, multi, ntouch; | 58 | int single, multi, ntouch; |
| 59 | grail_time_t time; | 59 | grail_time_t time; |
| 60 | }; | 60 | }; |
diff --git a/src/grail-impl.h b/src/grail-impl.h index 595f0fb..2c63b90 100644 --- a/src/grail-impl.h +++ b/src/grail-impl.h | |||
| @@ -42,6 +42,8 @@ struct grail_impl { | |||
| 42 | struct evbuf evbuf; | 42 | struct evbuf evbuf; |
| 43 | struct grailbuf gbuf; | 43 | struct grailbuf gbuf; |
| 44 | int filter_abs; | 44 | int filter_abs; |
| 45 | int ongoing; | ||
| 46 | int gesture; | ||
| 45 | }; | 47 | }; |
| 46 | 48 | ||
| 47 | #endif | 49 | #endif |
diff --git a/src/grail-recognizer.h b/src/grail-recognizer.h index b08ff34..56e5b8d 100644 --- a/src/grail-recognizer.h +++ b/src/grail-recognizer.h | |||
| @@ -25,12 +25,6 @@ | |||
| 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 | |||
| 34 | struct gesture_recognizer { | 28 | struct gesture_recognizer { |
| 35 | struct move_model move; | 29 | struct move_model move; |
| 36 | struct combo_model drag; | 30 | struct combo_model drag; |
| @@ -40,8 +34,6 @@ struct gesture_recognizer { | |||
| 40 | struct combo_model winpinch; | 34 | struct combo_model winpinch; |
| 41 | struct combo_model winrotate; | 35 | struct combo_model winrotate; |
| 42 | struct tapping_model tapping; | 36 | struct tapping_model tapping; |
| 43 | utouch_frame_time_t start_time; | ||
| 44 | enum recognition_state state; | ||
| 45 | }; | 37 | }; |
| 46 | 38 | ||
| 47 | int gru_init(struct grail *ge); | 39 | int gru_init(struct grail *ge); |
